Coverage Report

Created: 2025-11-06 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/card-flex.c
Line
Count
Source
1
/*
2
 * card-flex.c: Support for Schlumberger cards
3
 *
4
 * Copyright (C) 2001, 2002  Juha Yrjölä <juha.yrjola@iki.fi>
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#ifdef HAVE_CONFIG_H
22
#include "config.h"
23
#endif
24
25
#include <stdlib.h>
26
#include <string.h>
27
28
#include "internal.h"
29
#include "cardctl.h"
30
31
894
#define FLAG_KEYGEN   0x80000000
32
26
#define IS_CYBERFLEX(card)  (card->type == SC_CARD_TYPE_FLEX_CYBER)
33
34
static const struct sc_atr_table flex_atrs[] = {
35
  /* Cryptoflex */
36
  /* 8k win2000 */
37
  { "3b:95:15:40:20:68:01:02:00:00", NULL, "Cryptoflex 8K", SC_CARD_TYPE_FLEX_CRYPTO, 0, NULL },
38
  /* 8k */
39
  { "3B:95:15:40:FF:68:01:02:02:01", NULL, "Cryptoflex 8K", SC_CARD_TYPE_FLEX_CRYPTO, 0, NULL },
40
  /* 8k */
41
  { "3B:95:15:40:FF:68:01:02:02:04", NULL, "Cryptoflex 8K", SC_CARD_TYPE_FLEX_CRYPTO, 0, NULL },
42
  /* 8k */
43
  { "3B:85:40:20:68:01:01:05:01", NULL, "Cryptoflex 8K", SC_CARD_TYPE_FLEX_CRYPTO, 0, NULL },
44
  /* 16k */
45
  { "3B:95:94:40:FF:63:01:01:02:01", NULL, "Cryptoflex 16K", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
46
  /* "16K+SS1" alias Cryptoflex 16 card with Standard Softmask V1 */
47
  /* (taken from Cryptoflex Card Programmers Guide 4.5 Page xviii) */
48
  /* last two bytes can be ignored - version of the softmask */
49
  { "3B:95:15:40:FF:63:01:01:02:01", "FF:FF:FF:FF:FF:FF:FF:FF:00:00",
50
    "Cryptoflex 16K", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
51
  /* 32K v4 */
52
  /* "32K+SS1" alias Cryptoflex 32 card with Standard Softmask V1 */
53
  /* (taken from Cryptoflex Card Programmers Guide 4.5 Page xviii) */
54
  /* last two bytes can be ignored - version of the softmask */
55
  { "3B:95:18:40:FF:64:02:01:01:02","FF:FF:FF:FF:FF:FF:FF:FF:00:00",
56
    "Cryptoflex 32K v4", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
57
  /* "32K+e-gate" alias Cryptoflex e-gate 32K card */
58
  /* (taken from Cryptoflex Card Programmers Guide 4.5 Page xviii) */
59
  /* last two bytes can be ignored - version of the softmask */
60
  { "3B:95:18:40:FF:62:01:01:00:00", "FF:FF:FF:FF:FF:FF:FF:FF:00:00",
61
    "Cryptoflex e-gate 32K", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
62
  /* 32K e-gate */
63
  { "3B:95:18:40:FF:62:01:02:01:04", NULL, "Cryptoflex 32K e-gate", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
64
  /* 32K e-gate v4 */
65
  { "3B:95:18:40:FF:62:04:01:01:05", NULL, "Cryptoflex 32K e-gate v4", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
66
67
  /* new cryptoflex 32k card - atr looks very similar to old 8k card */
68
  { "3b:95:15:40:ff:68:01:02:45:47", NULL, "Cryptoflex 32K", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
69
70
  { "3B:E2:00:00:40:20:49:06", NULL, "Cryptoflex", SC_CARD_TYPE_FLEX_CRYPTO, 0, NULL },
71
  /* + full DES option */
72
  { "3B:E2:00:00:40:20:49:05", NULL, "Cryptoflex", SC_CARD_TYPE_FLEX_CRYPTO, 0, NULL },
73
  /* + Key Generation */
74
  { "3B:E2:00:00:40:20:49:07", NULL, "Cryptoflex", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
75
  /* + Key Generation */
76
  { "3B:85:40:20:68:01:01:03:05", NULL, "Cryptoflex", SC_CARD_TYPE_FLEX_CRYPTO, FLAG_KEYGEN, NULL },
77
78
  /* Multiflex */
79
  /* 3K */
80
  { "3B:02:14:50", NULL, "Multiflex 3K", SC_CARD_TYPE_FLEX_MULTI, 0, NULL },
81
  /* 4K */
82
  { "3B:19:14:55:90:01:02:01:00:05:04:B0", NULL, "Multiflex 4K", SC_CARD_TYPE_FLEX_MULTI, 0, NULL },
83
  /* 8K */
84
  { "3B:32:15:00:06:80", NULL, "Multiflex 8K", SC_CARD_TYPE_FLEX_MULTI, 0, NULL },
85
  /* 8K + full DES option */
86
  { "3B:32:15:00:06:95", NULL, "Multiflex 8K", SC_CARD_TYPE_FLEX_MULTI, 0, NULL },
87
  /* 8K */
88
  { "3B:19:14:59:01:01:0F:01:00:05:08:B0", NULL, "Multiflex 8K", SC_CARD_TYPE_FLEX_MULTI, 0, NULL },
89
  /* 8K */
90
  { "3B:19:14:55:90:01:01:01:00:05:08:B0", NULL, "Multiflex 8K", SC_CARD_TYPE_FLEX_MULTI, 0, NULL },
91
92
  /* Cyberflex Access */
93
  /* Crypto */
94
  { "3B:16:94:81:10:06:01:81:3F", NULL, "Cyberflex Access", SC_CARD_TYPE_FLEX_CYBER, 0, NULL },
95
  /* Aug. Crypto */
96
  { "3B:16:94:81:10:06:01:81:2F", NULL, "Cyberflex Access", SC_CARD_TYPE_FLEX_CYBER, 0, NULL },
97
  { NULL, NULL, NULL, 0, 0, NULL }
98
};
99
100
struct flex_private_data {
101
  int rsa_key_ref;
102
103
  /* Support card variations without having to
104
   * do the if (card->type ...) thing
105
   * all the time */
106
  u8  aak_key_ref;
107
};
108
109
2.08k
#define DRV_DATA(card)  ((struct flex_private_data *) (card)->drv_data)
110
111
static struct sc_card_operations cryptoflex_ops;
112
static struct sc_card_operations cyberflex_ops;
113
static struct sc_card_operations *iso_ops;
114
static struct sc_card_driver cryptoflex_drv = {
115
  "Schlumberger Multiflex/Cryptoflex",
116
  "flex",
117
  &cryptoflex_ops,
118
  NULL, 0, NULL
119
};
120
static struct sc_card_driver cyberflex_drv = {
121
  "Schlumberger Cyberflex",
122
  "cyberflex",
123
  &cyberflex_ops,
124
  NULL, 0, NULL
125
};
126
127
static int flex_finish(sc_card_t *card)
128
894
{
129
894
  free(card->drv_data);
130
894
  return 0;
131
894
}
132
133
static int cryptoflex_match_card(sc_card_t *card)
134
95.2k
{
135
95.2k
  int i;
136
137
95.2k
  i = _sc_match_atr(card, flex_atrs, NULL);
138
95.2k
  if (i < 0)
139
94.5k
    return 0;
140
652
  switch (flex_atrs[i].type) {
141
649
  case SC_CARD_TYPE_FLEX_CRYPTO:
142
652
  case SC_CARD_TYPE_FLEX_MULTI:
143
652
    card->name = flex_atrs[i].name;
144
652
    card->type = flex_atrs[i].type;
145
652
    card->flags = flex_atrs[i].flags;
146
652
    return 1;
147
652
  }
148
0
  return 0;
149
652
}
150
151
static int cyberflex_match_card(sc_card_t *card)
152
95.4k
{
153
95.4k
  int i;
154
155
95.4k
  i = _sc_match_atr(card, flex_atrs, NULL);
156
95.4k
  if (i < 0)
157
94.5k
    return 0;
158
894
  switch (flex_atrs[i].type) {
159
242
  case SC_CARD_TYPE_FLEX_CYBER:
160
242
    card->name = flex_atrs[i].name;
161
242
    card->type = flex_atrs[i].type;
162
242
    card->flags = flex_atrs[i].flags;
163
242
    return 1;
164
894
  }
165
652
  return 0;
166
894
}
167
168
static int flex_init(sc_card_t *card)
169
894
{
170
894
  struct flex_private_data *data;
171
172
894
  if (!(data = malloc(sizeof(*data))))
173
0
    return SC_ERROR_OUT_OF_MEMORY;
174
894
  card->drv_data = data;
175
176
894
  card->cla = 0xC0;
177
894
  data->aak_key_ref = 1;
178
179
  /* Override Cryptoflex defaults for specific card types */
180
894
  switch (card->type) {
181
242
  case SC_CARD_TYPE_FLEX_CYBER:
182
242
    card->cla = 0x00;
183
242
    data->aak_key_ref = 0;
184
242
    break;
185
894
  }
186
187
  /* FIXME: Card type detection */
188
894
  if (1) {
189
894
    unsigned long flags;
190
191
894
    flags = SC_ALGORITHM_RSA_RAW;
192
894
    flags |= SC_ALGORITHM_RSA_HASH_NONE;
193
894
    if (card->flags & FLAG_KEYGEN)
194
628
      flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
195
196
894
    _sc_card_add_rsa_alg(card, 512, flags, 0);
197
894
    _sc_card_add_rsa_alg(card, 768, flags, 0);
198
894
    _sc_card_add_rsa_alg(card, 1024, flags, 0);
199
894
    _sc_card_add_rsa_alg(card, 2048, flags, 0);
200
894
  }
201
202
  /* SCardTransmit failed: 8010002f
203
   * this can be solved with a small delay. */
204
894
  msleep(100);
205
206
  /* State that we have an RNG */
207
894
  card->caps |= SC_CARD_CAP_RNG;
208
209
894
  return 0;
210
894
}
211
212
static void
213
add_acl_entry(sc_card_t *card, sc_file_t *file, unsigned int op, u8 nibble)
214
2.07k
{
215
2.07k
  struct flex_private_data *prv = DRV_DATA(card);
216
217
2.07k
  switch (nibble) {
218
460
  case 0:
219
460
    sc_file_add_acl_entry(file, op, SC_AC_NONE, SC_AC_KEY_REF_NONE);
220
460
    break;
221
116
  case 1:
222
116
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
223
116
    break;
224
147
  case 2:
225
147
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
226
147
    break;
227
123
  case 3:
228
123
    sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
229
123
    break;
230
119
  case 4:
231
    /* Assume the key is the AAK */
232
119
    sc_file_add_acl_entry(file, op, SC_AC_AUT, prv->aak_key_ref);
233
119
    break;
234
132
  case 6:
235
132
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
236
132
    sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
237
132
    break;
238
196
  case 7:
239
196
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
240
196
    sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
241
196
    break;
242
97
  case 8:
243
97
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
244
    /* Assume the key is the AAK */
245
97
    sc_file_add_acl_entry(file, op, SC_AC_AUT, prv->aak_key_ref);
246
97
    break;
247
172
  case 9:
248
172
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
249
    /* Assume the key is the AAK */
250
172
    sc_file_add_acl_entry(file, op, SC_AC_AUT, prv->aak_key_ref);
251
172
    break;
252
232
  case 15:
253
232
    sc_file_add_acl_entry(file, op, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
254
232
    break;
255
278
  default:
256
278
    sc_file_add_acl_entry(file, op, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE);
257
278
    break;
258
2.07k
  }
259
2.07k
}
260
261
static int
262
cryptoflex_get_ac_keys(sc_card_t *card, sc_file_t *file)
263
408
{
264
408
  return 0;
265
408
}
266
267
static int
268
cryptoflex_process_file_attrs(sc_card_t *card, sc_file_t *file,
269
      const u8 *buf, size_t buflen)
270
540
{
271
540
  sc_context_t *ctx = card->ctx;
272
540
  const u8 *p = buf + 2;
273
540
  u8 b1, b2;
274
540
  int is_mf = 0;
275
276
540
  if (buflen < 14)
277
0
    return -1;
278
540
  b1 = *p++;
279
540
  b2 = *p++;
280
540
  file->size = (b1 << 8) + b2;
281
540
  b1 = *p++;
282
540
  b2 = *p++;
283
540
  file->id = (b1 << 8) + b2;
284
540
  if (file->id == 0x3F00)
285
55
    is_mf = 1;
286
540
  switch (*p) {
287
189
  case 0x01:
288
189
    file->type = SC_FILE_TYPE_WORKING_EF;
289
189
    file->ef_structure = SC_FILE_EF_TRANSPARENT;
290
189
    break;
291
105
  case 0x02:
292
105
    file->type = SC_FILE_TYPE_WORKING_EF;
293
105
    file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
294
105
    break;
295
45
  case 0x04:
296
45
    file->type = SC_FILE_TYPE_WORKING_EF;
297
45
    file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE;
298
45
    break;
299
40
  case 0x06:
300
40
    file->type = SC_FILE_TYPE_WORKING_EF;
301
40
    file->ef_structure = SC_FILE_EF_CYCLIC;
302
40
    break;
303
29
  case 0x38:
304
29
    file->type = SC_FILE_TYPE_DF;
305
29
    break;
306
132
  default:
307
132
    sc_log(ctx,  "invalid file type: 0x%02X\n", *p);
308
132
    return SC_ERROR_UNKNOWN_DATA_RECEIVED;
309
540
  }
310
408
  p += 2;
311
408
  if (file->type == SC_FILE_TYPE_DF) {
312
29
    add_acl_entry(card, file, SC_AC_OP_LIST_FILES, (u8)(p[0] >> 4));
313
29
    add_acl_entry(card, file, SC_AC_OP_DELETE, (u8)(p[1] >> 4));
314
29
    add_acl_entry(card, file, SC_AC_OP_CREATE, (u8)(p[1] & 0x0F));
315
379
  } else { /* EF */
316
379
    add_acl_entry(card, file, SC_AC_OP_READ, (u8)(p[0] >> 4));
317
379
    switch (file->ef_structure) {
318
189
    case SC_FILE_EF_TRANSPARENT:
319
189
      add_acl_entry(card, file, SC_AC_OP_UPDATE, (u8)(p[0] & 0x0F));
320
189
      break;
321
105
    case SC_FILE_EF_LINEAR_FIXED:
322
150
    case SC_FILE_EF_LINEAR_VARIABLE:
323
150
      add_acl_entry(card, file, SC_AC_OP_UPDATE, (u8)(p[0] & 0x0F));
324
150
      break;
325
40
    case SC_FILE_EF_CYCLIC:
326
40
      break;
327
379
    }
328
379
  }
329
408
  if (file->type != SC_FILE_TYPE_DF || is_mf) {
330
385
    add_acl_entry(card, file, SC_AC_OP_REHABILITATE, (u8)(p[2] >> 4));
331
385
    add_acl_entry(card, file, SC_AC_OP_INVALIDATE, (u8)(p[2] & 0x0F));
332
385
  }
333
408
  p += 3;
334
408
  if (*p)
335
316
    file->status = SC_FILE_STATUS_ACTIVATED;
336
92
  else
337
92
    file->status = SC_FILE_STATUS_INVALIDATED;
338
339
408
  return cryptoflex_get_ac_keys(card, file);
340
408
}
341
342
static int
343
cyberflex_process_file_attrs(sc_card_t *card, sc_file_t *file,
344
      const u8 *buf, size_t buflen)
345
168
{
346
168
  sc_context_t *ctx = card->ctx;
347
168
  const u8 *p = buf + 2;
348
168
  const u8 *pos;
349
168
  u8 b1, b2;
350
168
  int is_mf = 0;
351
352
168
  if (buflen < 14)
353
0
    return -1;
354
168
  b1 = *p++;
355
168
  b2 = *p++;
356
168
  file->size = (b1 << 8) + b2;
357
168
  b1 = *p++;
358
168
  b2 = *p++;
359
168
  file->id = (b1 << 8) + b2;
360
168
  switch (*p) {
361
13
  case 0x01:
362
13
    is_mf = 1;
363
13
    break;
364
106
  case 0x02:
365
106
    file->type = SC_FILE_TYPE_DF;
366
106
    break;
367
18
  case 0x04:
368
18
    file->type = SC_FILE_TYPE_WORKING_EF;
369
18
    break;
370
31
  default:
371
31
    sc_log(ctx,  "invalid file type: 0x%02X\n", *p);
372
31
    return SC_ERROR_UNKNOWN_DATA_RECEIVED;
373
168
  }
374
375
137
  if (is_mf) {
376
13
    sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES, SC_AC_AUT, 0);
377
13
    sc_file_add_acl_entry(file, SC_AC_OP_DELETE, SC_AC_AUT, 0);
378
13
    sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_AUT, 0);
379
124
  } else {
380
124
    p += 2;
381
124
    if (file->type == SC_FILE_TYPE_DF) {
382
106
      add_acl_entry(card, file, SC_AC_OP_LIST_FILES, (u8)(p[0] >> 4));
383
106
      add_acl_entry(card, file, SC_AC_OP_DELETE, (u8)(p[1] >> 4));
384
106
      add_acl_entry(card, file, SC_AC_OP_CREATE, (u8)(p[1] & 0x0F));
385
106
    } else { /* EF */
386
18
      add_acl_entry(card, file, SC_AC_OP_READ, (u8)(p[0] >> 4));
387
18
    }
388
124
  }
389
137
  if (file->type != SC_FILE_TYPE_DF) {
390
31
    add_acl_entry(card, file, SC_AC_OP_REHABILITATE, (u8)(p[2] >> 4));
391
31
    add_acl_entry(card, file, SC_AC_OP_INVALIDATE, (u8)(p[2] & 0x0F));
392
31
  }
393
137
  pos = p;
394
137
  p += 3;
395
137
  if (*p++)
396
87
    file->status = SC_FILE_STATUS_ACTIVATED;
397
50
  else
398
50
    file->status = SC_FILE_STATUS_INVALIDATED;
399
137
  p++;
400
137
  if (0 == is_mf) {
401
124
    p++;
402
124
    switch (*p) {
403
69
    case  0x00:
404
69
      file->ef_structure = SC_FILE_EF_TRANSPARENT;
405
69
      break;
406
14
    case  0x01:
407
14
      file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
408
14
      break;
409
16
    case  0x02:
410
16
      file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE;
411
16
      break;
412
6
    case  0x03:
413
6
      file->ef_structure = SC_FILE_EF_CYCLIC;
414
6
      break;
415
3
    case  0x04:
416
3
      break;
417
16
    default:
418
16
      sc_log(ctx,  "invalid file type: 0x%02X\n", *p);
419
16
      return SC_ERROR_UNKNOWN_DATA_RECEIVED;
420
124
    }
421
108
    switch (file->ef_structure) {
422
69
    case SC_FILE_EF_TRANSPARENT:
423
69
      add_acl_entry(card, file, SC_AC_OP_UPDATE, (u8)(pos[0] & 0x0F));
424
69
      break;
425
14
    case SC_FILE_EF_LINEAR_FIXED:
426
30
    case SC_FILE_EF_LINEAR_VARIABLE:
427
30
      add_acl_entry(card, file, SC_AC_OP_UPDATE, (u8)(pos[0] & 0x0F));
428
30
      break;
429
6
    case SC_FILE_EF_CYCLIC:
430
6
      break;
431
108
    }
432
108
  }
433
121
  return 0;
434
137
}
435
436
static int select_file_id(sc_card_t *card, const u8 *buf, size_t buflen,
437
        u8 p1, sc_file_t **file_out)
438
6.18k
{
439
6.18k
  int r;
440
6.18k
  sc_apdu_t apdu;
441
6.18k
        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
442
6.18k
        sc_file_t *file;
443
444
6.18k
  sc_log(card->ctx,  "called, p1=%u\n", p1);
445
6.18k
  sc_log_hex(card->ctx, "path", buf, buflen);
446
447
6.18k
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, p1, 0);
448
6.18k
  apdu.resp = rbuf;
449
6.18k
  apdu.resplen = sizeof(rbuf);
450
6.18k
  apdu.datalen = buflen;
451
6.18k
  apdu.data = buf;
452
6.18k
  apdu.lc = buflen;
453
6.18k
  apdu.le = 252;
454
455
  /* No need to get file information, if file is NULL. */
456
6.18k
  if (file_out == NULL) {
457
5.08k
    apdu.cse = SC_APDU_CASE_3_SHORT;
458
5.08k
    apdu.le = 0;
459
5.08k
  }
460
6.18k
  r = sc_transmit_apdu(card, &apdu);
461
6.18k
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
462
6.10k
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
463
6.10k
  LOG_TEST_RET(card->ctx, r, "Card returned error");
464
465
2.76k
  if (file_out == NULL)
466
1.87k
    return 0;
467
468
891
  if (apdu.resplen < 14)
469
146
    return SC_ERROR_UNKNOWN_DATA_RECEIVED;
470
745
  if (apdu.resp[0] == 0x6F) {
471
37
    sc_log(card->ctx,  "unsupported: card returned FCI\n");
472
37
    return SC_ERROR_UNKNOWN_DATA_RECEIVED; /* FIXME */
473
37
  }
474
708
  file = sc_file_new();
475
708
  if (file == NULL)
476
708
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
477
478
  /* We abuse process_fci here even though it's not the real FCI. */
479
708
  r = card->ops->process_fci(card, file, apdu.resp, apdu.resplen);
480
708
  if (r) {
481
179
    sc_file_free(file);
482
179
    return r;
483
179
  }
484
485
529
  *file_out = file;
486
529
  return 0;
487
708
}
488
489
static int flex_select_file(sc_card_t *card, const sc_path_t *path,
490
           sc_file_t **file_out)
491
4.76k
{
492
4.76k
  int r;
493
4.76k
  const u8 *pathptr = path->value;
494
4.76k
  size_t pathlen = path->len;
495
4.76k
  int locked = 0;
496
4.76k
  u8 p1 = 0;
497
498
4.76k
  switch (path->type) {
499
3.08k
  case SC_PATH_TYPE_PATH:
500
3.08k
    if ((pathlen & 1) != 0) /* not divisible by 2 */
501
0
      return SC_ERROR_INVALID_ARGUMENTS;
502
3.08k
    if (pathlen == 0)
503
7
      return 0;
504
3.07k
    if (pathlen != 2 || memcmp(pathptr, "\x3F\x00", 2) != 0) {
505
3.02k
      locked = 1;
506
3.02k
      r = sc_lock(card);
507
3.02k
      LOG_TEST_RET(card->ctx, r, "sc_lock() failed");
508
3.02k
      if (memcmp(pathptr, "\x3F\x00", 2) != 0) {
509
194
        r = select_file_id(card, (const u8 *) "\x3F\x00", 2, 0, NULL);
510
194
        if (r)
511
115
          sc_unlock(card);
512
194
        LOG_TEST_RET(card->ctx, r, "Unable to select Master File (MF)");
513
194
      }
514
4.28k
      while (pathlen > 2) {
515
3.10k
        r = select_file_id(card, pathptr, 2, 0, NULL);
516
3.10k
        if (r)
517
1.72k
          sc_unlock(card);
518
3.10k
        LOG_TEST_RET(card->ctx, r, "Unable to select DF");
519
1.37k
        pathptr += 2;
520
1.37k
        pathlen -= 2;
521
1.37k
      }
522
2.91k
    }
523
1.23k
    break;
524
1.63k
  case SC_PATH_TYPE_DF_NAME:
525
1.63k
    p1 = 0x04;
526
1.63k
    break;
527
40
  case SC_PATH_TYPE_FILE_ID:
528
40
    if (pathlen != 2)
529
24
      return SC_ERROR_INVALID_ARGUMENTS;
530
16
    break;
531
4.76k
  }
532
2.88k
  r = select_file_id(card, pathptr, pathlen, p1, file_out);
533
2.88k
  if (locked)
534
1.18k
    sc_unlock(card);
535
2.88k
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
536
2.88k
}
537
538
static int cryptoflex_list_files(sc_card_t *card, u8 *buf, size_t buflen)
539
41
{
540
41
  sc_apdu_t apdu;
541
41
  u8 rbuf[4];
542
41
  int r;
543
41
  size_t count = 0;
544
545
41
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA8, 0, 0);
546
41
  apdu.cla = 0xF0;
547
41
  apdu.le = 4;
548
41
  apdu.resplen = 4;
549
41
  apdu.resp = rbuf;
550
574
  while (buflen > 2) {
551
574
    r = sc_transmit_apdu(card, &apdu);
552
574
    if (r)
553
1
      return r;
554
573
    if (apdu.sw1 == 0x6A && apdu.sw2 == 0x82)
555
1
      break;
556
572
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
557
572
    if (r)
558
38
      return r;
559
534
    if (apdu.resplen != 4) {
560
1
      sc_log(card->ctx,
561
1
         "expected 4 bytes, got %"SC_FORMAT_LEN_SIZE_T"u.\n",
562
1
         apdu.resplen);
563
1
      return SC_ERROR_UNKNOWN_DATA_RECEIVED;
564
1
    }
565
533
    memcpy(buf, rbuf + 2, 2);
566
533
    buf += 2;
567
533
    count += 2;
568
533
    buflen -= 2;
569
533
  }
570
1
  return (int)count;
571
41
}
572
573
/*
574
 * The Cyberflex LIST FILES command is slightly different...
575
 */
576
static int cyberflex_list_files(sc_card_t *card, u8 *buf, size_t buflen)
577
0
{
578
0
  sc_apdu_t apdu;
579
0
  u8 rbuf[6];
580
0
  int r, p2 = 0;
581
0
  size_t count = 0;
582
583
0
  while (buflen > 2) {
584
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA8, 0, ++p2);
585
0
    apdu.le = 6;
586
0
    apdu.resplen = 6;
587
0
    apdu.resp = rbuf;
588
0
    r = sc_transmit_apdu(card, &apdu);
589
0
    if (r)
590
0
      return r;
591
0
    if (apdu.sw1 == 0x6A && apdu.sw2 == 0x83)
592
0
      break;
593
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
594
0
    if (r)
595
0
      return r;
596
0
    if (apdu.resplen != 6) {
597
0
      sc_log(card->ctx,
598
0
         "expected 6 bytes, got %"SC_FORMAT_LEN_SIZE_T"u.\n",
599
0
         apdu.resplen);
600
0
      return SC_ERROR_UNKNOWN_DATA_RECEIVED;
601
0
    }
602
0
    memcpy(buf, rbuf + 4, 2);
603
0
    buf += 2;
604
0
    count += 2;
605
0
    buflen -= 2;
606
0
  }
607
0
  return (int)count;
608
0
}
609
610
static int flex_delete_file(sc_card_t *card, const sc_path_t *path)
611
4
{
612
4
  sc_apdu_t apdu;
613
4
  int r;
614
615
4
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
616
4
  if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2) {
617
0
    sc_log(card->ctx,  "File type has to be SC_PATH_TYPE_FILE_ID\n");
618
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
619
0
  }
620
4
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
621
4
  if (!IS_CYBERFLEX(card))
622
2
    apdu.cla = 0xF0; /* Override CLA byte */
623
4
  apdu.data = path->value;
624
4
  apdu.lc = 2;
625
4
  apdu.datalen = 2;
626
627
4
  r = sc_transmit_apdu(card, &apdu);
628
4
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
629
3
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
630
4
}
631
632
static int acl_to_ac_nibble(const sc_acl_entry_t *e)
633
40
{
634
40
  if (e == NULL)
635
0
    return -1;
636
40
  if (e->next != NULL)  /* FIXME */
637
1
    return -1;
638
39
  switch (e->method) {
639
35
  case SC_AC_NONE:
640
35
    return 0x00;
641
4
  case SC_AC_CHV:
642
4
    switch (e->key_ref) {
643
3
    case 1:
644
3
      return 0x01;
645
0
      break;
646
0
    case 2:
647
0
      return 0x02;
648
0
      break;
649
4
    }
650
1
    return -1;
651
0
  case SC_AC_PRO:
652
0
    return 0x03;
653
0
  case SC_AC_AUT:
654
0
    return 0x04;
655
0
  case SC_AC_NEVER:
656
0
    return 0x0f;
657
39
  }
658
0
  return -1;
659
39
}
660
661
static int acl_to_keynum_nibble(const sc_acl_entry_t *e)
662
38
{
663
76
  while (e != NULL && e->method != SC_AC_AUT)
664
38
    e = e->next;
665
38
  if (e == NULL || e->key_ref == SC_AC_KEY_REF_NONE)
666
38
    return 0;
667
668
0
  return e->key_ref & 0x0F;
669
38
}
670
671
static int
672
cryptoflex_construct_file_attrs(sc_card_t *card, const sc_file_t *file,
673
         u8 *buf, size_t *buflen)
674
15
{
675
15
  u8 *p = buf;
676
15
  int r, i;
677
15
  int ops[6];
678
679
15
  p[0] = 0xFF;
680
15
  p[1] = 0xFF;
681
15
  p[2] = file->size >> 8;
682
15
  p[3] = file->size & 0xFF;
683
15
  p[4] = file->id >> 8;
684
15
  p[5] = file->id & 0xFF;
685
15
  if (file->type == SC_FILE_TYPE_DF)
686
14
    p[6] = 0x38;
687
1
  else
688
1
    switch (file->ef_structure) {
689
0
    case SC_FILE_EF_TRANSPARENT:
690
0
      p[6] = 0x01;
691
0
      break;
692
0
    case SC_FILE_EF_LINEAR_FIXED:
693
0
      p[6] = 0x02;
694
0
      break;
695
0
    case SC_FILE_EF_LINEAR_VARIABLE:
696
0
      p[6] = 0x04;
697
0
      break;
698
0
    case SC_FILE_EF_CYCLIC:
699
0
      p[6] = 0x06;
700
0
      break;
701
1
    default:
702
1
      sc_log(card->ctx,  "Invalid EF structure\n");
703
1
      return -1;
704
1
    }
705
14
  p[7] = 0xFF;  /* allow Decrease and Increase */
706
98
  for (i = 0; i < 6; i++)
707
84
    ops[i] = -1;
708
14
  if (file->type == SC_FILE_TYPE_DF) {
709
14
    ops[0] = SC_AC_OP_LIST_FILES;
710
14
    ops[2] = SC_AC_OP_DELETE;
711
14
    ops[3] = SC_AC_OP_CREATE;
712
14
  } else {
713
0
    ops[0] = SC_AC_OP_READ;
714
0
    ops[1] = SC_AC_OP_UPDATE;
715
0
    ops[2] = SC_AC_OP_READ;
716
0
    ops[3] = SC_AC_OP_UPDATE;
717
0
    ops[4] = SC_AC_OP_REHABILITATE;
718
0
    ops[5] = SC_AC_OP_INVALIDATE;
719
0
  }
720
14
  p[8] = p[9] = p[10] = 0;
721
14
  p[13] = p[14] = p[15] = 0; /* Key numbers */
722
90
  for (i = 0; i < 6; i++) {
723
78
    const sc_acl_entry_t *entry;
724
78
    if (ops[i] == -1)
725
38
      continue;
726
40
    entry = sc_file_get_acl_entry(file, ops[i]);
727
40
    r = acl_to_ac_nibble(entry);
728
40
    LOG_TEST_RET(card->ctx, r, "Invalid ACL value");
729
    /* Do some magic to get the nibbles right */
730
38
    p[8 + i/2] |= (r & 0x0F) << (((i+1) % 2) * 4);
731
38
    r = acl_to_keynum_nibble(entry);
732
38
    p[13 + i/2] |= (r & 0x0F) << (((i+1) % 2) * 4);
733
38
  }
734
12
  p[11] = (file->status == SC_FILE_STATUS_INVALIDATED) ? 0x00 : 0x01;
735
12
  if (file->type != SC_FILE_TYPE_DF &&
736
0
      (file->ef_structure == SC_FILE_EF_LINEAR_FIXED ||
737
0
      file->ef_structure == SC_FILE_EF_CYCLIC))
738
0
    p[12] = 0x04;
739
12
  else
740
12
    p[12] = 0x03;
741
12
  if (p[12] == 0x04) {
742
0
    p[16] = file->record_length;
743
0
    *buflen = 17;
744
0
  } else
745
12
    *buflen = 16;
746
747
12
  return 0;
748
14
}
749
750
static int
751
cyberflex_construct_file_attrs(sc_card_t *card, const sc_file_t *file,
752
         u8 *buf, size_t *buflen)
753
7
{
754
7
  u8 *p = buf;
755
7
  size_t size = file->size;
756
757
  /* cyberflex wants input parameters length added */
758
7
  switch (file->type) {
759
7
  case SC_FILE_TYPE_DF:
760
7
    size += 24;
761
7
    break;
762
0
  case SC_FILE_TYPE_WORKING_EF:
763
0
  default:
764
0
    size += 16;
765
0
    break;
766
7
  }
767
768
7
  sc_log(card->ctx,
769
7
     "Creating %02x:%02x, size %"SC_FORMAT_LEN_SIZE_T"u %02"SC_FORMAT_LEN_SIZE_T"x:%02"SC_FORMAT_LEN_SIZE_T"x\n",
770
7
     file->id >> 8,
771
7
     file->id & 0xFF,
772
7
     size,
773
7
     size >> 8,
774
7
     size & 0xFF);
775
776
7
  p[0] = size >> 8;
777
7
  p[1] = size & 0xFF;
778
7
  p[2] = file->id >> 8;
779
7
  p[3] = file->id & 0xFF;
780
7
  if (file->type == SC_FILE_TYPE_DF)
781
7
    p[4] = 0x20;
782
0
  else
783
0
    switch (file->ef_structure) {
784
0
    case SC_FILE_EF_TRANSPARENT:
785
0
      p[4] = 0x02;
786
0
      break;
787
0
    case SC_FILE_EF_LINEAR_FIXED:
788
0
      p[4] = 0x0C;
789
0
      break;
790
0
    case SC_FILE_EF_LINEAR_VARIABLE:
791
0
      p[4] = 0x19;
792
0
      break;
793
0
    case SC_FILE_EF_CYCLIC:
794
0
      p[4] = 0x1D;
795
0
      break;
796
0
    default:
797
0
      sc_log(card->ctx,  "Invalid EF structure\n");
798
0
      return -1;
799
0
    }
800
7
  p[5] = 0x01;  /* status?? */
801
7
  p[6] = p[7] = 0;
802
803
7
  *buflen = 16;
804
805
7
  p[8] = p[9] = p[11] = 0xFF;
806
7
  p[10] = p[12] = p[13] = p[14] = p[15] = 0x00;
807
7
  return 0;
808
7
}
809
810
static int flex_create_file(sc_card_t *card, sc_file_t *file)
811
22
{
812
22
  u8 sbuf[18];
813
22
  size_t sendlen;
814
22
  int r, rec_nr;
815
22
  sc_apdu_t apdu;
816
817
  /* Build the file attrs. These are not the real FCI bytes
818
   * in the standard sense, but its a convenient way of
819
   * abstracting the Cryptoflex/Cyberflex differences */
820
22
  r = card->ops->construct_fci(card, file, sbuf, &sendlen);
821
22
  if (r) {
822
3
    sc_log(card->ctx,  "File structure encoding failed.\n");
823
3
    return SC_ERROR_INVALID_ARGUMENTS;
824
3
  }
825
19
  if (file->type != SC_FILE_TYPE_DF && file->ef_structure != SC_FILE_EF_TRANSPARENT)
826
0
    rec_nr = (int)file->record_count;
827
19
  else
828
19
    rec_nr = 0;
829
19
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, rec_nr);
830
19
  if (!IS_CYBERFLEX(card))
831
12
    apdu.cla = 0xF0;
832
19
  apdu.data = sbuf;
833
19
  apdu.datalen = sendlen;
834
19
  apdu.lc = sendlen;
835
836
19
  r = sc_transmit_apdu(card, &apdu);
837
19
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
838
18
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
839
18
  LOG_TEST_RET(card->ctx, r, "Card returned error");
840
8
  return SC_SUCCESS;
841
18
}
842
843
static int flex_set_security_env(sc_card_t *card,
844
         const sc_security_env_t *env,
845
         int se_num)
846
0
{
847
0
  struct flex_private_data *prv = (struct flex_private_data *) card->drv_data;
848
849
0
  if (env->operation != SC_SEC_OPERATION_SIGN &&
850
0
      env->operation != SC_SEC_OPERATION_DECIPHER) {
851
0
    sc_log(card->ctx,  "Invalid crypto operation supplied.\n");
852
0
    return SC_ERROR_NOT_SUPPORTED;
853
0
  }
854
0
  if (env->algorithm != SC_ALGORITHM_RSA) {
855
0
    sc_log(card->ctx,  "Invalid crypto algorithm supplied.\n");
856
0
    return SC_ERROR_NOT_SUPPORTED;
857
0
  }
858
0
  if ((env->algorithm_flags & SC_ALGORITHM_RSA_PADS) ||
859
0
      (env->algorithm_flags & SC_ALGORITHM_RSA_HASHES)) {
860
0
        sc_log(card->ctx,  "Card supports only raw RSA.\n");
861
0
    return SC_ERROR_NOT_SUPPORTED;
862
0
  }
863
0
  if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
864
0
    if (env->key_ref_len != 1 ||
865
0
        (env->key_ref[0] != 0 && env->key_ref[0] != 1)) {
866
0
      sc_log(card->ctx,  "Invalid key reference supplied.\n");
867
0
      return SC_ERROR_NOT_SUPPORTED;
868
0
    }
869
0
    prv->rsa_key_ref = env->key_ref[0];
870
0
  }
871
0
  if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
872
0
    sc_log(card->ctx,  "Algorithm reference not supported.\n");
873
0
    return SC_ERROR_NOT_SUPPORTED;
874
0
  }
875
0
  if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT)
876
0
    if (memcmp(env->file_ref.value, "\x00\x12", 2) != 0) {
877
0
      sc_log(card->ctx,  "File reference is not 0012.\n");
878
0
      return SC_ERROR_NOT_SUPPORTED;
879
0
    }
880
0
  return 0;
881
0
}
882
883
static int flex_restore_security_env(sc_card_t *card, int se_num)
884
0
{
885
0
  return 0;
886
0
}
887
888
static int
889
cryptoflex_compute_signature(sc_card_t *card, const u8 *data,
890
        size_t data_len, u8 * out, size_t outlen)
891
0
{
892
0
  struct flex_private_data *prv = (struct flex_private_data *) card->drv_data;
893
0
  sc_apdu_t apdu;
894
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
895
0
  int r;
896
0
  size_t i, i2;
897
898
0
  if (data_len != 64 && data_len != 96 && data_len != 128  && data_len != 256) {
899
0
    sc_log(card->ctx,
900
0
       "Illegal input length: %"SC_FORMAT_LEN_SIZE_T"u\n",
901
0
       data_len);
902
0
    return SC_ERROR_INVALID_ARGUMENTS;
903
0
  }
904
0
  if (outlen < data_len) {
905
0
    sc_log(card->ctx,  "Output buffer too small.\n");
906
0
    return SC_ERROR_BUFFER_TOO_SMALL;
907
0
  }
908
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x00, prv->rsa_key_ref);
909
910
  /* This works around a problem with some PC/SC IFD drivers that don't grok
911
   * lc=00 (Chaskiel M Grundman <cg2v@andrew.cmu.edu>) */
912
0
  if (data_len == 256) {
913
0
    apdu.cla=0x10;
914
0
    apdu.cse= SC_APDU_CASE_3_SHORT;
915
0
    apdu.lc=10;
916
0
    apdu.datalen=10;
917
0
    apdu.data = sbuf;
918
0
    for (i2 = 0; i2 < 10; i2++)
919
0
      sbuf[i2]=data[data_len-1-i2];
920
0
    r = sc_transmit_apdu(card, &apdu);
921
0
    LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
922
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
923
0
    LOG_TEST_RET(card->ctx, r, "Card returned error");
924
0
    data_len -= 10;
925
0
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x00, prv->rsa_key_ref);
926
0
    apdu.cla=0x0;
927
0
  }
928
929
0
  apdu.lc = data_len;
930
0
  apdu.datalen = data_len;
931
0
  for (i = 0; i < data_len; i++)
932
0
    sbuf[i] = data[data_len-1-i];
933
0
  apdu.data = sbuf;
934
0
  apdu.resplen = outlen > sizeof(sbuf) ? sizeof(sbuf) : outlen;
935
0
  apdu.le      = apdu.resplen > 256 ? 256 : apdu.resplen;
936
0
  apdu.resp    = sbuf;
937
0
  r = sc_transmit_apdu(card, &apdu);
938
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
939
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
940
0
  LOG_TEST_RET(card->ctx, r, "Card returned error");
941
0
  for (i = 0; i < apdu.resplen; i++)
942
0
    out[i] = sbuf[apdu.resplen-1-i];
943
0
  return (int)apdu.resplen;
944
0
}
945
946
static int
947
cyberflex_compute_signature(sc_card_t *card, const u8 *data,
948
    size_t data_len, u8 * out, size_t outlen)
949
0
{
950
0
  struct flex_private_data *prv = DRV_DATA(card);
951
0
  sc_apdu_t apdu;
952
0
  u8 alg_id, key_id;
953
0
  int r;
954
955
0
  switch (data_len) {
956
0
  case 64:  alg_id = 0xC4; break;
957
0
  case 96:  alg_id = 0xC6; break;
958
0
  case 128: alg_id = 0xC8; break;
959
0
  default:
960
0
    sc_log(card->ctx,
961
0
       "Illegal input length: %"SC_FORMAT_LEN_SIZE_T"u\n",
962
0
       data_len);
963
0
    return SC_ERROR_INVALID_ARGUMENTS;
964
0
  }
965
0
  key_id = prv->rsa_key_ref + 1; /* Why? */
966
967
0
  if (outlen < data_len) {
968
0
    sc_log(card->ctx,  "Output buffer too small.\n");
969
0
    return SC_ERROR_BUFFER_TOO_SMALL;
970
0
  }
971
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x88, alg_id, key_id);
972
973
0
  apdu.lc = data_len;
974
0
  apdu.datalen = data_len;
975
0
  apdu.data = data;
976
0
  apdu.resplen = outlen;
977
0
  apdu.resp = out;
978
0
  r = sc_transmit_apdu(card, &apdu);
979
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
980
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
981
0
  LOG_TEST_RET(card->ctx, r, "Card returned error");
982
0
  return (int)apdu.resplen;
983
0
}
984
985
static int flex_decipher(sc_card_t *card,
986
          const u8 * crgram, size_t crgram_len,
987
          u8 * out, size_t outlen)
988
0
{
989
  /* There seems to be no Decipher command, but an RSA signature
990
   * is the same operation as an RSA decryption.
991
   * Of course, the (PKCS#1) padding is different, but at least
992
   * a Cryptoflex 32K e-gate doesn't seem to check this. */
993
0
  return card->ops->compute_signature(card, crgram, crgram_len, out, outlen);
994
0
}
995
996
/* Return the default AAK for this type of card */
997
static int flex_get_default_key(sc_card_t *card,
998
        struct sc_cardctl_default_key *data)
999
8
{
1000
8
  struct flex_private_data *prv = DRV_DATA(card);
1001
8
  const char *key;
1002
1003
8
  if (data->method != SC_AC_AUT || data->key_ref != prv->aak_key_ref)
1004
0
    return SC_ERROR_NO_DEFAULT_KEY;
1005
1006
  /* These seem to be the default AAKs used by Schlumberger */
1007
8
  switch (card->type) {
1008
1
  case SC_CARD_TYPE_FLEX_CRYPTO:
1009
1
    key = "2c:15:e5:26:e9:3e:8a:19";
1010
1
    break;
1011
7
  case SC_CARD_TYPE_FLEX_CYBER:
1012
7
    key = "ad:9f:61:fe:fa:20:ce:63";
1013
7
    break;
1014
0
  default:
1015
0
    return SC_ERROR_NO_DEFAULT_KEY;
1016
8
  }
1017
1018
8
  return sc_hex_to_bin(key, data->key_data, &data->len);
1019
8
}
1020
1021
/* Generate key on-card */
1022
static int flex_generate_key(sc_card_t *card, struct sc_cardctl_cryptoflex_genkey_info *data)
1023
0
{
1024
0
  sc_apdu_t apdu;
1025
0
  u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
1026
0
  int r, p1, p2;
1027
1028
0
  switch (data->key_bits) {
1029
0
  case  512:  p2 = 0x40; break;
1030
0
  case  768:  p2 = 0x60; break;
1031
0
  case 1024:  p2 = 0x80; break;
1032
0
  case 2048:  p2 = 0x00; break;
1033
0
  default:
1034
0
    sc_log(card->ctx,  "Illegal key length: %zu\n", data->key_bits);
1035
0
    return SC_ERROR_INVALID_ARGUMENTS;
1036
0
  }
1037
1038
0
  p1 = data->key_num;
1039
1040
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, p1, p2);
1041
0
  if (!IS_CYBERFLEX(card))
1042
0
    apdu.cla = 0xF0;
1043
0
  apdu.data = sbuf;
1044
0
  apdu.datalen = 4;
1045
0
  apdu.lc = 4;
1046
1047
  /* Little endian representation of exponent */
1048
0
  sbuf[0] = data->exponent & 0xFF;
1049
0
  sbuf[1] = (data->exponent >> 8) & 0xFF;
1050
0
  sbuf[2] = (data->exponent >> 16) & 0xFF;
1051
0
  sbuf[3] = (data->exponent >> 24) & 0xFF;
1052
1053
0
  r = sc_transmit_apdu(card, &apdu);
1054
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1055
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1056
0
  LOG_TEST_RET(card->ctx, r, "Card returned error");
1057
1058
0
  data->pubkey_len = (unsigned)apdu.resplen;
1059
0
  return 0;
1060
0
}
1061
1062
/* read the card serial number from the EF_gdo system file */
1063
static int flex_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
1064
104
{
1065
104
  int       r;
1066
104
  u8        buf[16];
1067
104
  size_t    len;
1068
104
  sc_path_t tpath;
1069
104
  sc_file_t *tfile = NULL;
1070
1071
104
  if (!serial)
1072
0
    return SC_ERROR_INVALID_ARGUMENTS;
1073
  /* see if we have cached serial number */
1074
104
  if (card->serialnr.len) {
1075
0
    memcpy(serial, &card->serialnr, sizeof(*serial));
1076
0
    return SC_SUCCESS;
1077
0
  }
1078
  /* read EF_ICCSN */
1079
104
  sc_format_path("3F000002", &tpath);
1080
104
  r = sc_select_file(card, &tpath, &tfile);
1081
104
  if (r < 0)
1082
69
    return r;
1083
35
  len = tfile->size;
1084
35
  sc_file_free(tfile);
1085
35
  if (len != 8) {
1086
31
    sc_log(card->ctx,  "unexpected file length of EF_ICCSN (%lu)\n",
1087
31
      (unsigned long) len);
1088
31
    return SC_ERROR_INTERNAL;
1089
31
  }
1090
4
  r = sc_read_binary(card, 0, buf, len, 0);
1091
4
  if (r < 0)
1092
2
    return r;
1093
2
  card->serialnr.len = len;
1094
2
  memcpy(card->serialnr.value, buf, len);
1095
1096
2
  memcpy(serial, &card->serialnr, sizeof(*serial));
1097
1098
2
  return SC_SUCCESS;
1099
4
}
1100
1101
static int flex_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
1102
429
{
1103
429
  switch (cmd) {
1104
8
  case SC_CARDCTL_GET_DEFAULT_KEY:
1105
8
    return flex_get_default_key(card,
1106
8
        (struct sc_cardctl_default_key *) ptr);
1107
0
  case SC_CARDCTL_CRYPTOFLEX_GENERATE_KEY:
1108
0
    return flex_generate_key(card,
1109
0
        (struct sc_cardctl_cryptoflex_genkey_info *) ptr);
1110
104
  case SC_CARDCTL_GET_SERIALNR:
1111
104
    return flex_get_serialnr(card, (sc_serial_number_t *) ptr);
1112
429
  }
1113
1114
317
  return SC_ERROR_NOT_SUPPORTED;
1115
429
}
1116
1117
static int flex_build_verify_apdu(sc_card_t *card, sc_apdu_t *apdu,
1118
          struct sc_pin_cmd_data *data)
1119
21
{
1120
21
  static u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
1121
21
  int r, len;
1122
21
  int cla = card->cla, ins;
1123
1124
21
  switch (data->pin_type) {
1125
18
  case SC_AC_CHV:
1126
18
    ins = 0x20;
1127
18
    break;
1128
3
  case SC_AC_AUT:
1129
    /* AUT keys cannot be entered through terminal */
1130
3
    if (data->flags & SC_PIN_CMD_USE_PINPAD)
1131
0
      return SC_ERROR_INVALID_ARGUMENTS;
1132
    /* Override CLA byte */
1133
3
    if (!IS_CYBERFLEX(card))
1134
0
      cla = 0xF0;
1135
3
    ins = 0x2A;
1136
3
    break;
1137
0
  default:
1138
0
    return SC_ERROR_INVALID_ARGUMENTS;
1139
21
  }
1140
  /* Copy the PIN, with padding */
1141
21
  if ((r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, 1)) < 0)
1142
0
    return r;
1143
21
  len = r;
1144
1145
21
  sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, ins, 0, data->pin_reference);
1146
21
  apdu->cla = cla;
1147
21
  apdu->data = sbuf;
1148
21
  apdu->datalen = len;
1149
21
  apdu->lc = len;
1150
1151
21
  return 0;
1152
21
}
1153
1154
static void flex_init_pin_info(struct sc_pin_cmd_pin *pin, unsigned int num)
1155
250
{
1156
250
  pin->encoding   = SC_PIN_ENCODING_ASCII;
1157
250
  pin->min_length = 4;
1158
250
  pin->max_length = 8;
1159
250
  pin->pad_length = 8;
1160
250
  pin->offset     = 5 + num * 8;
1161
250
}
1162
1163
static int flex_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
1164
      int *tries_left)
1165
125
{
1166
125
  sc_apdu_t apdu;
1167
125
  int r;
1168
125
  int old_cla = -1;
1169
1170
  /* Fix pin data */
1171
125
  data->flags |= SC_PIN_CMD_NEED_PADDING;
1172
125
  flex_init_pin_info(&data->pin1, 0);
1173
125
  flex_init_pin_info(&data->pin2, 1);
1174
1175
125
  if (data->cmd == SC_PIN_CMD_VERIFY) {
1176
21
    r = flex_build_verify_apdu(card, &apdu, data);
1177
21
    if (r < 0)
1178
0
      return r;
1179
21
    data->apdu = &apdu;
1180
104
  } else if (data->cmd == SC_PIN_CMD_CHANGE || data->cmd == SC_PIN_CMD_UNBLOCK) {
1181
0
    if (data->pin_type != SC_AC_CHV)
1182
0
      return SC_ERROR_INVALID_ARGUMENTS;
1183
0
    old_cla = card->cla;
1184
0
    if (!IS_CYBERFLEX(card))
1185
0
      card->cla = 0xF0;
1186
0
  }
1187
1188
  /* According to the Cryptoflex documentation, the card
1189
   * does not return the number of attempts left using
1190
   * the 63C0xx convention, hence we don't pass the
1191
   * tries_left pointer. */
1192
125
  r = iso_ops->pin_cmd(card, data, NULL);
1193
125
  if (old_cla != -1)
1194
0
    card->cla = old_cla;
1195
125
  data->apdu = NULL;
1196
125
  return r;
1197
125
}
1198
1199
static int flex_logout(sc_card_t *card)
1200
0
{
1201
0
  sc_apdu_t apdu;
1202
0
  int r;
1203
1204
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x22, 0x07, 0x00);
1205
0
  apdu.cla = 0xF0;
1206
1207
0
  r = sc_transmit_apdu(card, &apdu);
1208
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
1209
1210
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
1211
0
  LOG_TEST_RET(card->ctx, r, "Card returned error");
1212
1213
0
  LOG_FUNC_RETURN(card->ctx, r);
1214
0
}
1215
1216
1217
struct sc_card_driver * sc_get_cryptoflex_driver(void)
1218
100k
{
1219
100k
  if (iso_ops == NULL)
1220
0
    iso_ops = sc_get_iso7816_driver()->ops;
1221
1222
100k
  cryptoflex_ops = *iso_ops;
1223
100k
  cryptoflex_ops.match_card = cryptoflex_match_card;
1224
100k
  cryptoflex_ops.init = flex_init;
1225
100k
  cryptoflex_ops.finish = flex_finish;
1226
100k
  cryptoflex_ops.process_fci = cryptoflex_process_file_attrs;
1227
100k
  cryptoflex_ops.construct_fci = cryptoflex_construct_file_attrs;
1228
100k
  cryptoflex_ops.select_file = flex_select_file;
1229
100k
  cryptoflex_ops.list_files = cryptoflex_list_files;
1230
100k
  cryptoflex_ops.delete_file = flex_delete_file;
1231
100k
  cryptoflex_ops.create_file = flex_create_file;
1232
100k
  cryptoflex_ops.card_ctl = flex_card_ctl;
1233
100k
  cryptoflex_ops.set_security_env = flex_set_security_env;
1234
100k
  cryptoflex_ops.restore_security_env = flex_restore_security_env;
1235
100k
  cryptoflex_ops.compute_signature = cryptoflex_compute_signature;
1236
100k
  cryptoflex_ops.decipher = flex_decipher;
1237
100k
  cryptoflex_ops.pin_cmd = flex_pin_cmd;
1238
100k
  cryptoflex_ops.logout = flex_logout;
1239
100k
  return &cryptoflex_drv;
1240
100k
}
1241
1242
struct sc_card_driver * sc_get_cyberflex_driver(void)
1243
100k
{
1244
100k
  if (iso_ops == NULL)
1245
10
    iso_ops = sc_get_iso7816_driver()->ops;
1246
1247
100k
  cyberflex_ops = *iso_ops;
1248
100k
  cyberflex_ops.match_card = cyberflex_match_card;
1249
100k
  cyberflex_ops.init = flex_init;
1250
100k
  cyberflex_ops.finish = flex_finish;
1251
100k
  cyberflex_ops.process_fci = cyberflex_process_file_attrs;
1252
100k
  cyberflex_ops.construct_fci = cyberflex_construct_file_attrs;
1253
100k
  cyberflex_ops.select_file = flex_select_file;
1254
100k
  cyberflex_ops.list_files = cyberflex_list_files;
1255
100k
  cyberflex_ops.delete_file = flex_delete_file;
1256
100k
  cyberflex_ops.create_file = flex_create_file;
1257
100k
  cyberflex_ops.card_ctl = flex_card_ctl;
1258
100k
  cyberflex_ops.set_security_env = flex_set_security_env;
1259
100k
  cyberflex_ops.restore_security_env = flex_restore_security_env;
1260
100k
  cyberflex_ops.compute_signature = cyberflex_compute_signature;
1261
100k
  cyberflex_ops.decipher = flex_decipher;
1262
100k
  cyberflex_ops.pin_cmd = flex_pin_cmd;
1263
100k
  cyberflex_ops.logout = flex_logout;
1264
100k
  return &cyberflex_drv;
1265
100k
}