Coverage Report

Created: 2025-07-18 06:10

/src/opensc/src/pkcs15init/pkcs15-oberthur.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Oberthur specific operation for PKCS #15 initialization
3
 *
4
 * Copyright (C) 2002  Juha Yrjölä <juha.yrjola@iki.fi>
5
 * Copyright (C) 2009  Viktor Tarasov <viktor.tarasov@opentrust.com>,
6
 *                     OpenTrust <www.opentrust.com>
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22
23
#include "pkcs15-oberthur.h"
24
#include <sys/types.h>
25
#include <ctype.h>
26
27
#include "libopensc/opensc.h"
28
#include "libopensc/cardctl.h"
29
#include "libopensc/log.h"
30
#include "profile.h"
31
#include "pkcs15-init.h"
32
33
1.13k
#define COSM_TITLE "OberthurAWP"
34
35
#define TLV_TYPE_V  0
36
#define TLV_TYPE_LV 1
37
#define TLV_TYPE_TLV  2
38
39
/* Should be greater then SC_PKCS15_TYPE_CLASS_MASK */
40
220
#define SC_DEVICE_SPECIFIC_TYPE  0x1000
41
42
220
#define COSM_TYPE_PRKEY_RSA (SC_DEVICE_SPECIFIC_TYPE | SC_PKCS15_TYPE_PRKEY_RSA)
43
0
#define COSM_TYPE_PUBKEY_RSA (SC_DEVICE_SPECIFIC_TYPE | SC_PKCS15_TYPE_PUBKEY_RSA)
44
45
0
#define COSM_TOKEN_FLAG_PRN_GENERATION    0x01
46
0
#define COSM_TOKEN_FLAG_LOGIN_REQUIRED    0x04
47
0
#define COSM_TOKEN_FLAG_USER_PIN_INITIALIZED  0x08
48
0
#define COSM_TOKEN_FLAG_TOKEN_INITIALIZED 0x0400
49
50
static int cosm_create_reference_data(struct sc_profile *, struct sc_pkcs15_card *,
51
    struct sc_pkcs15_auth_info *, const unsigned char *, size_t,
52
    const unsigned char *, size_t);
53
static int cosm_update_pin(struct sc_profile *, struct sc_pkcs15_card *,
54
    struct sc_pkcs15_auth_info *, const unsigned char *, size_t,
55
    const unsigned char *, size_t);
56
57
static int
58
cosm_write_tokeninfo (struct sc_pkcs15_card *p15card, struct sc_profile *profile,
59
    char *label, unsigned flags)
60
0
{
61
0
  struct sc_context *ctx;
62
0
  struct sc_file *file = NULL;
63
0
  int rv;
64
0
  size_t sz;
65
0
  char *buffer = NULL;
66
67
0
  if (!p15card || !p15card->card || !profile)
68
0
    return SC_ERROR_INVALID_ARGUMENTS;
69
70
0
  ctx = p15card->card->ctx;
71
72
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
73
0
  if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file)) {
74
0
    rv = SC_ERROR_INCONSISTENT_PROFILE;
75
0
    SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Cannot find "COSM_TITLE"-token-info");
76
0
  }
77
78
0
  if (file->size < 16) {
79
0
    rv = SC_ERROR_INCONSISTENT_PROFILE;
80
0
    SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Insufficient size of the "COSM_TITLE"-token-info file");
81
0
  }
82
83
0
  buffer = calloc(1, file->size);
84
0
  if (!buffer) {
85
0
    rv = SC_ERROR_OUT_OF_MEMORY;
86
0
    SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Allocation error in cosm_write_tokeninfo()");
87
0
  }
88
89
0
  if (label)
90
0
    strncpy(buffer, label, file->size - 4);
91
0
  else if (p15card->tokeninfo->label)
92
0
    snprintf(buffer, file->size - 4, "%s", p15card->tokeninfo->label);
93
0
  else if (profile->p15_spec && profile->p15_spec->tokeninfo->label)
94
0
    snprintf(buffer, file->size - 4, "%s", profile->p15_spec->tokeninfo->label);
95
0
  else
96
0
    snprintf(buffer, file->size - 4, "OpenSC-Token");
97
98
0
  sz = strlen(buffer);
99
0
  if (sz < file->size - 4)
100
0
    memset(buffer + sz, ' ', file->size - sz);
101
102
0
  sc_log(ctx,  "cosm_write_tokeninfo() token label '%s'; oberthur flags 0x%X", buffer, flags);
103
104
0
  memset(buffer + file->size - 4, 0, 4);
105
0
  *(buffer + file->size - 1) = flags & 0xFF;
106
0
  *(buffer + file->size - 2) = (flags >> 8) & 0xFF;
107
108
0
  rv = sc_pkcs15init_update_file(profile, p15card, file, buffer, file->size);
109
0
  if (rv > 0)
110
0
    rv = 0;
111
112
0
err:
113
0
  sc_file_free(file);
114
0
  free(buffer);
115
0
  LOG_FUNC_RETURN(ctx, rv);
116
0
}
117
118
119
int
120
cosm_delete_file(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
121
    struct sc_file *df)
122
545
{
123
545
  struct sc_context *ctx = p15card->card->ctx;
124
545
  struct sc_path  path;
125
545
  struct sc_file  *parent;
126
545
  int rv = 0;
127
128
545
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
129
545
  sc_log(ctx,  "id %04X", df->id);
130
545
  if (df->type==SC_FILE_TYPE_DF)   {
131
477
    rv = sc_pkcs15init_authenticate(profile, p15card, df, SC_AC_OP_DELETE);
132
477
    LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE");
133
477
  }
134
135
  /* Select the parent DF */
136
166
  path = df->path;
137
166
  if (path.len < 2) {
138
6
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
139
6
  }
140
160
  path.len -= 2;
141
142
160
  rv = sc_select_file(p15card->card, &path, &parent);
143
160
  LOG_TEST_RET(ctx, rv, "Cannot select parent");
144
145
70
  rv = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_DELETE);
146
70
  sc_file_free(parent);
147
70
  LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE");
148
149
69
  memset(&path, 0, sizeof(path));
150
69
  path.type = SC_PATH_TYPE_FILE_ID;
151
69
  path.value[0] = df->id >> 8;
152
69
  path.value[1] = df->id & 0xFF;
153
69
  path.len = 2;
154
155
69
  rv = sc_delete_file(p15card->card, &path);
156
157
69
  LOG_FUNC_RETURN(ctx, rv);
158
69
}
159
160
161
/*
162
 * Erase the card
163
 */
164
static int
165
cosm_erase_card(struct sc_profile *profile, struct sc_pkcs15_card *p15card)
166
483
{
167
483
  struct sc_context *ctx = p15card->card->ctx;
168
483
  struct sc_file  *df = profile->df_info->file, *dir;
169
483
  int rv;
170
171
483
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
172
  /* Delete EF(DIR). This may not be very nice
173
   * against other applications that use this file, but
174
   * extremely useful for testing :)
175
   * Note we need to delete if before the DF because we create
176
   * it *after* the DF.
177
   * */
178
483
  if (sc_profile_get_file(profile, "DIR", &dir) >= 0) {
179
15
    sc_log(ctx,  "erase file dir %04X",dir->id);
180
15
    rv = cosm_delete_file(p15card, profile, dir);
181
15
    sc_file_free(dir);
182
15
    if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND)
183
7
      goto done;
184
15
  }
185
186
476
  sc_log(ctx,  "erase file ddf %04X",df->id);
187
476
  rv = cosm_delete_file(p15card, profile, df);
188
476
  if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND)
189
466
    goto done;
190
191
10
  if (sc_profile_get_file(profile, "private-DF", &dir) >= 0) {
192
4
    sc_log(ctx,  "erase file dir %04X",dir->id);
193
4
    rv = cosm_delete_file(p15card, profile, dir);
194
4
    sc_file_free(dir);
195
4
    if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND)
196
2
      goto done;
197
4
  }
198
199
8
  if (sc_profile_get_file(profile, "public-DF", &dir) >= 0) {
200
0
    sc_log(ctx,  "erase file dir %04X",dir->id);
201
0
    rv = cosm_delete_file(p15card, profile, dir);
202
0
    sc_file_free(dir);
203
0
    if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND)
204
0
      goto done;
205
0
  }
206
207
8
  rv = sc_profile_get_file(profile, COSM_TITLE"-AppDF", &dir);
208
8
  if (!rv) {
209
1
    sc_log(ctx,  "delete %s; r %i", COSM_TITLE"-AppDF", rv);
210
1
    rv = cosm_delete_file(p15card, profile, dir);
211
1
    sc_file_free(dir);
212
1
  }
213
214
8
  sc_free_apps(p15card->card);
215
483
done:
216
483
  if (rv == SC_ERROR_FILE_NOT_FOUND)
217
7
    rv = 0;
218
219
483
  LOG_FUNC_RETURN(ctx, rv);
220
483
}
221
222
223
static int
224
cosm_create_dir(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
225
    struct sc_file *df)
226
17
{
227
17
  struct sc_context *ctx = p15card->card->ctx;
228
17
  struct sc_file *file = NULL;
229
17
  size_t ii;
230
17
  int rv;
231
17
  static const char *create_dfs[] = {
232
17
    COSM_TITLE"-AppDF",
233
17
    "private-DF",
234
17
    "public-DF",
235
17
    COSM_TITLE"-token-info",
236
17
    COSM_TITLE"-puk-file",
237
17
    COSM_TITLE"-container-list",
238
17
    COSM_TITLE"-public-list",
239
17
    COSM_TITLE"-private-list",
240
17
    NULL
241
17
  };
242
243
17
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
244
245
  /* Oberthur AWP file system is expected.*/
246
  /* Create private objects DF */
247
19
  for (ii = 0; create_dfs[ii]; ii++)   {
248
19
    if (sc_profile_get_file(profile, create_dfs[ii], &file))   {
249
2
      sc_log(ctx,  "Inconsistent profile: cannot find %s", create_dfs[ii]);
250
2
      LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Profile do not contains Oberthur AWP file");
251
2
    }
252
253
17
    rv = sc_pkcs15init_create_file(profile, p15card, file);
254
17
    sc_file_free(file);
255
17
    if (rv != SC_ERROR_FILE_ALREADY_EXISTS)
256
17
      LOG_TEST_RET(ctx, rv, "Failed to create Oberthur AWP file");
257
17
  }
258
259
0
  rv = cosm_write_tokeninfo(p15card, profile, NULL,
260
0
    COSM_TOKEN_FLAG_TOKEN_INITIALIZED | COSM_TOKEN_FLAG_PRN_GENERATION);
261
262
0
  LOG_FUNC_RETURN(ctx, rv);
263
0
}
264
265
266
static int
267
cosm_create_reference_data(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
268
    struct sc_pkcs15_auth_info *ainfo,
269
    const unsigned char *pin, size_t pin_len,
270
    const unsigned char *puk, size_t puk_len )
271
7
{
272
7
  struct sc_context *ctx = p15card->card->ctx;
273
7
  struct sc_card *card = p15card->card;
274
7
  struct sc_pkcs15_auth_info profile_auth_pin = {0}, profile_auth_puk = {0};
275
7
  struct sc_cardctl_oberthur_createpin_info args;
276
7
  int rv;
277
7
  unsigned char oberthur_puk[16] = {
278
7
    0x6F, 0x47, 0xD9, 0x88, 0x4B, 0x6F, 0x9D, 0xC5,
279
7
    0x78, 0x33, 0x79, 0x8F, 0x5B, 0x7D, 0xE1, 0xA5
280
7
  };
281
282
7
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
283
7
  sc_log(ctx,
284
7
     "pin lens %"SC_FORMAT_LEN_SIZE_T"u/%"SC_FORMAT_LEN_SIZE_T"u",
285
7
     pin_len, puk_len);
286
7
  if (!pin || pin_len>0x40)
287
0
    return SC_ERROR_INVALID_ARGUMENTS;
288
7
  if (puk && !puk_len)
289
0
    return SC_ERROR_INVALID_ARGUMENTS;
290
7
  if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
291
0
    return SC_ERROR_OBJECT_NOT_VALID;
292
293
7
  rv = sc_select_file(card, &ainfo->path, NULL);
294
7
  LOG_TEST_RET(ctx, rv, "Cannot select file");
295
296
4
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &profile_auth_pin);
297
4
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &profile_auth_puk);
298
299
4
  memset(&args, 0, sizeof(args));
300
4
  args.type = SC_AC_CHV;
301
4
  args.ref = ainfo->attrs.pin.reference;
302
4
  args.pin = pin;
303
4
  args.pin_len = pin_len;
304
305
4
  if (!(ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN))   {
306
4
    args.pin_tries = profile_auth_pin.tries_left;
307
4
    if (profile_auth_puk.tries_left > 0)   {
308
4
      args.puk = oberthur_puk;
309
4
      args.puk_len = sizeof(oberthur_puk);
310
4
      args.puk_tries = 5;
311
4
    }
312
4
  }
313
0
  else   {
314
0
    args.pin_tries = profile_auth_puk.tries_left;
315
0
  }
316
317
4
  rv = sc_card_ctl(card, SC_CARDCTL_OBERTHUR_CREATE_PIN, &args);
318
4
  LOG_TEST_RET(ctx, rv, "'CREATE_PIN' card specific command failed");
319
320
1
  if (!(ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)
321
1
      && (profile_auth_puk.tries_left > 0))   {
322
1
          struct sc_file *file = NULL;
323
324
1
    if (sc_profile_get_file(profile, COSM_TITLE"-puk-file", &file))
325
1
      LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Cannot find PUKFILE");
326
327
0
    rv = sc_pkcs15init_update_file(profile, p15card, file, oberthur_puk, sizeof(oberthur_puk));
328
0
    LOG_TEST_RET(ctx, rv, "Failed to update pukfile");
329
330
0
    sc_file_free(file);
331
0
  }
332
333
0
  LOG_FUNC_RETURN(ctx, rv);
334
0
}
335
336
337
/*
338
 * Update PIN
339
 */
340
static int
341
cosm_update_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
342
    struct sc_pkcs15_auth_info *ainfo, const unsigned char *pin, size_t pin_len,
343
    const unsigned char *puk, size_t puk_len )
344
8
{
345
8
  struct sc_context *ctx = p15card->card->ctx;
346
8
  int rv;
347
348
8
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
349
8
  if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
350
0
    return SC_ERROR_OBJECT_NOT_VALID;
351
352
8
  sc_log(ctx,  "ref %i; flags 0x%X", ainfo->attrs.pin.reference, ainfo->attrs.pin.flags);
353
354
8
  if (ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)   {
355
1
    if (ainfo->attrs.pin.reference != 4)
356
1
      LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "cosm_update_pin() invalid SOPIN reference");
357
1
    sc_log(ctx,  "Update SOPIN ignored");
358
1
    rv = SC_SUCCESS;
359
1
  }
360
7
  else   {
361
7
    rv = cosm_create_reference_data(profile, p15card, ainfo, pin, pin_len, puk, puk_len);
362
7
    LOG_TEST_RET(ctx, rv, "cosm_update_pin() failed to change PIN");
363
364
0
    rv = cosm_write_tokeninfo(p15card, profile, NULL,
365
0
      COSM_TOKEN_FLAG_TOKEN_INITIALIZED
366
0
      | COSM_TOKEN_FLAG_PRN_GENERATION
367
0
      | COSM_TOKEN_FLAG_LOGIN_REQUIRED
368
0
      | COSM_TOKEN_FLAG_USER_PIN_INITIALIZED);
369
0
    LOG_TEST_RET(ctx, rv, "cosm_update_pin() failed to update tokeninfo");
370
0
  }
371
372
1
  LOG_FUNC_RETURN(ctx, rv);
373
1
}
374
375
376
static int
377
cosm_select_pin_reference(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
378
    struct sc_pkcs15_auth_info *auth_info)
379
525
{
380
525
  struct sc_context *ctx = p15card->card->ctx;
381
525
  struct sc_pkcs15_pin_attributes *pin_attrs;
382
525
  struct sc_file *pinfile;
383
384
525
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
385
525
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
386
0
    return SC_ERROR_OBJECT_NOT_VALID;
387
388
525
  pin_attrs = &auth_info->attrs.pin;
389
390
525
  sc_log(ctx,  "ref %i; flags %X", pin_attrs->reference, pin_attrs->flags);
391
525
  if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pinfile) < 0) {
392
478
    sc_log(ctx,  "Profile doesn't define \"%s\"", COSM_TITLE "-AppDF");
393
478
    return SC_ERROR_INCONSISTENT_PROFILE;
394
478
  }
395
396
47
  if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL)
397
35
    auth_info->path = pinfile->path;
398
399
47
  sc_file_free(pinfile);
400
401
47
  if (pin_attrs->reference <= 0)   {
402
36
    if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
403
4
      pin_attrs->reference = 4;
404
32
    else if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)
405
6
      pin_attrs->reference = 4;
406
26
    else
407
26
      pin_attrs->reference = 1;
408
409
36
    if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL)
410
25
      pin_attrs->reference |= 0x80;
411
36
  }
412
413
47
  LOG_FUNC_RETURN(ctx, SC_SUCCESS);
414
47
}
415
416
417
/*
418
 * Store a PIN
419
 */
420
static int
421
cosm_create_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
422
    struct sc_file *df, struct sc_pkcs15_object *pin_obj,
423
    const unsigned char *pin, size_t pin_len,
424
    const unsigned char *puk, size_t puk_len)
425
17
{
426
17
  struct sc_context *ctx = p15card->card->ctx;
427
17
  struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data;
428
17
  struct sc_pkcs15_pin_attributes *pin_attrs;
429
17
  struct sc_file *pin_file;
430
17
  int rv = 0;
431
432
17
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
433
17
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
434
0
    return SC_ERROR_OBJECT_NOT_VALID;
435
436
17
  pin_attrs = &auth_info->attrs.pin;
437
438
17
  sc_log(ctx,  "create '%.*s'; ref 0x%X; flags %X", (int) sizeof pin_obj->label, pin_obj->label, pin_attrs->reference, pin_attrs->flags);
439
17
  if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pin_file) < 0)
440
17
    LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "\""COSM_TITLE"-AppDF\" not defined");
441
442
17
  if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL)
443
10
    auth_info->path = pin_file->path;
444
445
17
  sc_file_free(pin_file);
446
447
17
  if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN)   {
448
3
    if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)   {
449
1
      LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "SOPIN unblocking is not supported");
450
1
    }
451
2
    else   {
452
2
      if (pin_attrs->reference != 4)
453
2
        LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid SOPIN reference");
454
2
    }
455
3
  }
456
14
  else {
457
14
    if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)   {
458
4
      if (pin_attrs->reference != 0x84)
459
4
        LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PUK reference");
460
4
    }
461
10
    else   {
462
10
      if (pin_attrs->reference != 0x81)
463
10
        LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PIN reference");
464
10
    }
465
14
  }
466
467
8
  if (pin && pin_len)   {
468
8
    rv = cosm_update_pin(profile, p15card, auth_info, pin, pin_len,  puk, puk_len);
469
8
    LOG_TEST_RET(ctx, rv, "Update PIN failed");
470
8
  }
471
472
1
  LOG_FUNC_RETURN(ctx, rv);
473
1
}
474
475
476
/*
477
 * Allocate a file
478
 */
479
static int
480
cosm_new_file(struct sc_profile *profile, struct sc_card *card,
481
    unsigned int type, unsigned int num, struct sc_file **out)
482
220
{
483
220
  struct sc_file  *file;
484
220
  const char *_template = NULL, *desc = NULL;
485
220
  unsigned int structure = 0xFFFFFFFF;
486
487
220
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
488
220
  sc_log(card->ctx,  "cosm_new_file() type %X; num %i",type, num);
489
220
  while (1) {
490
220
    switch (type) {
491
220
    case SC_PKCS15_TYPE_PRKEY_RSA:
492
220
    case COSM_TYPE_PRKEY_RSA:
493
220
      desc = "RSA private key";
494
220
      _template = "template-private-key";
495
220
      structure = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT;
496
220
      break;
497
0
    case SC_PKCS15_TYPE_PUBKEY_RSA:
498
0
    case COSM_TYPE_PUBKEY_RSA:
499
0
      desc = "RSA public key";
500
0
      _template = "template-public-key";
501
0
      structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
502
0
      break;
503
0
    case SC_PKCS15_TYPE_CERT:
504
0
      desc = "certificate";
505
0
      _template = "template-certificate";
506
0
      break;
507
0
    case SC_PKCS15_TYPE_DATA_OBJECT:
508
0
      desc = "data object";
509
0
      _template = "template-public-data";
510
0
      break;
511
220
    }
512
220
    if (_template)
513
220
      break;
514
    /* If this is a specific type such as
515
     * SC_PKCS15_TYPE_CERT_FOOBAR, fall back to
516
     * the generic class (SC_PKCS15_TYPE_CERT)
517
     */
518
0
    if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) {
519
0
      sc_log(card->ctx,  "File type %X not supported by card driver",
520
0
        type);
521
0
      return SC_ERROR_INVALID_ARGUMENTS;
522
0
    }
523
0
    type &= SC_PKCS15_TYPE_CLASS_MASK;
524
0
  }
525
526
220
  sc_log(card->ctx,  "cosm_new_file() template %s; num %i",_template, num);
527
220
  if (sc_profile_get_file(profile, _template, &file) < 0) {
528
127
    sc_log(card->ctx,  "Profile doesn't define %s template '%s'",
529
127
        desc, _template);
530
127
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
531
127
  }
532
533
93
  file->id |= (num & 0xFF);
534
93
  if (file->path.len) {
535
92
    file->path.value[file->path.len - 1] |= (num & 0xFF);
536
92
  }
537
93
  if (file->type == SC_FILE_TYPE_INTERNAL_EF)   {
538
7
    file->ef_structure = structure;
539
7
  }
540
541
93
  sc_log(card->ctx,
542
93
     "cosm_new_file() file size %"SC_FORMAT_LEN_SIZE_T"u; ef type %i/%i; id %04X",
543
93
     file->size, file->type, file->ef_structure, file->id);
544
93
  *out = file;
545
546
93
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
547
93
}
548
549
550
static int
551
cosm_get_temporary_public_key_file(struct sc_card *card,
552
    struct sc_file *prvkey_file, struct sc_file **pubkey_file)
553
25
{
554
25
  struct sc_context *ctx = card->ctx;
555
25
  const struct sc_acl_entry *entry = NULL;
556
25
  struct sc_file *file = NULL;
557
25
  int rv;
558
559
25
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
560
25
  if (!pubkey_file || !prvkey_file)
561
25
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
562
563
25
  file = sc_file_new();
564
25
  if (!file)
565
25
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
566
567
25
  file->status = SC_FILE_STATUS_ACTIVATED;
568
25
        file->type = SC_FILE_TYPE_INTERNAL_EF;
569
25
  file->ef_structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
570
25
  file->id = 0x1012;
571
25
  memcpy(&file->path, &prvkey_file->path, sizeof(file->path));
572
25
        file->path.value[file->path.len - 2] = 0x10;
573
25
  file->path.value[file->path.len - 1] = 0x12;
574
25
  file->size = prvkey_file->size;
575
576
25
  entry = sc_file_get_acl_entry(prvkey_file, SC_AC_OP_UPDATE);
577
25
  if (!entry) {
578
2
    sc_file_free(file);
579
2
    LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "Failed to find ACL entry");
580
2
  }
581
23
  rv = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, entry->method, entry->key_ref);
582
23
  if (!rv)
583
23
    rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_ENCRYPT, SC_AC_NONE, 0);
584
23
  if (!rv)
585
23
    rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_VERIFY_SIGNATURE, SC_AC_NONE, 0);
586
23
  if (!rv)
587
23
    rv = sc_file_add_acl_entry(file, SC_AC_OP_EXTERNAL_AUTHENTICATE, SC_AC_NONE, 0);
588
23
  if (rv < 0)
589
0
    sc_file_free(file);
590
23
  LOG_TEST_RET(ctx, rv, "Failed to add ACL entry to the temporary public key file");
591
592
23
  *pubkey_file = file;
593
594
23
  LOG_FUNC_RETURN(card->ctx, rv);
595
23
}
596
597
598
static int
599
cosm_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
600
    struct sc_pkcs15_object *object,
601
    struct sc_pkcs15_pubkey *pubkey)
602
35
{
603
35
  struct sc_context *ctx = p15card->card->ctx;
604
35
  struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
605
35
  struct sc_cardctl_oberthur_genkey_info args;
606
35
  struct sc_file *prkf = NULL, *tmpf = NULL;
607
35
  struct sc_path path;
608
35
  int rv = 0;
609
610
35
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
611
612
35
  if (object->type != SC_PKCS15_TYPE_PRKEY_RSA)
613
35
    LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: RSA only supported");
614
615
35
  path = key_info->path;
616
35
  path.len -= 2;
617
618
35
  rv = sc_select_file(p15card->card, &path, &tmpf);
619
35
  LOG_TEST_RET(ctx, rv, "Cannot generate key: failed to select private object DF");
620
621
34
  rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CRYPTO);
622
34
  if (rv != SC_SUCCESS) {
623
1
    sc_file_free(tmpf);
624
1
    LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CRYPTO' authentication failed");
625
1
  }
626
627
33
  rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CREATE);
628
33
  sc_file_free(tmpf);
629
33
  tmpf = NULL;
630
33
  LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CREATE' authentication failed");
631
632
32
  rv = sc_select_file(p15card->card, &key_info->path, &prkf);
633
32
  LOG_TEST_RET(ctx, rv, "Failed to generate key: cannot select private key file");
634
635
  /* In the private key DF create the temporary public RSA file. */
636
25
  rv = cosm_get_temporary_public_key_file(p15card->card, prkf, &tmpf);
637
25
  if (rv != SC_SUCCESS) {
638
2
    sc_file_free(prkf);
639
2
    LOG_TEST_RET(ctx, rv, "Error while getting temporary public key file");
640
2
  }
641
642
23
  rv = sc_pkcs15init_create_file(profile, p15card, tmpf);
643
23
  if (rv != SC_SUCCESS) {
644
18
    sc_file_free(prkf);
645
18
    sc_file_free(tmpf);
646
18
    LOG_TEST_RET(ctx, rv, "cosm_generate_key() failed to create temporary public key EF");
647
18
  }
648
649
5
  memset(&args, 0, sizeof(args));
650
5
  args.id_prv = prkf->id;
651
5
  args.id_pub = tmpf->id;
652
5
  args.exponent = 0x10001;
653
5
  args.key_bits = key_info->modulus_length;
654
5
  args.pubkey_len = key_info->modulus_length / 8;
655
5
  args.pubkey = malloc(key_info->modulus_length / 8);
656
5
  if (!args.pubkey) {
657
0
    sc_file_free(prkf);
658
0
    sc_file_free(tmpf);
659
0
    LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate pubkey");
660
0
  }
661
662
5
  rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_GENERATE_KEY, &args);
663
5
  if (rv != SC_SUCCESS) {
664
4
    sc_file_free(prkf);
665
4
    sc_file_free(tmpf);
666
4
    free(args.pubkey);
667
4
  }
668
5
  LOG_TEST_RET(ctx, rv, "cosm_generate_key() CARDCTL_OBERTHUR_GENERATE_KEY failed");
669
670
  /* extract public key */
671
1
  pubkey->algorithm = SC_ALGORITHM_RSA;
672
1
  pubkey->u.rsa.modulus.len   = key_info->modulus_length / 8;
673
1
  pubkey->u.rsa.modulus.data  = malloc(key_info->modulus_length / 8);
674
1
  if (!pubkey->u.rsa.modulus.data) {
675
0
    sc_file_free(prkf);
676
0
    sc_file_free(tmpf);
677
0
    free(args.pubkey);
678
0
    LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate modulus buf");
679
0
  }
680
681
  /* FIXME and if the exponent length is not 3? */
682
1
  pubkey->u.rsa.exponent.len  = 3;
683
1
  pubkey->u.rsa.exponent.data = malloc(3);
684
1
  if (!pubkey->u.rsa.exponent.data) {
685
0
    sc_file_free(prkf);
686
0
    sc_file_free(tmpf);
687
0
    free(args.pubkey);
688
0
    free(pubkey->u.rsa.modulus.data);
689
0
    LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate exponent buf");
690
0
  }
691
1
  memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3);
692
1
  memcpy(pubkey->u.rsa.modulus.data, args.pubkey, args.pubkey_len);
693
694
1
  key_info->key_reference = prkf->path.value[prkf->path.len - 1] & 0xFF;
695
1
  key_info->path = prkf->path;
696
697
1
  sc_log(ctx,  "cosm_generate_key() now delete temporary public key");
698
1
  rv =  cosm_delete_file(p15card, profile, tmpf);
699
700
1
  sc_file_free(tmpf);
701
1
  sc_file_free(prkf);
702
1
  free(args.pubkey);
703
704
1
  LOG_FUNC_RETURN(ctx, rv);
705
1
}
706
707
708
/*
709
 * Create private key file
710
 */
711
static int
712
cosm_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
713
    struct sc_pkcs15_object *object)
714
1.92k
{
715
1.92k
  struct sc_context *ctx = p15card->card->ctx;
716
1.92k
  struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
717
1.92k
  struct sc_file *file = NULL;
718
1.92k
  int rv = 0;
719
720
1.92k
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
721
1.92k
  if (object->type != SC_PKCS15_TYPE_PRKEY_RSA)
722
1.92k
    LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Create key failed: RSA only supported");
723
724
481
  if (key_info->path.len < 2)
725
481
    LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID, "The path needs to be at least to bytes long");
726
727
220
  sc_log(ctx,  "create private key ID:%s",  sc_pkcs15_print_id(&key_info->id));
728
  /* Here, the path of private key file should be defined.
729
   * Nevertheless, we need to instantiate private key to get the ACLs. */
730
220
  rv = cosm_new_file(profile, p15card->card, SC_PKCS15_TYPE_PRKEY_RSA, key_info->key_reference, &file);
731
220
  LOG_TEST_RET(ctx, rv, "Cannot create key: failed to allocate new key object");
732
733
93
  file->size = key_info->modulus_length;
734
93
  memcpy(&file->path, &key_info->path, sizeof(file->path));
735
93
  file->id = file->path.value[file->path.len - 2] * 0x100
736
93
        + file->path.value[file->path.len - 1];
737
738
93
  sc_log(ctx,  "Path of private key file to create %s", sc_print_path(&file->path));
739
740
93
  rv = sc_select_file(p15card->card, &file->path, NULL);
741
93
  if (rv == 0)   {
742
48
    rv = cosm_delete_file(p15card, profile, file);
743
48
    SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to delete private key file");
744
48
  }
745
45
  else if (rv != SC_ERROR_FILE_NOT_FOUND)    {
746
9
    SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Select private key file error");
747
9
  }
748
749
50
  rv = sc_pkcs15init_create_file(profile, p15card, file);
750
50
  SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to create private key file");
751
752
35
  key_info->key_reference = file->path.value[file->path.len - 1];
753
754
93
err:
755
93
  sc_file_free(file);
756
757
93
  LOG_FUNC_RETURN(ctx, rv);
758
93
}
759
760
761
/*
762
 * Store a private key
763
 */
764
static int
765
cosm_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
766
    struct sc_pkcs15_object *object,
767
    struct sc_pkcs15_prkey *prkey)
768
0
{
769
0
  struct sc_context *ctx = p15card->card->ctx;
770
0
  struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
771
0
  struct sc_file *file = NULL;
772
0
  struct sc_cardctl_oberthur_updatekey_info update_info;
773
0
  int rv = 0;
774
775
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
776
0
  if (object->type != SC_PKCS15_TYPE_PRKEY_RSA || prkey->algorithm != SC_ALGORITHM_RSA)
777
0
    LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Store key failed: RSA only supported");
778
779
0
  sc_log(ctx,  "store key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id),
780
0
            sc_print_path(&key_info->path));
781
782
0
  rv = sc_select_file(p15card->card, &key_info->path, &file);
783
0
  LOG_TEST_RET(ctx, rv, "Cannot store key: select key file failed");
784
785
0
  rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
786
0
  LOG_TEST_RET(ctx, rv, "No authorisation to store private key");
787
788
0
  if (key_info->id.len > sizeof(update_info.id))
789
0
     LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
790
791
0
  memset(&update_info, 0, sizeof(update_info));
792
0
  update_info.type = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT;
793
0
  update_info.data = (void *)&prkey->u.rsa;
794
0
  update_info.data_len = sizeof(void *);
795
0
  update_info.id_len = key_info->id.len;
796
0
  memcpy(update_info.id, key_info->id.value, update_info.id_len);
797
798
0
  rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_UPDATE_KEY, &update_info);
799
0
  LOG_TEST_RET(ctx, rv, "Cannot update private key");
800
801
0
  sc_file_free(file);
802
803
0
  LOG_FUNC_RETURN(ctx, rv);
804
0
}
805
806
807
#ifdef ENABLE_OPENSSL
808
static int
809
cosm_emu_update_dir (struct sc_profile *profile, struct sc_pkcs15_card *p15card,
810
    struct sc_app_info *info)
811
0
{
812
0
  SC_FUNC_CALLED(p15card->card->ctx, 1);
813
  /* No DIR file in the native Oberthur card */
814
0
  SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS);
815
0
}
816
817
818
static int
819
cosm_emu_update_any_df(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
820
    unsigned op, struct sc_pkcs15_object *object)
821
0
{
822
0
  struct sc_context *ctx = p15card->card->ctx;
823
0
  int rv = SC_ERROR_NOT_SUPPORTED;
824
825
0
  SC_FUNC_CALLED(ctx, 1);
826
0
  switch(op)   {
827
0
  case SC_AC_OP_ERASE:
828
0
    sc_log(ctx,  "Update DF; erase object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type);
829
0
    rv = awp_update_df_delete(p15card, profile, object);
830
0
    break;
831
0
  case SC_AC_OP_CREATE:
832
0
    sc_log(ctx,  "Update DF; create object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type);
833
0
    rv = awp_update_df_create(p15card, profile, object);
834
0
    break;
835
0
  }
836
0
  SC_FUNC_RETURN(ctx, 1, rv);
837
0
}
838
839
840
static int
841
cosm_emu_update_tokeninfo(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
842
    struct sc_pkcs15_tokeninfo *tinfo)
843
0
{
844
0
  struct sc_context *ctx = p15card->card->ctx;
845
0
  struct sc_file *file = NULL;
846
0
  int rv, flags = 0;
847
0
  size_t label_len;
848
0
  unsigned char *buf = NULL;
849
850
0
  SC_FUNC_CALLED(ctx, 1);
851
852
0
  if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file))
853
0
    LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "cannot find "COSM_TITLE"-token-info");
854
855
0
  buf = calloc(1, file->size);
856
0
  if (!buf) {
857
0
    sc_file_free(file);
858
0
    SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
859
0
  }
860
861
0
  label_len = strlen(tinfo->label) > (file->size - 4) ? (file->size - 4) : strlen(tinfo->label);
862
0
  memcpy(buf, tinfo->label, label_len);
863
0
  memset(buf  + label_len, ' ', file->size - 4 - label_len);
864
865
  /*  current PKCS#11 flags should be read from the token,
866
   *  but for simplicity assume that user-pin is already initialised -- Andre 2010-10-05
867
   */
868
0
  flags = COSM_TOKEN_FLAG_TOKEN_INITIALIZED
869
0
    | COSM_TOKEN_FLAG_USER_PIN_INITIALIZED
870
0
    | COSM_TOKEN_FLAG_LOGIN_REQUIRED
871
0
    | COSM_TOKEN_FLAG_PRN_GENERATION;
872
873
0
  memset(buf + file->size - 4, 0, 4);
874
0
  *(buf + file->size - 1) = flags % 0x100;
875
0
  *(buf + file->size - 2) = (flags % 0x10000) / 0x100;
876
877
0
  sc_log(ctx,  "Update token info (label:'%s',flags:%X,p15card->flags:%X)", buf, flags, p15card->flags);
878
0
  rv = sc_pkcs15init_update_file(profile, p15card, file, buf, file->size);
879
0
  free(buf);
880
0
  sc_file_free(file);
881
882
0
  if (rv > 0)
883
0
    rv = 0;
884
885
0
  SC_FUNC_RETURN(ctx, 1, rv);
886
0
}
887
888
889
static int
890
cosm_emu_write_info(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
891
    struct sc_pkcs15_object *pin_obj)
892
0
{
893
0
  SC_FUNC_CALLED(p15card->card->ctx, 1);
894
  /* No OpenSC Info file in the native Oberthur card */
895
0
  SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS);
896
0
}
897
#endif
898
899
900
static struct sc_pkcs15init_operations
901
sc_pkcs15init_oberthur_operations = {
902
  cosm_erase_card,
903
  NULL,       /* init_card  */
904
  cosm_create_dir,    /* create_dir */
905
  NULL,       /* create_domain */
906
  cosm_select_pin_reference,
907
  cosm_create_pin,
908
  NULL,       /* select_key_reference */
909
  cosm_create_key,    /* create_key */
910
  cosm_store_key,     /* store_key */
911
  cosm_generate_key,    /* generate_key */
912
  NULL,
913
  NULL,       /* encode private/public key */
914
  NULL,       /* finalize_card */
915
  NULL,       /* delete_object */
916
#ifdef ENABLE_OPENSSL
917
  cosm_emu_update_dir,
918
  cosm_emu_update_any_df,
919
  cosm_emu_update_tokeninfo,
920
  cosm_emu_write_info,
921
  NULL,
922
  NULL
923
#else
924
  NULL, NULL, NULL, NULL, NULL,
925
  NULL
926
#endif
927
};
928
929
struct sc_pkcs15init_operations *
930
sc_pkcs15init_get_oberthur_ops(void)
931
945
{
932
945
  return &sc_pkcs15init_oberthur_operations;
933
945
}