Coverage Report

Created: 2025-09-04 06:45

/src/opensc/src/libopensc/card-muscle.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * card-muscle.c: Support for MuscleCard Applet from musclecard.com
3
 *
4
 * Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com>
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
#include "muscle.h"
31
#include "muscle-filesystem.h"
32
#include "types.h"
33
#include "opensc.h"
34
35
static struct sc_card_operations muscle_ops;
36
static const struct sc_card_operations *iso_ops = NULL;
37
38
static struct sc_card_driver muscle_drv = {
39
  "MuscleApplet",
40
  "muscle",
41
  &muscle_ops,
42
  NULL, 0, NULL
43
};
44
45
static const struct sc_atr_table muscle_atrs[] = {
46
  /* Tyfone JCOP 242R2 cards */
47
  { "3b:6d:00:00:ff:54:79:66:6f:6e:65:20:32:34:32:52:32", NULL, NULL, SC_CARD_TYPE_MUSCLE_JCOP242R2_NO_EXT_APDU, 0, NULL },
48
  /* Aladdin eToken PRO USB 72K Java */
49
  { "3b:d5:18:00:81:31:3a:7d:80:73:c8:21:10:30", NULL, NULL, SC_CARD_TYPE_MUSCLE_ETOKEN_72K, 0, NULL },
50
  /* JCOP31 v2.4.1 contact interface */
51
  { "3b:f8:13:00:00:81:31:fe:45:4a:43:4f:50:76:32:34:31:b7", NULL, NULL, SC_CARD_TYPE_MUSCLE_JCOP241, 0, NULL },
52
  /* JCOP31 v2.4.1 RF interface */
53
  { "3b:88:80:01:4a:43:4f:50:76:32:34:31:5e", NULL, NULL, SC_CARD_TYPE_MUSCLE_JCOP241, 0, NULL },
54
  { NULL, NULL, NULL, 0, 0, NULL }
55
};
56
57
1.25k
#define MUSCLE_DATA(card) ( (muscle_private_t*)card->drv_data )
58
0
#define MUSCLE_FS(card) ( ((muscle_private_t*)card->drv_data)->fs )
59
typedef struct muscle_private {
60
  sc_security_env_t env;
61
  unsigned short verifiedPins;
62
  mscfs_t *fs;
63
  int rsa_key_ref;
64
65
} muscle_private_t;
66
67
static int muscle_finish(sc_card_t *card)
68
419
{
69
419
  muscle_private_t *priv = MUSCLE_DATA(card);
70
419
  mscfs_free(priv->fs);
71
419
  free(priv);
72
419
  return 0;
73
419
}
74
75
76
static u8 muscleAppletId[] = { 0xA0, 0x00,0x00,0x00, 0x01, 0x01 };
77
78
static int muscle_match_card(sc_card_t *card)
79
6.06k
{
80
6.06k
  sc_apdu_t apdu;
81
6.06k
  u8 response[64];
82
6.06k
  int r;
83
84
6.06k
  if (msc_select_applet(card, muscleAppletId, sizeof muscleAppletId) == 1) {
85
    /* Muscle applet is present, check the protocol version to be sure */
86
419
    sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x3C, 0x00, 0x00);
87
419
    apdu.cla = 0xB0;
88
419
    apdu.le = 64;
89
419
    apdu.resplen = 64;
90
419
    apdu.resp = response;
91
419
    r = sc_transmit_apdu(card, &apdu);
92
419
    if (r == SC_SUCCESS && apdu.resplen > 1 && response[0] == 0x01) {
93
1
      card->type = SC_CARD_TYPE_MUSCLE_V1;
94
418
    } else {
95
418
      card->type = SC_CARD_TYPE_MUSCLE_GENERIC;
96
418
    }
97
419
    return 1;
98
419
  }
99
5.64k
  return 0;
100
6.06k
}
101
102
/* Since Musclecard has a different ACL system then PKCS15
103
 * objects need to have their READ/UPDATE/DELETE permissions mapped for files
104
 * and directory ACLS need to be set
105
 * For keys.. they have different ACLS, but are accessed in different locations, so it shouldn't be an issue here
106
 */
107
static unsigned short muscle_parse_singleAcl(const sc_acl_entry_t* acl)
108
0
{
109
0
  unsigned short acl_entry = 0;
110
0
  while(acl) {
111
0
    int key = acl->key_ref;
112
0
    int method = acl->method;
113
0
    switch(method) {
114
0
    case SC_AC_NEVER:
115
0
      return 0xFFFF;
116
    /* Ignore... other items overwrite these */
117
0
    case SC_AC_NONE:
118
0
    case SC_AC_UNKNOWN:
119
0
      break;
120
0
    case SC_AC_CHV:
121
      /* Ignore shift with more bits that acl_entry has */
122
0
      if ((size_t) key < sizeof(acl_entry) * 8)
123
0
        acl_entry |= (1u << key); /* Assuming key 0 == SO */
124
0
      break;
125
0
    case SC_AC_AUT:
126
0
    case SC_AC_TERM:
127
0
    case SC_AC_PRO:
128
0
    default:
129
      /* Ignored */
130
0
      break;
131
0
    }
132
0
    acl = acl->next;
133
0
  }
134
0
  return acl_entry;
135
0
}
136
137
static void muscle_parse_acls(const sc_file_t* file, unsigned short* read_perm, unsigned short* write_perm, unsigned short* delete_perm)
138
0
{
139
0
  assert(read_perm && write_perm && delete_perm);
140
0
  *read_perm =  muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_READ));
141
0
  *write_perm =  muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_UPDATE));
142
0
  *delete_perm =  muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_DELETE));
143
0
}
144
145
static int muscle_create_directory(sc_card_t *card, sc_file_t *file)
146
0
{
147
0
  mscfs_t *fs = MUSCLE_FS(card);
148
0
  msc_id objectId;
149
0
  u8* oid = objectId.id;
150
0
  unsigned id = file->id;
151
0
  unsigned short read_perm = 0, write_perm = 0, delete_perm = 0;
152
0
  size_t objectSize;
153
0
  int r;
154
0
  if(id == 0) /* No null name files */
155
0
    return SC_ERROR_INVALID_ARGUMENTS;
156
157
  /* No nesting directories */
158
0
  if(fs->currentPath[0] != 0x3F || fs->currentPath[1] != 0x00)
159
0
    return SC_ERROR_NOT_SUPPORTED;
160
0
  oid[0] = ((id & 0xFF00) >> 8) & 0xFF;
161
0
  oid[1] = id & 0xFF;
162
0
  oid[2] = oid[3] = 0;
163
164
0
  objectSize = file->size;
165
166
0
  muscle_parse_acls(file, &read_perm, &write_perm, &delete_perm);
167
0
  r = msc_create_object(card, objectId, objectSize, read_perm, write_perm, delete_perm);
168
0
  mscfs_clear_cache(fs);
169
0
  if(r >= 0) return 0;
170
0
  return r;
171
0
}
172
173
174
static int muscle_create_file(sc_card_t *card, sc_file_t *file)
175
0
{
176
0
  mscfs_t *fs = MUSCLE_FS(card);
177
0
  size_t objectSize = file->size;
178
0
  unsigned short read_perm = 0, write_perm = 0, delete_perm = 0;
179
0
  msc_id objectId;
180
0
  int r;
181
0
  if(file->type == SC_FILE_TYPE_DF)
182
0
    return muscle_create_directory(card, file);
183
0
  if(file->type != SC_FILE_TYPE_WORKING_EF)
184
0
    return SC_ERROR_NOT_SUPPORTED;
185
0
  if(file->id == 0) /* No null name files */
186
0
    return SC_ERROR_INVALID_ARGUMENTS;
187
188
0
  muscle_parse_acls(file, &read_perm, &write_perm, &delete_perm);
189
190
0
  mscfs_lookup_local(fs, file->id, &objectId);
191
0
  r = msc_create_object(card, objectId, objectSize, read_perm, write_perm, delete_perm);
192
0
  mscfs_clear_cache(fs);
193
0
  if(r >= 0) return 0;
194
0
  return r;
195
0
}
196
197
static int muscle_read_binary(sc_card_t *card, unsigned int idx, u8* buf, size_t count, unsigned long *flags)
198
0
{
199
0
  mscfs_t *fs = MUSCLE_FS(card);
200
0
  int r;
201
0
  msc_id objectId;
202
0
  u8* oid = objectId.id;
203
0
  mscfs_file_t *file;
204
205
0
  r = mscfs_check_selection(fs, -1);
206
0
  if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
207
0
  file = &fs->cache.array[fs->currentFileIndex];
208
0
  objectId = file->objectId;
209
  /* memcpy(objectId.id, file->objectId.id, 4); */
210
0
  if(!file->ef) {
211
0
    oid[0] = oid[2];
212
0
    oid[1] = oid[3];
213
0
    oid[2] = oid[3] = 0;
214
0
  }
215
0
  r = msc_read_object(card, objectId, idx, buf, count);
216
0
  LOG_FUNC_RETURN(card->ctx, r);
217
0
}
218
219
static int muscle_update_binary(sc_card_t *card, unsigned int idx, const u8* buf, size_t count, unsigned long flags)
220
0
{
221
0
  mscfs_t *fs = MUSCLE_FS(card);
222
0
  int r;
223
0
  mscfs_file_t *file;
224
0
  msc_id objectId;
225
0
  u8* oid = objectId.id;
226
227
0
  r = mscfs_check_selection(fs, -1);
228
0
  if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
229
0
  file = &fs->cache.array[fs->currentFileIndex];
230
231
0
  objectId = file->objectId;
232
  /* memcpy(objectId.id, file->objectId.id, 4); */
233
0
  if(!file->ef) {
234
0
    oid[0] = oid[2];
235
0
    oid[1] = oid[3];
236
0
    oid[2] = oid[3] = 0;
237
0
  }
238
0
  if(file->size < idx + count) {
239
0
    size_t newFileSize = idx + count;
240
0
    u8* buffer = malloc(newFileSize);
241
0
    if(buffer == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
242
243
0
    r = msc_read_object(card, objectId, 0, buffer, file->size);
244
    /* TODO: RETRIEVE ACLS */
245
0
    if(r < 0) goto update_bin_free_buffer;
246
0
    r = msc_delete_object(card, objectId, 0);
247
0
    if(r < 0) goto update_bin_free_buffer;
248
0
    r = msc_create_object(card, objectId, newFileSize, 0,0,0);
249
0
    if(r < 0) goto update_bin_free_buffer;
250
0
    memcpy(buffer + idx, buf, count);
251
0
    r = msc_update_object(card, objectId, 0, buffer, newFileSize);
252
0
    if(r < 0) goto update_bin_free_buffer;
253
0
    file->size = newFileSize;
254
0
update_bin_free_buffer:
255
0
    free(buffer);
256
0
    LOG_FUNC_RETURN(card->ctx, r);
257
0
  } else {
258
0
    r = msc_update_object(card, objectId, idx, buf, count);
259
0
  }
260
  /* mscfs_clear_cache(fs); */
261
0
  return r;
262
0
}
263
264
/* TODO: Evaluate correctness */
265
static int muscle_delete_mscfs_file(sc_card_t *card, mscfs_file_t *file_data)
266
0
{
267
0
  mscfs_t *fs = MUSCLE_FS(card);
268
0
  msc_id id = file_data->objectId;
269
0
  u8* oid = id.id;
270
0
  int r;
271
0
  file_data->deleteFile = 1;
272
273
0
  if(!file_data->ef) {
274
0
    int x;
275
0
    mscfs_file_t *childFile;
276
    /* Delete children */
277
0
    r = mscfs_check_cache(fs);
278
0
    if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
279
280
0
    sc_log(card->ctx,
281
0
      "DELETING Children of: %02X%02X%02X%02X\n",
282
0
      oid[0],oid[1],oid[2],oid[3]);
283
0
    for(x = 0; x < fs->cache.size; x++) {
284
0
      msc_id objectId;
285
0
      childFile = &fs->cache.array[x];
286
0
      objectId = childFile->objectId;
287
288
0
      if(0 == memcmp(oid + 2, objectId.id, 2) && !childFile->deleteFile) {
289
0
        sc_log(card->ctx,
290
0
          "DELETING: %02X%02X%02X%02X\n",
291
0
          objectId.id[0],objectId.id[1],
292
0
          objectId.id[2],objectId.id[3]);
293
0
        r = muscle_delete_mscfs_file(card, childFile);
294
0
        if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
295
296
0
      }
297
0
    }
298
0
    oid[0] = oid[2];
299
0
    oid[1] = oid[3];
300
0
    oid[2] = oid[3] = 0;
301
    /* ??? objectId = objectId >> 16; */
302
0
  }
303
0
  r = msc_delete_object(card, id, 1);
304
  /* Check if its the root... this file generally is virtual
305
   * So don't return an error if it fails */
306
0
  if((0 == memcmp(oid, "\x3F\x00\x00\x00", 4))
307
0
    || (0 == memcmp(oid, "\x3F\x00\x3F\x00", 4)))
308
0
    return 0;
309
310
0
  if(r < 0) {
311
0
    printf("ID: %02X%02X%02X%02X\n",
312
0
          oid[0],oid[1],oid[2],oid[3]);
313
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
314
0
  }
315
0
  return 0;
316
0
}
317
318
static int muscle_delete_file(sc_card_t *card, const sc_path_t *path_in)
319
0
{
320
0
  mscfs_t *fs = MUSCLE_FS(card);
321
0
  mscfs_file_t *file_data = NULL;
322
0
  int r = 0;
323
324
0
  r = mscfs_loadFileInfo(fs, path_in->value, path_in->len, &file_data, NULL);
325
0
  if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
326
0
  for(int x = 0; x < fs->cache.size; x++) {
327
0
    mscfs_file_t *file = &fs->cache.array[x];
328
0
    file->deleteFile = 0;
329
0
  }
330
0
  r = muscle_delete_mscfs_file(card, file_data);
331
0
  mscfs_clear_cache(fs);
332
0
  if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
333
0
  return 0;
334
0
}
335
336
static void muscle_load_single_acl(sc_file_t* file, int operation, unsigned short acl)
337
0
{
338
0
  int key;
339
  /* Everybody by default.... */
340
0
  sc_file_add_acl_entry(file, operation, SC_AC_NONE, 0);
341
0
  if(acl == 0xFFFF) {
342
0
    sc_file_add_acl_entry(file, operation, SC_AC_NEVER, 0);
343
0
    return;
344
0
  }
345
0
  for(key = 0; key < 16; key++) {
346
0
    if(acl >> key & 1) {
347
0
      sc_file_add_acl_entry(file, operation, SC_AC_CHV, key);
348
0
    }
349
0
  }
350
0
}
351
static void muscle_load_file_acls(sc_file_t* file, mscfs_file_t *file_data)
352
0
{
353
0
  muscle_load_single_acl(file, SC_AC_OP_READ, file_data->read);
354
0
  muscle_load_single_acl(file, SC_AC_OP_WRITE, file_data->write);
355
0
  muscle_load_single_acl(file, SC_AC_OP_UPDATE, file_data->write);
356
0
  muscle_load_single_acl(file, SC_AC_OP_DELETE, file_data->delete);
357
0
}
358
static void muscle_load_dir_acls(sc_file_t* file, mscfs_file_t *file_data)
359
0
{
360
0
  muscle_load_single_acl(file, SC_AC_OP_SELECT, 0);
361
0
  muscle_load_single_acl(file, SC_AC_OP_LIST_FILES, 0);
362
0
  muscle_load_single_acl(file, SC_AC_OP_LOCK, 0xFFFF);
363
0
  muscle_load_single_acl(file, SC_AC_OP_DELETE, file_data->delete);
364
0
  muscle_load_single_acl(file, SC_AC_OP_CREATE, file_data->write);
365
0
}
366
367
/* Required type = -1 for don't care, 1 for EF, 0 for DF */
368
static int select_item(sc_card_t *card, const sc_path_t *path_in, sc_file_t ** file_out, int requiredType)
369
0
{
370
0
  mscfs_t *fs = MUSCLE_FS(card);
371
0
  mscfs_file_t *file_data = NULL;
372
0
  size_t pathlen = path_in->len;
373
0
  int r = 0;
374
0
  int objectIndex;
375
0
  u8* oid;
376
377
0
  r = mscfs_check_cache(fs);
378
0
  if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
379
0
  r = mscfs_loadFileInfo(fs, path_in->value, path_in->len, &file_data, &objectIndex);
380
0
  if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
381
382
  /* Check if its the right type */
383
0
  if(requiredType >= 0 && requiredType != file_data->ef) {
384
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
385
0
  }
386
0
  oid = file_data->objectId.id;
387
  /* Is it a file or directory */
388
0
  if(file_data->ef) {
389
0
    fs->currentPath[0] = oid[0];
390
0
    fs->currentPath[1] = oid[1];
391
0
    fs->currentFile[0] = oid[2];
392
0
    fs->currentFile[1] = oid[3];
393
0
  } else {
394
0
    if(pathlen < 2) {
395
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
396
0
    }
397
0
    fs->currentPath[0] = oid[pathlen - 2];
398
0
    fs->currentPath[1] = oid[pathlen - 1];
399
0
    fs->currentFile[0] = 0;
400
0
    fs->currentFile[1] = 0;
401
0
  }
402
403
0
  fs->currentFileIndex = objectIndex;
404
0
  if(file_out) {
405
0
    sc_file_t *file;
406
0
    file = sc_file_new();
407
0
    file->path = *path_in;
408
0
    file->size = file_data->size;
409
0
    file->id = (oid[2] << 8) | oid[3];
410
0
    if(!file_data->ef) {
411
0
      file->type = SC_FILE_TYPE_DF;
412
0
    } else {
413
0
      file->type = SC_FILE_TYPE_WORKING_EF;
414
0
      file->ef_structure = SC_FILE_EF_TRANSPARENT;
415
0
    }
416
417
    /* Setup ACLS */
418
0
    if(file_data->ef) {
419
0
      muscle_load_file_acls(file, file_data);
420
0
    } else {
421
0
      muscle_load_dir_acls(file, file_data);
422
      /* Setup directory acls... */
423
0
    }
424
425
0
    file->magic = SC_FILE_MAGIC;
426
0
    *file_out = file;
427
0
  }
428
0
  return 0;
429
0
}
430
431
static int muscle_select_file(sc_card_t *card, const sc_path_t *path_in,
432
           sc_file_t **file_out)
433
0
{
434
0
  int r;
435
436
0
  assert(card != NULL && path_in != NULL);
437
438
0
  switch (path_in->type) {
439
0
  case SC_PATH_TYPE_FILE_ID:
440
0
    r = select_item(card, path_in, file_out, 1);
441
0
    break;
442
0
  case SC_PATH_TYPE_DF_NAME:
443
0
    r = select_item(card, path_in, file_out, 0);
444
0
    break;
445
0
  case SC_PATH_TYPE_PATH:
446
0
    r = select_item(card, path_in, file_out, -1);
447
0
    break;
448
0
  default:
449
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
450
0
  }
451
0
  if(r > 0) r = 0;
452
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
453
0
}
454
455
static int _listFile(mscfs_file_t *file, int reset, void *udata)
456
97.1k
{
457
97.1k
  int next = reset ? 0x00 : 0x01;
458
97.1k
  return msc_list_objects( (sc_card_t*)udata, next, file);
459
97.1k
}
460
461
static int muscle_init(sc_card_t *card)
462
419
{
463
419
  muscle_private_t *priv;
464
419
  int r;
465
466
419
  card->name = "MuscleApplet";
467
419
  card->drv_data = malloc(sizeof(muscle_private_t));
468
419
  if(!card->drv_data) {
469
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
470
0
  }
471
419
  memset(card->drv_data, 0, sizeof(muscle_private_t));
472
419
  priv = MUSCLE_DATA(card);
473
419
  priv->verifiedPins = 0;
474
419
  priv->fs = mscfs_new();
475
419
  if(!priv->fs) {
476
0
    free(card->drv_data);
477
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
478
0
  }
479
419
  priv->fs->udata = card;
480
419
  priv->fs->listFile = _listFile;
481
482
419
  card->cla = 0xB0;
483
484
419
  card->flags |= SC_CARD_FLAG_RNG;
485
419
  card->caps |= SC_CARD_CAP_RNG;
486
487
  /* Card type detection */
488
419
  r = _sc_match_atr(card, muscle_atrs, &card->type);
489
419
  if (r < 0) {
490
409
    sc_log(card->ctx, "Failed to match the ATRs");
491
409
  }
492
419
  if(card->type == SC_CARD_TYPE_MUSCLE_ETOKEN_72K) {
493
0
    card->caps |= SC_CARD_CAP_APDU_EXT;
494
0
  }
495
419
  if(card->type == SC_CARD_TYPE_MUSCLE_JCOP241) {
496
10
    card->caps |= SC_CARD_CAP_APDU_EXT;
497
10
  }
498
419
  if (!(card->caps & SC_CARD_CAP_APDU_EXT)) {
499
409
    card->max_recv_size = 255;
500
409
    card->max_send_size = 255;
501
409
  }
502
419
  if(card->type == SC_CARD_TYPE_MUSCLE_JCOP242R2_NO_EXT_APDU) {
503
          /* Tyfone JCOP v242R2 card that doesn't support extended APDUs */
504
0
  }
505
506
507
  /* FIXME: Card type detection */
508
419
  if (1) {
509
419
    unsigned long flags;
510
511
419
    flags = SC_ALGORITHM_RSA_RAW;
512
419
    flags |= SC_ALGORITHM_RSA_HASH_NONE;
513
419
    flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
514
515
419
    _sc_card_add_rsa_alg(card, 1024, flags, 0);
516
419
    _sc_card_add_rsa_alg(card, 2048, flags, 0);
517
419
  }
518
419
  return SC_SUCCESS;
519
419
}
520
521
static int muscle_list_files(sc_card_t *card, u8 *buf, size_t bufLen)
522
419
{
523
419
  muscle_private_t* priv = MUSCLE_DATA(card);
524
419
  mscfs_t *fs = priv->fs;
525
419
  int x, r;
526
419
  int count = 0;
527
528
419
  r = mscfs_check_cache(priv->fs);
529
419
  if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
530
531
34.5k
  for(x = 0; x < fs->cache.size; x++) {
532
34.4k
    u8* oid = fs->cache.array[x].objectId.id;
533
34.4k
    if (bufLen < 2)
534
0
      break;
535
34.4k
    sc_log(card->ctx,
536
34.4k
      "FILE: %02X%02X%02X%02X\n",
537
34.4k
      oid[0],oid[1],oid[2],oid[3]);
538
34.4k
    if(0 == memcmp(fs->currentPath, oid, 2)) {
539
1.24k
      buf[0] = oid[2];
540
1.24k
      buf[1] = oid[3];
541
1.24k
      if(buf[0] == 0x00 && buf[1] == 0x00) continue; /* No directories/null names outside of root */
542
1.11k
      buf += 2;
543
1.11k
      count += 2;
544
1.11k
      bufLen -= 2;
545
1.11k
    }
546
34.4k
  }
547
75
  return count;
548
419
}
549
550
static int muscle_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *cmd,
551
        int *tries_left)
552
0
{
553
0
  muscle_private_t* priv = MUSCLE_DATA(card);
554
0
  const int bufferLength = MSC_MAX_PIN_COMMAND_LENGTH;
555
0
  u8 buffer[MSC_MAX_PIN_COMMAND_LENGTH];
556
0
  switch(cmd->cmd) {
557
0
  case SC_PIN_CMD_VERIFY:
558
0
    switch(cmd->pin_type) {
559
0
    case SC_AC_CHV: {
560
0
      sc_apdu_t apdu;
561
0
      int r;
562
0
      r = msc_verify_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len);
563
0
      if (r < 0)
564
0
        return r;
565
0
      cmd->apdu = &apdu;
566
0
      cmd->pin1.offset = 5;
567
0
      r = iso_ops->pin_cmd(card, cmd, tries_left);
568
0
      if(r >= 0)
569
0
        priv->verifiedPins |= (1 << cmd->pin_reference);
570
0
      return r;
571
0
    }
572
0
    case SC_AC_TERM:
573
0
    case SC_AC_PRO:
574
0
    case SC_AC_AUT:
575
0
    case SC_AC_NONE:
576
0
    default:
577
0
      sc_log(card->ctx,  "Unsupported authentication method\n");
578
0
      return SC_ERROR_NOT_SUPPORTED;
579
0
    }
580
0
  case SC_PIN_CMD_CHANGE:
581
0
    switch(cmd->pin_type) {
582
0
    case SC_AC_CHV: {
583
0
      sc_apdu_t apdu;
584
0
      int r;
585
0
      r = msc_change_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len, cmd->pin2.data, cmd->pin2.len);
586
0
      if (r < 0)
587
0
        return r;
588
0
      cmd->apdu = &apdu;
589
0
      return iso_ops->pin_cmd(card, cmd, tries_left);
590
0
    }
591
0
    case SC_AC_TERM:
592
0
    case SC_AC_PRO:
593
0
    case SC_AC_AUT:
594
0
    case SC_AC_NONE:
595
0
    default:
596
0
      sc_log(card->ctx,  "Unsupported authentication method\n");
597
0
      return SC_ERROR_NOT_SUPPORTED;
598
0
    }
599
0
  case SC_PIN_CMD_UNBLOCK:
600
0
  switch(cmd->pin_type) {
601
0
    case SC_AC_CHV: {
602
0
      sc_apdu_t apdu;
603
0
      int r;
604
0
      r = msc_unblock_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len);
605
0
      if (r < 0)
606
0
        return r;
607
0
      cmd->apdu = &apdu;
608
0
      return iso_ops->pin_cmd(card, cmd, tries_left);
609
0
    }
610
0
    case SC_AC_TERM:
611
0
    case SC_AC_PRO:
612
0
    case SC_AC_AUT:
613
0
    case SC_AC_NONE:
614
0
    default:
615
0
      sc_log(card->ctx,  "Unsupported authentication method\n");
616
0
      return SC_ERROR_NOT_SUPPORTED;
617
0
    }
618
0
  default:
619
0
    sc_log(card->ctx,  "Unsupported command\n");
620
0
    return SC_ERROR_NOT_SUPPORTED;
621
622
0
  }
623
624
0
}
625
626
static int muscle_card_extract_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info)
627
0
{
628
  /* CURRENTLY DONT SUPPORT EXTRACTING PRIVATE KEYS... */
629
0
  switch(info->keyType) {
630
0
  case 1: /* RSA */
631
0
    return msc_extract_rsa_public_key(card,
632
0
      info->keyLocation,
633
0
      &info->modLength,
634
0
      &info->modValue,
635
0
      &info->expLength,
636
0
      &info->expValue);
637
0
  default:
638
0
    return SC_ERROR_NOT_SUPPORTED;
639
0
  }
640
0
}
641
642
static int muscle_card_import_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info)
643
0
{
644
  /* CURRENTLY DONT SUPPORT EXTRACTING PRIVATE KEYS... */
645
0
  switch(info->keyType) {
646
0
  case 0x02: /* RSA_PRIVATE */
647
0
  case 0x03: /* RSA_PRIVATE_CRT */
648
0
    return msc_import_key(card,
649
0
      info->keyLocation,
650
0
      info);
651
0
  default:
652
0
    return SC_ERROR_NOT_SUPPORTED;
653
0
  }
654
0
}
655
656
static int muscle_card_generate_key(sc_card_t *card, sc_cardctl_muscle_gen_key_info_t *info)
657
0
{
658
0
  return msc_generate_keypair(card,
659
0
    info->privateKeyLocation,
660
0
    info->publicKeyLocation,
661
0
    info->keyType,
662
0
    info->keySize,
663
0
    0);
664
0
}
665
666
static int muscle_card_verified_pins(sc_card_t *card, sc_cardctl_muscle_verified_pins_info_t *info)
667
0
{
668
0
  muscle_private_t* priv = MUSCLE_DATA(card);
669
0
  info->verifiedPins = priv->verifiedPins;
670
0
  return 0;
671
0
}
672
static int muscle_card_ctl(sc_card_t *card, unsigned long request, void *data)
673
0
{
674
0
  switch(request) {
675
0
  case SC_CARDCTL_MUSCLE_GENERATE_KEY:
676
0
    return muscle_card_generate_key(card, (sc_cardctl_muscle_gen_key_info_t*) data);
677
0
  case SC_CARDCTL_MUSCLE_EXTRACT_KEY:
678
0
    return muscle_card_extract_key(card, (sc_cardctl_muscle_key_info_t*) data);
679
0
  case SC_CARDCTL_MUSCLE_IMPORT_KEY:
680
0
    return muscle_card_import_key(card, (sc_cardctl_muscle_key_info_t*) data);
681
0
  case SC_CARDCTL_MUSCLE_VERIFIED_PINS:
682
0
    return muscle_card_verified_pins(card, (sc_cardctl_muscle_verified_pins_info_t*) data);
683
0
  default:
684
0
    return SC_ERROR_NOT_SUPPORTED; /* Unsupported.. whatever it is */
685
0
  }
686
0
}
687
688
static int muscle_set_security_env(sc_card_t *card,
689
         const sc_security_env_t *env,
690
         int se_num)
691
0
{
692
0
  muscle_private_t* priv = MUSCLE_DATA(card);
693
694
0
  if (env->operation != SC_SEC_OPERATION_SIGN &&
695
0
      env->operation != SC_SEC_OPERATION_DECIPHER) {
696
0
    sc_log(card->ctx,  "Invalid crypto operation supplied.\n");
697
0
    return SC_ERROR_NOT_SUPPORTED;
698
0
  }
699
0
  if (env->algorithm != SC_ALGORITHM_RSA) {
700
0
    sc_log(card->ctx,  "Invalid crypto algorithm supplied.\n");
701
0
    return SC_ERROR_NOT_SUPPORTED;
702
0
  }
703
  /* ADJUST FOR PKCS1 padding support for decryption only */
704
0
  if ((env->algorithm_flags & SC_ALGORITHM_RSA_PADS) ||
705
0
      (env->algorithm_flags & SC_ALGORITHM_RSA_HASHES)) {
706
0
    sc_log(card->ctx,  "Card supports only raw RSA.\n");
707
0
    return SC_ERROR_NOT_SUPPORTED;
708
0
  }
709
0
  if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
710
0
    if (env->key_ref_len != 1 ||
711
0
        (env->key_ref[0] > 0x0F)) {
712
0
      sc_log(card->ctx,  "Invalid key reference supplied.\n");
713
0
      return SC_ERROR_NOT_SUPPORTED;
714
0
    }
715
0
    priv->rsa_key_ref = env->key_ref[0];
716
0
  }
717
0
  if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
718
0
    sc_log(card->ctx,  "Algorithm reference not supported.\n");
719
0
    return SC_ERROR_NOT_SUPPORTED;
720
0
  }
721
  /* if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT)
722
    if (memcmp(env->file_ref.value, "\x00\x12", 2) != 0) {
723
      sc_log(card->ctx,  "File reference is not 0012.\n");
724
      return SC_ERROR_NOT_SUPPORTED;
725
    } */
726
0
  priv->env = *env;
727
0
  return 0;
728
0
}
729
730
static int muscle_restore_security_env(sc_card_t *card, int se_num)
731
0
{
732
0
  muscle_private_t* priv = MUSCLE_DATA(card);
733
0
  memset(&priv->env, 0, sizeof(priv->env));
734
0
  return 0;
735
0
}
736
737
738
static int muscle_decipher(sc_card_t * card,
739
       const u8 * crgram, size_t crgram_len, u8 * out,
740
       size_t out_len)
741
0
{
742
0
  muscle_private_t* priv = MUSCLE_DATA(card);
743
744
0
  u8 key_id;
745
0
  int r;
746
747
  /* sanity check */
748
0
  if (priv->env.operation != SC_SEC_OPERATION_DECIPHER)
749
0
    return SC_ERROR_INVALID_ARGUMENTS;
750
751
0
  key_id = priv->rsa_key_ref * 2; /* Private key */
752
753
0
  if (out_len < crgram_len) {
754
0
    sc_log(card->ctx,  "Output buffer too small");
755
0
    return SC_ERROR_BUFFER_TOO_SMALL;
756
0
  }
757
758
0
  r = msc_compute_crypt(card,
759
0
    key_id,
760
0
    0x00, /* RSA NO PADDING */
761
0
    0x04, /* decrypt */
762
0
    crgram,
763
0
    out,
764
0
    crgram_len,
765
0
    out_len);
766
0
  LOG_TEST_RET(card->ctx, r, "Card signature failed");
767
0
  return r;
768
0
}
769
770
static int muscle_compute_signature(sc_card_t *card, const u8 *data,
771
    size_t data_len, u8 * out, size_t outlen)
772
0
{
773
0
  muscle_private_t* priv = MUSCLE_DATA(card);
774
0
  u8 key_id;
775
0
  int r;
776
777
0
  key_id = priv->rsa_key_ref * 2; /* Private key */
778
779
0
  if (outlen < data_len) {
780
0
    sc_log(card->ctx,  "Output buffer too small");
781
0
    return SC_ERROR_BUFFER_TOO_SMALL;
782
0
  }
783
784
0
  r = msc_compute_crypt(card,
785
0
    key_id,
786
0
    0x00, /* RSA NO PADDING */
787
0
    0x04, /* -- decrypt raw... will do what we need since signing isn't yet supported */
788
0
    data,
789
0
    out,
790
0
    data_len,
791
0
    outlen);
792
0
  LOG_TEST_RET(card->ctx, r, "Card signature failed");
793
0
  return r;
794
0
}
795
796
static int muscle_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
797
334
{
798
334
  if (len == 0)
799
0
    return SC_SUCCESS;
800
334
  else {
801
334
    LOG_TEST_RET(card->ctx,
802
18
        msc_get_challenge(card, len, 0, NULL, rnd),
803
18
        "GET CHALLENGE cmd failed");
804
18
    return (int) len;
805
334
  }
806
334
}
807
808
97.8k
static int muscle_check_sw(sc_card_t * card, unsigned int sw1, unsigned int sw2) {
809
97.8k
  if(sw1 == 0x9C) {
810
157
    switch(sw2) {
811
14
      case 0x01: /* SW_NO_MEMORY_LEFT */
812
14
        return SC_ERROR_NOT_ENOUGH_MEMORY;
813
12
      case 0x02: /* SW_AUTH_FAILED */
814
12
        return SC_ERROR_PIN_CODE_INCORRECT;
815
10
      case 0x03: /* SW_OPERATION_NOT_ALLOWED */
816
10
        return SC_ERROR_NOT_ALLOWED;
817
10
      case 0x05: /* SW_UNSUPPORTED_FEATURE */
818
10
        return SC_ERROR_NO_CARD_SUPPORT;
819
10
      case 0x06: /* SW_UNAUTHORIZED */
820
10
        return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
821
12
      case 0x07: /* SW_OBJECT_NOT_FOUND */
822
12
        return SC_ERROR_FILE_NOT_FOUND;
823
10
      case 0x08: /* SW_OBJECT_EXISTS */
824
10
        return SC_ERROR_FILE_ALREADY_EXISTS;
825
11
      case 0x09: /* SW_INCORRECT_ALG */
826
11
        return SC_ERROR_INCORRECT_PARAMETERS;
827
10
      case 0x0B: /* SW_SIGNATURE_INVALID */
828
10
        return SC_ERROR_CARD_CMD_FAILED;
829
11
      case 0x0C: /* SW_IDENTITY_BLOCKED */
830
11
        return SC_ERROR_AUTH_METHOD_BLOCKED;
831
12
      case 0x0F: /* SW_INVALID_PARAMETER */
832
22
      case 0x10: /* SW_INCORRECT_P1 */
833
33
      case 0x11: /* SW_INCORRECT_P2 */
834
33
        return SC_ERROR_INCORRECT_PARAMETERS;
835
157
    }
836
157
  }
837
97.7k
  return iso_ops->check_sw(card, sw1, sw2);
838
97.8k
}
839
840
static int muscle_card_reader_lock_obtained(sc_card_t *card, int was_reset)
841
104k
{
842
104k
  int r = SC_SUCCESS;
843
844
104k
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
845
846
104k
  if (was_reset > 0) {
847
0
    if (msc_select_applet(card, muscleAppletId, sizeof muscleAppletId) != 1) {
848
0
      r = SC_ERROR_INVALID_CARD;
849
0
    }
850
0
  }
851
852
104k
  LOG_FUNC_RETURN(card->ctx, r);
853
104k
}
854
855
static int muscle_logout(sc_card_t *card)
856
0
{
857
0
  int r = SC_ERROR_NOT_SUPPORTED;
858
859
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
860
861
0
  if (msc_select_applet(card, muscleAppletId, sizeof muscleAppletId) == 1) {
862
0
    r = SC_SUCCESS;
863
0
  }
864
865
0
  LOG_FUNC_RETURN(card->ctx, r);
866
0
}
867
868
869
static struct sc_card_driver * sc_get_driver(void)
870
9.35k
{
871
9.35k
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
872
9.35k
  if (iso_ops == NULL)
873
1
    iso_ops = iso_drv->ops;
874
875
9.35k
  muscle_ops = *iso_drv->ops;
876
9.35k
  muscle_ops.check_sw = muscle_check_sw;
877
9.35k
  muscle_ops.pin_cmd = muscle_pin_cmd;
878
9.35k
  muscle_ops.match_card = muscle_match_card;
879
9.35k
  muscle_ops.init = muscle_init;
880
9.35k
  muscle_ops.finish = muscle_finish;
881
882
9.35k
  muscle_ops.get_challenge = muscle_get_challenge;
883
884
9.35k
  muscle_ops.set_security_env = muscle_set_security_env;
885
9.35k
  muscle_ops.restore_security_env = muscle_restore_security_env;
886
9.35k
  muscle_ops.compute_signature = muscle_compute_signature;
887
9.35k
  muscle_ops.decipher = muscle_decipher;
888
9.35k
  muscle_ops.card_ctl = muscle_card_ctl;
889
9.35k
  muscle_ops.read_binary = muscle_read_binary;
890
9.35k
  muscle_ops.update_binary = muscle_update_binary;
891
9.35k
  muscle_ops.create_file = muscle_create_file;
892
9.35k
  muscle_ops.select_file = muscle_select_file;
893
9.35k
  muscle_ops.delete_file = muscle_delete_file;
894
9.35k
  muscle_ops.list_files = muscle_list_files;
895
9.35k
  muscle_ops.card_reader_lock_obtained = muscle_card_reader_lock_obtained;
896
9.35k
  muscle_ops.logout = muscle_logout;
897
898
9.35k
  return &muscle_drv;
899
9.35k
}
900
901
struct sc_card_driver * sc_get_muscle_driver(void)
902
9.35k
{
903
9.35k
  return sc_get_driver();
904
9.35k
}