Coverage Report

Created: 2025-08-26 06:43

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