Coverage Report

Created: 2026-01-17 06:13

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
373
#define FLAG_KEYGEN   0x80000000
32
50
#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
1.43k
#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
373
{
129
373
  free(card->drv_data);
130
373
  return 0;
131
373
}
132
133
static int cryptoflex_match_card(sc_card_t *card)
134
19.7k
{
135
19.7k
  int i;
136
137
19.7k
  i = _sc_match_atr(card, flex_atrs, NULL);
138
19.7k
  if (i < 0)
139
19.5k
    return 0;
140
173
  switch (flex_atrs[i].type) {
141
172
  case SC_CARD_TYPE_FLEX_CRYPTO:
142
173
  case SC_CARD_TYPE_FLEX_MULTI:
143
173
    card->name = flex_atrs[i].name;
144
173
    card->type = flex_atrs[i].type;
145
173
    card->flags = flex_atrs[i].flags;
146
173
    return 1;
147
173
  }
148
0
  return 0;
149
173
}
150
151
static int cyberflex_match_card(sc_card_t *card)
152
19.9k
{
153
19.9k
  int i;
154
155
19.9k
  i = _sc_match_atr(card, flex_atrs, NULL);
156
19.9k
  if (i < 0)
157
19.5k
    return 0;
158
373
  switch (flex_atrs[i].type) {
159
200
  case SC_CARD_TYPE_FLEX_CYBER:
160
200
    card->name = flex_atrs[i].name;
161
200
    card->type = flex_atrs[i].type;
162
200
    card->flags = flex_atrs[i].flags;
163
200
    return 1;
164
373
  }
165
173
  return 0;
166
373
}
167
168
static int flex_init(sc_card_t *card)
169
373
{
170
373
  struct flex_private_data *data;
171
172
373
  if (!(data = malloc(sizeof(*data))))
173
0
    return SC_ERROR_OUT_OF_MEMORY;
174
373
  card->drv_data = data;
175
176
373
  card->cla = 0xC0;
177
373
  data->aak_key_ref = 1;
178
179
  /* Override Cryptoflex defaults for specific card types */
180
373
  switch (card->type) {
181
200
  case SC_CARD_TYPE_FLEX_CYBER:
182
200
    card->cla = 0x00;
183
200
    data->aak_key_ref = 0;
184
200
    break;
185
373
  }
186
187
  /* FIXME: Card type detection */
188
373
  if (1) {
189
373
    unsigned long flags;
190
191
373
    flags = SC_ALGORITHM_RSA_RAW;
192
373
    flags |= SC_ALGORITHM_RSA_HASH_NONE;
193
373
    if (card->flags & FLAG_KEYGEN)
194
172
      flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
195
196
373
    _sc_card_add_rsa_alg(card, 512, flags, 0);
197
373
    _sc_card_add_rsa_alg(card, 768, flags, 0);
198
373
    _sc_card_add_rsa_alg(card, 1024, flags, 0);
199
373
    _sc_card_add_rsa_alg(card, 2048, flags, 0);
200
373
  }
201
202
  /* SCardTransmit failed: 8010002f
203
   * this can be solved with a small delay. */
204
373
  msleep(100);
205
206
  /* State that we have an RNG */
207
373
  card->caps |= SC_CARD_CAP_RNG;
208
209
373
  return 0;
210
373
}
211
212
static void
213
add_acl_entry(sc_card_t *card, sc_file_t *file, unsigned int op, u8 nibble)
214
1.42k
{
215
1.42k
  struct flex_private_data *prv = DRV_DATA(card);
216
217
1.42k
  switch (nibble) {
218
540
  case 0:
219
540
    sc_file_add_acl_entry(file, op, SC_AC_NONE, SC_AC_KEY_REF_NONE);
220
540
    break;
221
30
  case 1:
222
30
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
223
30
    break;
224
112
  case 2:
225
112
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
226
112
    break;
227
47
  case 3:
228
47
    sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
229
47
    break;
230
95
  case 4:
231
    /* Assume the key is the AAK */
232
95
    sc_file_add_acl_entry(file, op, SC_AC_AUT, prv->aak_key_ref);
233
95
    break;
234
70
  case 6:
235
70
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
236
70
    sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
237
70
    break;
238
48
  case 7:
239
48
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
240
48
    sc_file_add_acl_entry(file, op, SC_AC_PRO, SC_AC_KEY_REF_NONE);
241
48
    break;
242
18
  case 8:
243
18
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 1);
244
    /* Assume the key is the AAK */
245
18
    sc_file_add_acl_entry(file, op, SC_AC_AUT, prv->aak_key_ref);
246
18
    break;
247
129
  case 9:
248
129
    sc_file_add_acl_entry(file, op, SC_AC_CHV, 2);
249
    /* Assume the key is the AAK */
250
129
    sc_file_add_acl_entry(file, op, SC_AC_AUT, prv->aak_key_ref);
251
129
    break;
252
230
  case 15:
253
230
    sc_file_add_acl_entry(file, op, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
254
230
    break;
255
102
  default:
256
102
    sc_file_add_acl_entry(file, op, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE);
257
102
    break;
258
1.42k
  }
259
1.42k
}
260
261
static int
262
cryptoflex_get_ac_keys(sc_card_t *card, sc_file_t *file)
263
250
{
264
250
  return 0;
265
250
}
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
304
{
271
304
  sc_context_t *ctx = card->ctx;
272
304
  const u8 *p = buf + 2;
273
304
  u8 b1, b2;
274
304
  int is_mf = 0;
275
276
304
  if (buflen < 14)
277
0
    return -1;
278
304
  b1 = *p++;
279
304
  b2 = *p++;
280
304
  file->size = (b1 << 8) + b2;
281
304
  b1 = *p++;
282
304
  b2 = *p++;
283
304
  file->id = (b1 << 8) + b2;
284
304
  if (file->id == 0x3F00)
285
24
    is_mf = 1;
286
304
  switch (*p) {
287
20
  case 0x01:
288
20
    file->type = SC_FILE_TYPE_WORKING_EF;
289
20
    file->ef_structure = SC_FILE_EF_TRANSPARENT;
290
20
    break;
291
73
  case 0x02:
292
73
    file->type = SC_FILE_TYPE_WORKING_EF;
293
73
    file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
294
73
    break;
295
23
  case 0x04:
296
23
    file->type = SC_FILE_TYPE_WORKING_EF;
297
23
    file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE;
298
23
    break;
299
106
  case 0x06:
300
106
    file->type = SC_FILE_TYPE_WORKING_EF;
301
106
    file->ef_structure = SC_FILE_EF_CYCLIC;
302
106
    break;
303
28
  case 0x38:
304
28
    file->type = SC_FILE_TYPE_DF;
305
28
    break;
306
54
  default:
307
54
    sc_log(ctx,  "invalid file type: 0x%02X\n", *p);
308
54
    return SC_ERROR_UNKNOWN_DATA_RECEIVED;
309
304
  }
310
250
  p += 2;
311
250
  if (file->type == SC_FILE_TYPE_DF) {
312
28
    add_acl_entry(card, file, SC_AC_OP_LIST_FILES, (u8)(p[0] >> 4));
313
28
    add_acl_entry(card, file, SC_AC_OP_DELETE, (u8)(p[1] >> 4));
314
28
    add_acl_entry(card, file, SC_AC_OP_CREATE, (u8)(p[1] & 0x0F));
315
222
  } else { /* EF */
316
222
    add_acl_entry(card, file, SC_AC_OP_READ, (u8)(p[0] >> 4));
317
222
    switch (file->ef_structure) {
318
20
    case SC_FILE_EF_TRANSPARENT:
319
20
      add_acl_entry(card, file, SC_AC_OP_UPDATE, (u8)(p[0] & 0x0F));
320
20
      break;
321
73
    case SC_FILE_EF_LINEAR_FIXED:
322
96
    case SC_FILE_EF_LINEAR_VARIABLE:
323
96
      add_acl_entry(card, file, SC_AC_OP_UPDATE, (u8)(p[0] & 0x0F));
324
96
      break;
325
106
    case SC_FILE_EF_CYCLIC:
326
106
      break;
327
222
    }
328
222
  }
329
250
  if (file->type != SC_FILE_TYPE_DF || is_mf) {
330
240
    add_acl_entry(card, file, SC_AC_OP_REHABILITATE, (u8)(p[2] >> 4));
331
240
    add_acl_entry(card, file, SC_AC_OP_INVALIDATE, (u8)(p[2] & 0x0F));
332
240
  }
333
250
  p += 3;
334
250
  if (*p)
335
215
    file->status = SC_FILE_STATUS_ACTIVATED;
336
35
  else
337
35
    file->status = SC_FILE_STATUS_INVALIDATED;
338
339
250
  return cryptoflex_get_ac_keys(card, file);
340
250
}
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
160
{
346
160
  sc_context_t *ctx = card->ctx;
347
160
  const u8 *p = buf + 2;
348
160
  const u8 *pos;
349
160
  u8 b1, b2;
350
160
  int is_mf = 0;
351
352
160
  if (buflen < 14)
353
0
    return -1;
354
160
  b1 = *p++;
355
160
  b2 = *p++;
356
160
  file->size = (b1 << 8) + b2;
357
160
  b1 = *p++;
358
160
  b2 = *p++;
359
160
  file->id = (b1 << 8) + b2;
360
160
  switch (*p) {
361
12
  case 0x01:
362
12
    is_mf = 1;
363
12
    break;
364
84
  case 0x02:
365
84
    file->type = SC_FILE_TYPE_DF;
366
84
    break;
367
45
  case 0x04:
368
45
    file->type = SC_FILE_TYPE_WORKING_EF;
369
45
    break;
370
19
  default:
371
19
    sc_log(ctx,  "invalid file type: 0x%02X\n", *p);
372
19
    return SC_ERROR_UNKNOWN_DATA_RECEIVED;
373
160
  }
374
375
141
  if (is_mf) {
376
12
    sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES, SC_AC_AUT, 0);
377
12
    sc_file_add_acl_entry(file, SC_AC_OP_DELETE, SC_AC_AUT, 0);
378
12
    sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_AUT, 0);
379
129
  } else {
380
129
    p += 2;
381
129
    if (file->type == SC_FILE_TYPE_DF) {
382
84
      add_acl_entry(card, file, SC_AC_OP_LIST_FILES, (u8)(p[0] >> 4));
383
84
      add_acl_entry(card, file, SC_AC_OP_DELETE, (u8)(p[1] >> 4));
384
84
      add_acl_entry(card, file, SC_AC_OP_CREATE, (u8)(p[1] & 0x0F));
385
84
    } else { /* EF */
386
45
      add_acl_entry(card, file, SC_AC_OP_READ, (u8)(p[0] >> 4));
387
45
    }
388
129
  }
389
141
  if (file->type != SC_FILE_TYPE_DF) {
390
57
    add_acl_entry(card, file, SC_AC_OP_REHABILITATE, (u8)(p[2] >> 4));
391
57
    add_acl_entry(card, file, SC_AC_OP_INVALIDATE, (u8)(p[2] & 0x0F));
392
57
  }
393
141
  pos = p;
394
141
  p += 3;
395
141
  if (*p++)
396
84
    file->status = SC_FILE_STATUS_ACTIVATED;
397
57
  else
398
57
    file->status = SC_FILE_STATUS_INVALIDATED;
399
141
  p++;
400
141
  if (0 == is_mf) {
401
129
    p++;
402
129
    switch (*p) {
403
59
    case  0x00:
404
59
      file->ef_structure = SC_FILE_EF_TRANSPARENT;
405
59
      break;
406
19
    case  0x01:
407
19
      file->ef_structure = SC_FILE_EF_LINEAR_FIXED;
408
19
      break;
409
30
    case  0x02:
410
30
      file->ef_structure = SC_FILE_EF_LINEAR_VARIABLE;
411
30
      break;
412
1
    case  0x03:
413
1
      file->ef_structure = SC_FILE_EF_CYCLIC;
414
1
      break;
415
5
    case  0x04:
416
5
      break;
417
15
    default:
418
15
      sc_log(ctx,  "invalid file type: 0x%02X\n", *p);
419
15
      return SC_ERROR_UNKNOWN_DATA_RECEIVED;
420
129
    }
421
114
    switch (file->ef_structure) {
422
59
    case SC_FILE_EF_TRANSPARENT:
423
59
      add_acl_entry(card, file, SC_AC_OP_UPDATE, (u8)(pos[0] & 0x0F));
424
59
      break;
425
19
    case SC_FILE_EF_LINEAR_FIXED:
426
49
    case SC_FILE_EF_LINEAR_VARIABLE:
427
49
      add_acl_entry(card, file, SC_AC_OP_UPDATE, (u8)(pos[0] & 0x0F));
428
49
      break;
429
1
    case SC_FILE_EF_CYCLIC:
430
1
      break;
431
114
    }
432
114
  }
433
126
  return 0;
434
141
}
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
3.71k
{
439
3.71k
  int r;
440
3.71k
  sc_apdu_t apdu;
441
3.71k
        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
442
3.71k
        sc_file_t *file;
443
444
3.71k
  sc_log(card->ctx,  "called, p1=%u\n", p1);
445
3.71k
  sc_log_hex(card->ctx, "path", buf, buflen);
446
447
3.71k
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, p1, 0);
448
3.71k
  apdu.resp = rbuf;
449
3.71k
  apdu.resplen = sizeof(rbuf);
450
3.71k
  apdu.datalen = buflen;
451
3.71k
  apdu.data = buf;
452
3.71k
  apdu.lc = buflen;
453
3.71k
  apdu.le = 252;
454
455
  /* No need to get file information, if file is NULL. */
456
3.71k
  if (file_out == NULL) {
457
3.05k
    apdu.cse = SC_APDU_CASE_3_SHORT;
458
3.05k
    apdu.le = 0;
459
3.05k
  }
460
3.71k
  r = sc_transmit_apdu(card, &apdu);
461
3.71k
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
462
3.68k
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
463
3.68k
  LOG_TEST_RET(card->ctx, r, "Card returned error");
464
465
1.82k
  if (file_out == NULL)
466
1.29k
    return 0;
467
468
529
  if (apdu.resplen < 14)
469
53
    return SC_ERROR_UNKNOWN_DATA_RECEIVED;
470
476
  if (apdu.resp[0] == 0x6F) {
471
12
    sc_log(card->ctx,  "unsupported: card returned FCI\n");
472
12
    return SC_ERROR_UNKNOWN_DATA_RECEIVED; /* FIXME */
473
12
  }
474
464
  file = sc_file_new();
475
464
  if (file == NULL)
476
464
    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
464
  r = card->ops->process_fci(card, file, apdu.resp, apdu.resplen);
480
464
  if (r) {
481
88
    sc_file_free(file);
482
88
    return r;
483
88
  }
484
485
376
  *file_out = file;
486
376
  return 0;
487
464
}
488
489
static int flex_select_file(sc_card_t *card, const sc_path_t *path,
490
           sc_file_t **file_out)
491
2.70k
{
492
2.70k
  int r;
493
2.70k
  const u8 *pathptr = path->value;
494
2.70k
  size_t pathlen = path->len;
495
2.70k
  int locked = 0;
496
2.70k
  u8 p1 = 0;
497
498
2.70k
  switch (path->type) {
499
1.90k
  case SC_PATH_TYPE_PATH:
500
1.90k
    if ((pathlen & 1) != 0) /* not divisible by 2 */
501
0
      return SC_ERROR_INVALID_ARGUMENTS;
502
1.90k
    if (pathlen == 0)
503
6
      return 0;
504
1.89k
    if (pathlen != 2 || memcmp(pathptr, "\x3F\x00", 2) != 0) {
505
1.79k
      locked = 1;
506
1.79k
      r = sc_lock(card);
507
1.79k
      LOG_TEST_RET(card->ctx, r, "sc_lock() failed");
508
1.79k
      if (memcmp(pathptr, "\x3F\x00", 2) != 0) {
509
134
        r = select_file_id(card, (const u8 *) "\x3F\x00", 2, 0, NULL);
510
134
        if (r)
511
75
          sc_unlock(card);
512
134
        LOG_TEST_RET(card->ctx, r, "Unable to select Master File (MF)");
513
134
      }
514
2.70k
      while (pathlen > 2) {
515
2.05k
        r = select_file_id(card, pathptr, 2, 0, NULL);
516
2.05k
        if (r)
517
1.06k
          sc_unlock(card);
518
2.05k
        LOG_TEST_RET(card->ctx, r, "Unable to select DF");
519
986
        pathptr += 2;
520
986
        pathlen -= 2;
521
986
      }
522
1.71k
    }
523
756
    break;
524
756
  case SC_PATH_TYPE_DF_NAME:
525
738
    p1 = 0x04;
526
738
    break;
527
59
  case SC_PATH_TYPE_FILE_ID:
528
59
    if (pathlen != 2)
529
30
      return SC_ERROR_INVALID_ARGUMENTS;
530
29
    break;
531
2.70k
  }
532
1.52k
  r = select_file_id(card, pathptr, pathlen, p1, file_out);
533
1.52k
  if (locked)
534
647
    sc_unlock(card);
535
1.52k
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
536
1.52k
}
537
538
static int cryptoflex_list_files(sc_card_t *card, u8 *buf, size_t buflen)
539
0
{
540
0
  sc_apdu_t apdu;
541
0
  u8 rbuf[4];
542
0
  int r;
543
0
  size_t count = 0;
544
545
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xA8, 0, 0);
546
0
  apdu.cla = 0xF0;
547
0
  apdu.le = 4;
548
0
  apdu.resplen = 4;
549
0
  apdu.resp = rbuf;
550
0
  while (buflen > 2) {
551
0
    r = sc_transmit_apdu(card, &apdu);
552
0
    if (r)
553
0
      return r;
554
0
    if (apdu.sw1 == 0x6A && apdu.sw2 == 0x82)
555
0
      break;
556
0
    r = sc_check_sw(card, apdu.sw1, apdu.sw2);
557
0
    if (r)
558
0
      return r;
559
0
    if (apdu.resplen != 4) {
560
0
      sc_log(card->ctx,
561
0
         "expected 4 bytes, got %"SC_FORMAT_LEN_SIZE_T"u.\n",
562
0
         apdu.resplen);
563
0
      return SC_ERROR_UNKNOWN_DATA_RECEIVED;
564
0
    }
565
0
    memcpy(buf, rbuf + 2, 2);
566
0
    buf += 2;
567
0
    count += 2;
568
0
    buflen -= 2;
569
0
  }
570
0
  return (int)count;
571
0
}
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
21
{
612
21
  sc_apdu_t apdu;
613
21
  int r;
614
615
21
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
616
21
  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
21
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
621
21
  if (!IS_CYBERFLEX(card))
622
19
    apdu.cla = 0xF0; /* Override CLA byte */
623
21
  apdu.data = path->value;
624
21
  apdu.lc = 2;
625
21
  apdu.datalen = 2;
626
627
21
  r = sc_transmit_apdu(card, &apdu);
628
21
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
629
20
  return sc_check_sw(card, apdu.sw1, apdu.sw2);
630
21
}
631
632
static int acl_to_ac_nibble(const sc_acl_entry_t *e)
633
140
{
634
140
  if (e == NULL)
635
0
    return -1;
636
140
  if (e->next != NULL)  /* FIXME */
637
1
    return -1;
638
139
  switch (e->method) {
639
78
  case SC_AC_NONE:
640
78
    return 0x00;
641
26
  case SC_AC_CHV:
642
26
    switch (e->key_ref) {
643
25
    case 1:
644
25
      return 0x01;
645
0
      break;
646
0
    case 2:
647
0
      return 0x02;
648
0
      break;
649
26
    }
650
1
    return -1;
651
1
  case SC_AC_PRO:
652
1
    return 0x03;
653
1
  case SC_AC_AUT:
654
1
    return 0x04;
655
3
  case SC_AC_NEVER:
656
3
    return 0x0f;
657
139
  }
658
30
  return -1;
659
139
}
660
661
static int acl_to_keynum_nibble(const sc_acl_entry_t *e)
662
108
{
663
215
  while (e != NULL && e->method != SC_AC_AUT)
664
107
    e = e->next;
665
108
  if (e == NULL || e->key_ref == SC_AC_KEY_REF_NONE)
666
107
    return 0;
667
668
1
  return e->key_ref & 0x0F;
669
108
}
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
51
{
675
51
  u8 *p = buf;
676
51
  int r, i;
677
51
  int ops[6];
678
679
51
  p[0] = 0xFF;
680
51
  p[1] = 0xFF;
681
51
  p[2] = file->size >> 8;
682
51
  p[3] = file->size & 0xFF;
683
51
  p[4] = file->id >> 8;
684
51
  p[5] = file->id & 0xFF;
685
51
  if (file->type == SC_FILE_TYPE_DF)
686
50
    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
50
  p[7] = 0xFF;  /* allow Decrease and Increase */
706
350
  for (i = 0; i < 6; i++)
707
300
    ops[i] = -1;
708
50
  if (file->type == SC_FILE_TYPE_DF) {
709
50
    ops[0] = SC_AC_OP_LIST_FILES;
710
50
    ops[2] = SC_AC_OP_DELETE;
711
50
    ops[3] = SC_AC_OP_CREATE;
712
50
  } 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
50
  p[8] = p[9] = p[10] = 0;
721
50
  p[13] = p[14] = p[15] = 0; /* Key numbers */
722
242
  for (i = 0; i < 6; i++) {
723
224
    const sc_acl_entry_t *entry;
724
224
    if (ops[i] == -1)
725
84
      continue;
726
140
    entry = sc_file_get_acl_entry(file, ops[i]);
727
140
    r = acl_to_ac_nibble(entry);
728
140
    LOG_TEST_RET(card->ctx, r, "Invalid ACL value");
729
    /* Do some magic to get the nibbles right */
730
108
    p[8 + i/2] |= (r & 0x0F) << (((i+1) % 2) * 4);
731
108
    r = acl_to_keynum_nibble(entry);
732
108
    p[13 + i/2] |= (r & 0x0F) << (((i+1) % 2) * 4);
733
108
  }
734
18
  p[11] = (file->status == SC_FILE_STATUS_INVALIDATED) ? 0x00 : 0x01;
735
18
  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
18
  else
740
18
    p[12] = 0x03;
741
18
  if (p[12] == 0x04) {
742
0
    p[16] = file->record_length;
743
0
    *buflen = 17;
744
0
  } else
745
18
    *buflen = 16;
746
747
18
  return 0;
748
50
}
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
6
{
754
6
  u8 *p = buf;
755
6
  size_t size = file->size;
756
757
  /* cyberflex wants input parameters length added */
758
6
  switch (file->type) {
759
1
  case SC_FILE_TYPE_DF:
760
1
    size += 24;
761
1
    break;
762
4
  case SC_FILE_TYPE_WORKING_EF:
763
5
  default:
764
5
    size += 16;
765
5
    break;
766
6
  }
767
768
6
  sc_log(card->ctx,
769
6
     "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
6
     file->id >> 8,
771
6
     file->id & 0xFF,
772
6
     size,
773
6
     size >> 8,
774
6
     size & 0xFF);
775
776
6
  p[0] = size >> 8;
777
6
  p[1] = size & 0xFF;
778
6
  p[2] = file->id >> 8;
779
6
  p[3] = file->id & 0xFF;
780
6
  if (file->type == SC_FILE_TYPE_DF)
781
1
    p[4] = 0x20;
782
5
  else
783
5
    switch (file->ef_structure) {
784
3
    case SC_FILE_EF_TRANSPARENT:
785
3
      p[4] = 0x02;
786
3
      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
2
    default:
797
2
      sc_log(card->ctx,  "Invalid EF structure\n");
798
2
      return -1;
799
5
    }
800
4
  p[5] = 0x01;  /* status?? */
801
4
  p[6] = p[7] = 0;
802
803
4
  *buflen = 16;
804
805
4
  p[8] = p[9] = p[11] = 0xFF;
806
4
  p[10] = p[12] = p[13] = p[14] = p[15] = 0x00;
807
4
  return 0;
808
6
}
809
810
static int flex_create_file(sc_card_t *card, sc_file_t *file)
811
57
{
812
57
  u8 sbuf[18];
813
57
  size_t sendlen;
814
57
  int r, rec_nr;
815
57
  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
57
  r = card->ops->construct_fci(card, file, sbuf, &sendlen);
821
57
  if (r) {
822
35
    sc_log(card->ctx,  "File structure encoding failed.\n");
823
35
    return SC_ERROR_INVALID_ARGUMENTS;
824
35
  }
825
22
  if (file->type != SC_FILE_TYPE_DF && file->ef_structure != SC_FILE_EF_TRANSPARENT)
826
0
    rec_nr = (int)file->record_count;
827
22
  else
828
22
    rec_nr = 0;
829
22
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, rec_nr);
830
22
  if (!IS_CYBERFLEX(card))
831
18
    apdu.cla = 0xF0;
832
22
  apdu.data = sbuf;
833
22
  apdu.datalen = sendlen;
834
22
  apdu.lc = sendlen;
835
836
22
  r = sc_transmit_apdu(card, &apdu);
837
22
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
838
20
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
839
20
  LOG_TEST_RET(card->ctx, r, "Card returned error");
840
6
  return SC_SUCCESS;
841
20
}
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
14
{
1000
14
  struct flex_private_data *prv = DRV_DATA(card);
1001
14
  const char *key;
1002
1003
14
  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
14
  switch (card->type) {
1008
7
  case SC_CARD_TYPE_FLEX_CRYPTO:
1009
7
    key = "2c:15:e5:26:e9:3e:8a:19";
1010
7
    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
14
  }
1017
1018
14
  return sc_hex_to_bin(key, data->key_data, &data->len);
1019
14
}
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
75
{
1065
75
  int       r;
1066
75
  u8        buf[16];
1067
75
  size_t    len;
1068
75
  sc_path_t tpath;
1069
75
  sc_file_t *tfile = NULL;
1070
1071
75
  if (!serial)
1072
0
    return SC_ERROR_INVALID_ARGUMENTS;
1073
  /* see if we have cached serial number */
1074
75
  if (card->serialnr.len) {
1075
0
    memcpy(serial, &card->serialnr, sizeof(*serial));
1076
0
    return SC_SUCCESS;
1077
0
  }
1078
  /* read EF_ICCSN */
1079
75
  sc_format_path("3F000002", &tpath);
1080
75
  r = sc_select_file(card, &tpath, &tfile);
1081
75
  if (r < 0)
1082
57
    return r;
1083
18
  len = tfile->size;
1084
18
  sc_file_free(tfile);
1085
18
  if (len != 8) {
1086
16
    sc_log(card->ctx,  "unexpected file length of EF_ICCSN (%lu)\n",
1087
16
      (unsigned long) len);
1088
16
    return SC_ERROR_INTERNAL;
1089
16
  }
1090
2
  r = sc_read_binary(card, 0, buf, len, 0);
1091
2
  if (r < 0)
1092
1
    return r;
1093
1
  card->serialnr.len = len;
1094
1
  memcpy(card->serialnr.value, buf, len);
1095
1096
1
  memcpy(serial, &card->serialnr, sizeof(*serial));
1097
1098
1
  return SC_SUCCESS;
1099
2
}
1100
1101
static int flex_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
1102
519
{
1103
519
  switch (cmd) {
1104
14
  case SC_CARDCTL_GET_DEFAULT_KEY:
1105
14
    return flex_get_default_key(card,
1106
14
        (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
75
  case SC_CARDCTL_GET_SERIALNR:
1111
75
    return flex_get_serialnr(card, (sc_serial_number_t *) ptr);
1112
519
  }
1113
1114
430
  return SC_ERROR_NOT_SUPPORTED;
1115
519
}
1116
1117
static int flex_build_verify_apdu(sc_card_t *card, sc_apdu_t *apdu,
1118
          struct sc_pin_cmd_data *data)
1119
28
{
1120
28
  static u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
1121
28
  int r, len;
1122
28
  int cla = card->cla, ins;
1123
1124
28
  switch (data->pin_type) {
1125
21
  case SC_AC_CHV:
1126
21
    ins = 0x20;
1127
21
    break;
1128
7
  case SC_AC_AUT:
1129
    /* AUT keys cannot be entered through terminal */
1130
7
    if (data->flags & SC_PIN_CMD_USE_PINPAD)
1131
0
      return SC_ERROR_INVALID_ARGUMENTS;
1132
    /* Override CLA byte */
1133
7
    if (!IS_CYBERFLEX(card))
1134
4
      cla = 0xF0;
1135
7
    ins = 0x2A;
1136
7
    break;
1137
0
  default:
1138
0
    return SC_ERROR_INVALID_ARGUMENTS;
1139
28
  }
1140
  /* Copy the PIN, with padding */
1141
28
  if ((r = sc_build_pin(sbuf, sizeof(sbuf), &data->pin1, 1)) < 0)
1142
0
    return r;
1143
28
  len = r;
1144
1145
28
  sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, ins, 0, data->pin_reference);
1146
28
  apdu->cla = cla;
1147
28
  apdu->data = sbuf;
1148
28
  apdu->datalen = len;
1149
28
  apdu->lc = len;
1150
1151
28
  return 0;
1152
28
}
1153
1154
static void flex_init_pin_info(struct sc_pin_cmd_pin *pin, unsigned int num)
1155
208
{
1156
208
  pin->encoding   = SC_PIN_ENCODING_ASCII;
1157
208
  pin->min_length = 4;
1158
208
  pin->max_length = 8;
1159
208
  pin->pad_length = 8;
1160
208
  pin->offset     = 5 + num * 8;
1161
208
}
1162
1163
static int flex_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
1164
      int *tries_left)
1165
104
{
1166
104
  sc_apdu_t apdu;
1167
104
  int r;
1168
104
  int old_cla = -1;
1169
1170
  /* Fix pin data */
1171
104
  data->flags |= SC_PIN_CMD_NEED_PADDING;
1172
104
  flex_init_pin_info(&data->pin1, 0);
1173
104
  flex_init_pin_info(&data->pin2, 1);
1174
1175
104
  if (data->cmd == SC_PIN_CMD_VERIFY) {
1176
28
    r = flex_build_verify_apdu(card, &apdu, data);
1177
28
    if (r < 0)
1178
0
      return r;
1179
28
    data->apdu = &apdu;
1180
76
  } 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
104
  r = iso_ops->pin_cmd(card, data, NULL);
1193
104
  if (old_cla != -1)
1194
0
    card->cla = old_cla;
1195
104
  data->apdu = NULL;
1196
104
  return r;
1197
104
}
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
19.9k
{
1219
19.9k
  if (iso_ops == NULL)
1220
0
    iso_ops = sc_get_iso7816_driver()->ops;
1221
1222
19.9k
  cryptoflex_ops = *iso_ops;
1223
19.9k
  cryptoflex_ops.match_card = cryptoflex_match_card;
1224
19.9k
  cryptoflex_ops.init = flex_init;
1225
19.9k
  cryptoflex_ops.finish = flex_finish;
1226
19.9k
  cryptoflex_ops.process_fci = cryptoflex_process_file_attrs;
1227
19.9k
  cryptoflex_ops.construct_fci = cryptoflex_construct_file_attrs;
1228
19.9k
  cryptoflex_ops.select_file = flex_select_file;
1229
19.9k
  cryptoflex_ops.list_files = cryptoflex_list_files;
1230
19.9k
  cryptoflex_ops.delete_file = flex_delete_file;
1231
19.9k
  cryptoflex_ops.create_file = flex_create_file;
1232
19.9k
  cryptoflex_ops.card_ctl = flex_card_ctl;
1233
19.9k
  cryptoflex_ops.set_security_env = flex_set_security_env;
1234
19.9k
  cryptoflex_ops.restore_security_env = flex_restore_security_env;
1235
19.9k
  cryptoflex_ops.compute_signature = cryptoflex_compute_signature;
1236
19.9k
  cryptoflex_ops.decipher = flex_decipher;
1237
19.9k
  cryptoflex_ops.pin_cmd = flex_pin_cmd;
1238
19.9k
  cryptoflex_ops.logout = flex_logout;
1239
19.9k
  return &cryptoflex_drv;
1240
19.9k
}
1241
1242
struct sc_card_driver * sc_get_cyberflex_driver(void)
1243
19.9k
{
1244
19.9k
  if (iso_ops == NULL)
1245
1
    iso_ops = sc_get_iso7816_driver()->ops;
1246
1247
19.9k
  cyberflex_ops = *iso_ops;
1248
19.9k
  cyberflex_ops.match_card = cyberflex_match_card;
1249
19.9k
  cyberflex_ops.init = flex_init;
1250
19.9k
  cyberflex_ops.finish = flex_finish;
1251
19.9k
  cyberflex_ops.process_fci = cyberflex_process_file_attrs;
1252
19.9k
  cyberflex_ops.construct_fci = cyberflex_construct_file_attrs;
1253
19.9k
  cyberflex_ops.select_file = flex_select_file;
1254
19.9k
  cyberflex_ops.list_files = cyberflex_list_files;
1255
19.9k
  cyberflex_ops.delete_file = flex_delete_file;
1256
19.9k
  cyberflex_ops.create_file = flex_create_file;
1257
19.9k
  cyberflex_ops.card_ctl = flex_card_ctl;
1258
19.9k
  cyberflex_ops.set_security_env = flex_set_security_env;
1259
19.9k
  cyberflex_ops.restore_security_env = flex_restore_security_env;
1260
19.9k
  cyberflex_ops.compute_signature = cyberflex_compute_signature;
1261
19.9k
  cyberflex_ops.decipher = flex_decipher;
1262
19.9k
  cyberflex_ops.pin_cmd = flex_pin_cmd;
1263
19.9k
  cyberflex_ops.logout = flex_logout;
1264
19.9k
  return &cyberflex_drv;
1265
19.9k
}