Coverage Report

Created: 2026-06-06 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/pkcs15init/pkcs15-oberthur.c
Line
Count
Source
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
596
#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
91
#define SC_DEVICE_SPECIFIC_TYPE  0x1000
41
42
91
#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
338
{
123
338
  struct sc_context *ctx = p15card->card->ctx;
124
338
  struct sc_path  path;
125
338
  struct sc_file  *parent;
126
338
  int rv = 0;
127
128
338
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
129
338
  sc_log(ctx,  "id %04X", df->id);
130
338
  if (df->type==SC_FILE_TYPE_DF)   {
131
287
    rv = sc_pkcs15init_authenticate(profile, p15card, df, SC_AC_OP_DELETE);
132
287
    LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE");
133
287
  }
134
135
  /* Select the parent DF */
136
66
  path = df->path;
137
66
  if (path.len < 2) {
138
2
    LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
139
2
  }
140
64
  path.len -= 2;
141
142
64
  rv = sc_select_file(p15card->card, &path, &parent);
143
64
  LOG_TEST_RET(ctx, rv, "Cannot select parent");
144
145
49
  rv = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_DELETE);
146
49
  sc_file_free(parent);
147
49
  LOG_TEST_RET(ctx, rv, "Cannot authenticate SC_AC_OP_DELETE");
148
149
49
  memset(&path, 0, sizeof(path));
150
49
  path.type = SC_PATH_TYPE_FILE_ID;
151
49
  path.value[0] = df->id >> 8;
152
49
  path.value[1] = df->id & 0xFF;
153
49
  path.len = 2;
154
155
49
  rv = sc_delete_file(p15card->card, &path);
156
157
49
  LOG_FUNC_RETURN(ctx, rv);
158
49
}
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
290
{
167
290
  struct sc_context *ctx = p15card->card->ctx;
168
290
  struct sc_file  *df = profile->df_info->file, *dir;
169
290
  int rv;
170
171
290
  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
290
  if (sc_profile_get_file(profile, "DIR", &dir) >= 0) {
179
6
    sc_log(ctx,  "erase file dir %04X",dir->id);
180
6
    rv = cosm_delete_file(p15card, profile, dir);
181
6
    sc_file_free(dir);
182
6
    if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND)
183
2
      goto done;
184
6
  }
185
186
288
  sc_log(ctx,  "erase file ddf %04X",df->id);
187
288
  rv = cosm_delete_file(p15card, profile, df);
188
288
  if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND)
189
287
    goto done;
190
191
1
  if (sc_profile_get_file(profile, "private-DF", &dir) >= 0) {
192
1
    sc_log(ctx,  "erase file dir %04X",dir->id);
193
1
    rv = cosm_delete_file(p15card, profile, dir);
194
1
    sc_file_free(dir);
195
1
    if (rv < 0 && rv != SC_ERROR_FILE_NOT_FOUND)
196
1
      goto done;
197
1
  }
198
199
0
  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
0
  rv = sc_profile_get_file(profile, COSM_TITLE"-AppDF", &dir);
208
0
  if (!rv) {
209
0
    sc_log(ctx,  "delete %s; r %i", COSM_TITLE"-AppDF", rv);
210
0
    rv = cosm_delete_file(p15card, profile, dir);
211
0
    sc_file_free(dir);
212
0
  }
213
214
0
  sc_free_apps(p15card->card);
215
290
done:
216
290
  if (rv == SC_ERROR_FILE_NOT_FOUND)
217
0
    rv = 0;
218
219
290
  LOG_FUNC_RETURN(ctx, rv);
220
290
}
221
222
223
static int
224
cosm_create_dir(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
225
    struct sc_file *df)
226
0
{
227
0
  struct sc_context *ctx = p15card->card->ctx;
228
0
  struct sc_file *file = NULL;
229
0
  size_t ii;
230
0
  int rv;
231
0
  static const char *create_dfs[] = {
232
0
    COSM_TITLE"-AppDF",
233
0
    "private-DF",
234
0
    "public-DF",
235
0
    COSM_TITLE"-token-info",
236
0
    COSM_TITLE"-puk-file",
237
0
    COSM_TITLE"-container-list",
238
0
    COSM_TITLE"-public-list",
239
0
    COSM_TITLE"-private-list",
240
0
    NULL
241
0
  };
242
243
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
244
245
  /* Oberthur AWP file system is expected.*/
246
  /* Create private objects DF */
247
0
  for (ii = 0; create_dfs[ii]; ii++)   {
248
0
    if (sc_profile_get_file(profile, create_dfs[ii], &file))   {
249
0
      sc_log(ctx,  "Inconsistent profile: cannot find %s", create_dfs[ii]);
250
0
      LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Profile do not contains Oberthur AWP file");
251
0
    }
252
253
0
    rv = sc_pkcs15init_create_file(profile, p15card, file);
254
0
    sc_file_free(file);
255
0
    if (rv != SC_ERROR_FILE_ALREADY_EXISTS)
256
0
      LOG_TEST_RET(ctx, rv, "Failed to create Oberthur AWP file");
257
0
  }
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
0
{
272
0
  struct sc_context *ctx = p15card->card->ctx;
273
0
  struct sc_card *card = p15card->card;
274
0
  struct sc_pkcs15_auth_info profile_auth_pin = {0}, profile_auth_puk = {0};
275
0
  struct sc_cardctl_oberthur_createpin_info args;
276
0
  int rv;
277
0
  unsigned char oberthur_puk[16] = {
278
0
    0x6F, 0x47, 0xD9, 0x88, 0x4B, 0x6F, 0x9D, 0xC5,
279
0
    0x78, 0x33, 0x79, 0x8F, 0x5B, 0x7D, 0xE1, 0xA5
280
0
  };
281
282
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
283
0
  sc_log(ctx,
284
0
     "pin lens %"SC_FORMAT_LEN_SIZE_T"u/%"SC_FORMAT_LEN_SIZE_T"u",
285
0
     pin_len, puk_len);
286
0
  if (!pin || pin_len>0x40)
287
0
    return SC_ERROR_INVALID_ARGUMENTS;
288
0
  if (puk && !puk_len)
289
0
    return SC_ERROR_INVALID_ARGUMENTS;
290
0
  if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
291
0
    return SC_ERROR_OBJECT_NOT_VALID;
292
293
0
  rv = sc_select_file(card, &ainfo->path, NULL);
294
0
  LOG_TEST_RET(ctx, rv, "Cannot select file");
295
296
0
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &profile_auth_pin);
297
0
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &profile_auth_puk);
298
299
0
  memset(&args, 0, sizeof(args));
300
0
  args.type = SC_AC_CHV;
301
0
  args.ref = ainfo->attrs.pin.reference;
302
0
  args.pin = pin;
303
0
  args.pin_len = pin_len;
304
305
0
  if (!(ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN))   {
306
0
    args.pin_tries = profile_auth_pin.tries_left;
307
0
    if (profile_auth_puk.tries_left > 0)   {
308
0
      args.puk = oberthur_puk;
309
0
      args.puk_len = sizeof(oberthur_puk);
310
0
      args.puk_tries = 5;
311
0
    }
312
0
  }
313
0
  else   {
314
0
    args.pin_tries = profile_auth_puk.tries_left;
315
0
  }
316
317
0
  rv = sc_card_ctl(card, SC_CARDCTL_OBERTHUR_CREATE_PIN, &args);
318
0
  LOG_TEST_RET(ctx, rv, "'CREATE_PIN' card specific command failed");
319
320
0
  if (!(ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)
321
0
      && (profile_auth_puk.tries_left > 0))   {
322
0
          struct sc_file *file = NULL;
323
324
0
    if (sc_profile_get_file(profile, COSM_TITLE"-puk-file", &file))
325
0
      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
0
{
345
0
  struct sc_context *ctx = p15card->card->ctx;
346
0
  int rv;
347
348
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
349
0
  if (ainfo->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
350
0
    return SC_ERROR_OBJECT_NOT_VALID;
351
352
0
  sc_log(ctx,  "ref %i; flags 0x%X", ainfo->attrs.pin.reference, ainfo->attrs.pin.flags);
353
354
0
  if (ainfo->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)   {
355
0
    if (ainfo->attrs.pin.reference != 4)
356
0
      LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "cosm_update_pin() invalid SOPIN reference");
357
0
    sc_log(ctx,  "Update SOPIN ignored");
358
0
    rv = SC_SUCCESS;
359
0
  }
360
0
  else   {
361
0
    rv = cosm_create_reference_data(profile, p15card, ainfo, pin, pin_len, puk, puk_len);
362
0
    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
0
  LOG_FUNC_RETURN(ctx, rv);
373
0
}
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
299
{
380
299
  struct sc_context *ctx = p15card->card->ctx;
381
299
  struct sc_pkcs15_pin_attributes *pin_attrs;
382
299
  struct sc_file *pinfile;
383
384
299
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
385
299
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
386
0
    return SC_ERROR_OBJECT_NOT_VALID;
387
388
299
  pin_attrs = &auth_info->attrs.pin;
389
390
299
  sc_log(ctx,  "ref %i; flags %X", pin_attrs->reference, pin_attrs->flags);
391
299
  if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pinfile) < 0) {
392
296
    sc_log(ctx,  "Profile doesn't define \"%s\"", COSM_TITLE "-AppDF");
393
296
    return SC_ERROR_INCONSISTENT_PROFILE;
394
296
  }
395
396
3
  if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL)
397
0
    auth_info->path = pinfile->path;
398
399
3
  sc_file_free(pinfile);
400
401
3
  if (pin_attrs->reference <= 0)   {
402
2
    if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
403
0
      pin_attrs->reference = 4;
404
2
    else if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)
405
1
      pin_attrs->reference = 4;
406
1
    else
407
1
      pin_attrs->reference = 1;
408
409
2
    if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL)
410
0
      pin_attrs->reference |= 0x80;
411
2
  }
412
413
3
  LOG_FUNC_RETURN(ctx, SC_SUCCESS);
414
3
}
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
1
{
426
1
  struct sc_context *ctx = p15card->card->ctx;
427
1
  struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) pin_obj->data;
428
1
  struct sc_pkcs15_pin_attributes *pin_attrs;
429
1
  struct sc_file *pin_file;
430
1
  int rv = 0;
431
432
1
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
433
1
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
434
0
    return SC_ERROR_OBJECT_NOT_VALID;
435
436
1
  pin_attrs = &auth_info->attrs.pin;
437
438
1
  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
1
  if (sc_profile_get_file(profile, COSM_TITLE "-AppDF", &pin_file) < 0)
440
1
    LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "\""COSM_TITLE"-AppDF\" not defined");
441
442
1
  if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_LOCAL)
443
0
    auth_info->path = pin_file->path;
444
445
1
  sc_file_free(pin_file);
446
447
1
  if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN)   {
448
0
    if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)   {
449
0
      LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "SOPIN unblocking is not supported");
450
0
    }
451
0
    else   {
452
0
      if (pin_attrs->reference != 4)
453
0
        LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid SOPIN reference");
454
0
    }
455
0
  }
456
1
  else {
457
1
    if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN)   {
458
1
      if (pin_attrs->reference != 0x84)
459
1
        LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PUK reference");
460
1
    }
461
0
    else   {
462
0
      if (pin_attrs->reference != 0x81)
463
0
        LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_REFERENCE, "Invalid User PIN reference");
464
0
    }
465
1
  }
466
467
0
  if (pin && pin_len)   {
468
0
    rv = cosm_update_pin(profile, p15card, auth_info, pin, pin_len,  puk, puk_len);
469
0
    LOG_TEST_RET(ctx, rv, "Update PIN failed");
470
0
  }
471
472
0
  LOG_FUNC_RETURN(ctx, rv);
473
0
}
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
91
{
483
91
  struct sc_file  *file;
484
91
  const char *_template = NULL, *desc = NULL;
485
91
  unsigned int structure = 0xFFFFFFFF;
486
487
91
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
488
91
  sc_log(card->ctx,  "cosm_new_file() type %X; num %i",type, num);
489
91
  while (1) {
490
91
    switch (type) {
491
91
    case SC_PKCS15_TYPE_PRKEY_RSA:
492
91
    case COSM_TYPE_PRKEY_RSA:
493
91
      desc = "RSA private key";
494
91
      _template = "template-private-key";
495
91
      structure = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT;
496
91
      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
91
    }
512
91
    if (_template)
513
91
      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
91
  sc_log(card->ctx,  "cosm_new_file() template %s; num %i",_template, num);
527
91
  if (sc_profile_get_file(profile, _template, &file) < 0) {
528
37
    sc_log(card->ctx,  "Profile doesn't define %s template '%s'",
529
37
        desc, _template);
530
37
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
531
37
  }
532
533
54
  file->id |= (num & 0xFF);
534
54
  if (file->path.len) {
535
54
    file->path.value[file->path.len - 1] |= (num & 0xFF);
536
54
  }
537
54
  if (file->type == SC_FILE_TYPE_INTERNAL_EF)   {
538
1
    file->ef_structure = structure;
539
1
  }
540
541
54
  sc_log(card->ctx,
542
54
     "cosm_new_file() file size %"SC_FORMAT_LEN_SIZE_T"u; ef type %i/%i; id %04X",
543
54
     file->size, file->type, file->ef_structure, file->id);
544
54
  *out = file;
545
546
54
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
547
54
}
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
5
{
554
5
  struct sc_context *ctx = card->ctx;
555
5
  const struct sc_acl_entry *entry = NULL;
556
5
  struct sc_file *file = NULL;
557
5
  int rv;
558
559
5
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
560
5
  if (!pubkey_file || !prvkey_file)
561
5
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
562
563
5
  file = sc_file_new();
564
5
  if (!file)
565
5
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
566
567
5
  file->status = SC_FILE_STATUS_ACTIVATED;
568
5
        file->type = SC_FILE_TYPE_INTERNAL_EF;
569
5
  file->ef_structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
570
5
  file->id = 0x1012;
571
5
  memcpy(&file->path, &prvkey_file->path, sizeof(file->path));
572
5
        file->path.value[file->path.len - 2] = 0x10;
573
5
  file->path.value[file->path.len - 1] = 0x12;
574
5
  file->size = prvkey_file->size;
575
576
5
  entry = sc_file_get_acl_entry(prvkey_file, SC_AC_OP_UPDATE);
577
5
  if (!entry) {
578
1
    sc_file_free(file);
579
1
    LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "Failed to find ACL entry");
580
1
  }
581
4
  rv = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, entry->method, entry->key_ref);
582
4
  if (!rv)
583
4
    rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_ENCRYPT, SC_AC_NONE, 0);
584
4
  if (!rv)
585
4
    rv = sc_file_add_acl_entry(file, SC_AC_OP_PSO_VERIFY_SIGNATURE, SC_AC_NONE, 0);
586
4
  if (!rv)
587
4
    rv = sc_file_add_acl_entry(file, SC_AC_OP_EXTERNAL_AUTHENTICATE, SC_AC_NONE, 0);
588
4
  if (rv < 0)
589
0
    sc_file_free(file);
590
4
  LOG_TEST_RET(ctx, rv, "Failed to add ACL entry to the temporary public key file");
591
592
4
  *pubkey_file = file;
593
594
4
  LOG_FUNC_RETURN(card->ctx, rv);
595
4
}
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
10
{
603
10
  struct sc_context *ctx = p15card->card->ctx;
604
10
  struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
605
10
  struct sc_cardctl_oberthur_genkey_info args;
606
10
  struct sc_file *prkf = NULL, *tmpf = NULL;
607
10
  struct sc_path path;
608
10
  int rv = 0;
609
610
10
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
611
612
10
  if (object->type != SC_PKCS15_TYPE_PRKEY_RSA)
613
10
    LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: RSA only supported");
614
615
10
  if (key_info->path.len < 4) {
616
0
    LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID,
617
0
        "The path needs to be at least four bytes long");
618
0
  }
619
620
10
  path = key_info->path;
621
10
  path.len -= 2;
622
623
10
  rv = sc_select_file(p15card->card, &path, &tmpf);
624
10
  LOG_TEST_RET(ctx, rv, "Cannot generate key: failed to select private object DF");
625
626
9
  rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CRYPTO);
627
9
  if (rv != SC_SUCCESS) {
628
1
    sc_file_free(tmpf);
629
1
    LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CRYPTO' authentication failed");
630
1
  }
631
632
8
  rv = sc_pkcs15init_authenticate(profile, p15card, tmpf, SC_AC_OP_CREATE);
633
8
  sc_file_free(tmpf);
634
8
  tmpf = NULL;
635
8
  LOG_TEST_RET(ctx, rv, "Cannot generate key: 'CREATE' authentication failed");
636
637
7
  rv = sc_select_file(p15card->card, &key_info->path, &prkf);
638
7
  LOG_TEST_RET(ctx, rv, "Failed to generate key: cannot select private key file");
639
640
  /* In the private key DF create the temporary public RSA file. */
641
5
  rv = cosm_get_temporary_public_key_file(p15card->card, prkf, &tmpf);
642
5
  if (rv != SC_SUCCESS) {
643
1
    sc_file_free(prkf);
644
1
    LOG_TEST_RET(ctx, rv, "Error while getting temporary public key file");
645
1
  }
646
647
4
  rv = sc_pkcs15init_create_file(profile, p15card, tmpf);
648
4
  if (rv != SC_SUCCESS) {
649
0
    sc_file_free(prkf);
650
0
    sc_file_free(tmpf);
651
0
    LOG_TEST_RET(ctx, rv, "cosm_generate_key() failed to create temporary public key EF");
652
0
  }
653
654
4
  memset(&args, 0, sizeof(args));
655
4
  args.id_prv = prkf->id;
656
4
  args.id_pub = tmpf->id;
657
4
  args.exponent = 0x10001;
658
4
  args.key_bits = key_info->modulus_length;
659
4
  args.pubkey_len = key_info->modulus_length / 8;
660
4
  args.pubkey = malloc(key_info->modulus_length / 8);
661
4
  if (!args.pubkey) {
662
0
    sc_file_free(prkf);
663
0
    sc_file_free(tmpf);
664
0
    LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate pubkey");
665
0
  }
666
667
4
  rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_GENERATE_KEY, &args);
668
4
  if (rv != SC_SUCCESS) {
669
3
    sc_file_free(prkf);
670
3
    sc_file_free(tmpf);
671
3
    free(args.pubkey);
672
3
  }
673
4
  LOG_TEST_RET(ctx, rv, "cosm_generate_key() CARDCTL_OBERTHUR_GENERATE_KEY failed");
674
675
  /* extract public key */
676
1
  pubkey->algorithm = SC_ALGORITHM_RSA;
677
1
  pubkey->u.rsa.modulus.len   = key_info->modulus_length / 8;
678
1
  pubkey->u.rsa.modulus.data  = malloc(key_info->modulus_length / 8);
679
1
  if (!pubkey->u.rsa.modulus.data) {
680
0
    sc_file_free(prkf);
681
0
    sc_file_free(tmpf);
682
0
    free(args.pubkey);
683
0
    LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate modulus buf");
684
0
  }
685
686
  /* FIXME and if the exponent length is not 3? */
687
1
  pubkey->u.rsa.exponent.len  = 3;
688
1
  pubkey->u.rsa.exponent.data = malloc(3);
689
1
  if (!pubkey->u.rsa.exponent.data) {
690
0
    sc_file_free(prkf);
691
0
    sc_file_free(tmpf);
692
0
    free(args.pubkey);
693
0
    free(pubkey->u.rsa.modulus.data);
694
0
    LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "cosm_generate_key() cannot allocate exponent buf");
695
0
  }
696
1
  memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3);
697
1
  memcpy(pubkey->u.rsa.modulus.data, args.pubkey, args.pubkey_len);
698
1
  pubkey->u.rsa.modulus.len = args.pubkey_len;
699
700
1
  key_info->key_reference = prkf->path.value[prkf->path.len - 1] & 0xFF;
701
1
  key_info->path = prkf->path;
702
703
1
  sc_log(ctx,  "cosm_generate_key() now delete temporary public key");
704
1
  rv =  cosm_delete_file(p15card, profile, tmpf);
705
706
1
  sc_file_free(tmpf);
707
1
  sc_file_free(prkf);
708
1
  free(args.pubkey);
709
710
1
  LOG_FUNC_RETURN(ctx, rv);
711
1
}
712
713
714
/*
715
 * Create private key file
716
 */
717
static int
718
cosm_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
719
    struct sc_pkcs15_object *object)
720
1.15k
{
721
1.15k
  struct sc_context *ctx = p15card->card->ctx;
722
1.15k
  struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
723
1.15k
  struct sc_file *file = NULL;
724
1.15k
  int rv = 0;
725
726
1.15k
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
727
1.15k
  if (object->type != SC_PKCS15_TYPE_PRKEY_RSA)
728
1.15k
    LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Create key failed: RSA only supported");
729
730
288
  if (key_info->path.len < 2) {
731
197
    LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_VALID,
732
197
        "The path needs to be at least two bytes long");
733
197
  }
734
735
91
  sc_log(ctx,  "create private key ID:%s",  sc_pkcs15_print_id(&key_info->id));
736
  /* Here, the path of private key file should be defined.
737
   * Nevertheless, we need to instantiate private key to get the ACLs. */
738
91
  rv = cosm_new_file(profile, p15card->card, SC_PKCS15_TYPE_PRKEY_RSA, key_info->key_reference, &file);
739
91
  LOG_TEST_RET(ctx, rv, "Cannot create key: failed to allocate new key object");
740
741
54
  file->size = key_info->modulus_length;
742
54
  memcpy(&file->path, &key_info->path, sizeof(file->path));
743
54
  file->id = file->path.value[file->path.len - 2] * 0x100
744
54
        + file->path.value[file->path.len - 1];
745
746
54
  sc_log(ctx,  "Path of private key file to create %s", sc_print_path(&file->path));
747
748
54
  rv = sc_select_file(p15card->card, &file->path, NULL);
749
54
  if (rv == 0)   {
750
42
    rv = cosm_delete_file(p15card, profile, file);
751
42
    SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to delete private key file");
752
42
  }
753
12
  else if (rv != SC_ERROR_FILE_NOT_FOUND)    {
754
1
    SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Select private key file error");
755
1
  }
756
757
12
  rv = sc_pkcs15init_create_file(profile, p15card, file);
758
12
  SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "Failed to create private key file");
759
760
10
  key_info->key_reference = file->path.value[file->path.len - 1];
761
762
54
err:
763
54
  sc_file_free(file);
764
765
54
  LOG_FUNC_RETURN(ctx, rv);
766
54
}
767
768
769
/*
770
 * Store a private key
771
 */
772
static int
773
cosm_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
774
    struct sc_pkcs15_object *object,
775
    struct sc_pkcs15_prkey *prkey)
776
0
{
777
0
  struct sc_context *ctx = p15card->card->ctx;
778
0
  struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
779
0
  struct sc_file *file = NULL;
780
0
  struct sc_cardctl_oberthur_updatekey_info update_info;
781
0
  int rv = 0;
782
783
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
784
0
  if (object->type != SC_PKCS15_TYPE_PRKEY_RSA || prkey->algorithm != SC_ALGORITHM_RSA)
785
0
    LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Store key failed: RSA only supported");
786
787
0
  sc_log(ctx,  "store key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id),
788
0
            sc_print_path(&key_info->path));
789
790
0
  rv = sc_select_file(p15card->card, &key_info->path, &file);
791
0
  LOG_TEST_RET(ctx, rv, "Cannot store key: select key file failed");
792
793
0
  rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
794
0
  LOG_TEST_RET(ctx, rv, "No authorisation to store private key");
795
796
0
  if (key_info->id.len > sizeof(update_info.id))
797
0
     LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
798
799
0
  memset(&update_info, 0, sizeof(update_info));
800
0
  update_info.type = SC_CARDCTL_OBERTHUR_KEY_RSA_CRT;
801
0
  update_info.data = (void *)&prkey->u.rsa;
802
0
  update_info.data_len = sizeof(void *);
803
0
  update_info.id_len = key_info->id.len;
804
0
  memcpy(update_info.id, key_info->id.value, update_info.id_len);
805
806
0
  rv = sc_card_ctl(p15card->card, SC_CARDCTL_OBERTHUR_UPDATE_KEY, &update_info);
807
0
  LOG_TEST_RET(ctx, rv, "Cannot update private key");
808
809
0
  sc_file_free(file);
810
811
0
  LOG_FUNC_RETURN(ctx, rv);
812
0
}
813
814
815
#ifdef ENABLE_OPENSSL
816
static int
817
cosm_emu_update_dir (struct sc_profile *profile, struct sc_pkcs15_card *p15card,
818
    struct sc_app_info *info)
819
0
{
820
0
  SC_FUNC_CALLED(p15card->card->ctx, 1);
821
  /* No DIR file in the native Oberthur card */
822
0
  SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS);
823
0
}
824
825
826
static int
827
cosm_emu_update_any_df(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
828
    unsigned op, struct sc_pkcs15_object *object)
829
0
{
830
0
  struct sc_context *ctx = p15card->card->ctx;
831
0
  int rv = SC_ERROR_NOT_SUPPORTED;
832
833
0
  SC_FUNC_CALLED(ctx, 1);
834
0
  switch(op)   {
835
0
  case SC_AC_OP_ERASE:
836
0
    sc_log(ctx,  "Update DF; erase object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type);
837
0
    rv = awp_update_df_delete(p15card, profile, object);
838
0
    break;
839
0
  case SC_AC_OP_CREATE:
840
0
    sc_log(ctx,  "Update DF; create object('%.*s',type:%X)", (int) sizeof object->label, object->label, object->type);
841
0
    rv = awp_update_df_create(p15card, profile, object);
842
0
    break;
843
0
  }
844
0
  SC_FUNC_RETURN(ctx, 1, rv);
845
0
}
846
847
848
static int
849
cosm_emu_update_tokeninfo(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
850
    struct sc_pkcs15_tokeninfo *tinfo)
851
0
{
852
0
  struct sc_context *ctx = p15card->card->ctx;
853
0
  struct sc_file *file = NULL;
854
0
  int rv, flags = 0;
855
0
  size_t label_len;
856
0
  unsigned char *buf = NULL;
857
858
0
  SC_FUNC_CALLED(ctx, 1);
859
860
0
  if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file))
861
0
    LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "cannot find "COSM_TITLE"-token-info");
862
863
0
  buf = calloc(1, file->size);
864
0
  if (!buf) {
865
0
    sc_file_free(file);
866
0
    SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
867
0
  }
868
869
0
  label_len = strlen(tinfo->label) > (file->size - 4) ? (file->size - 4) : strlen(tinfo->label);
870
0
  memcpy(buf, tinfo->label, label_len);
871
0
  memset(buf  + label_len, ' ', file->size - 4 - label_len);
872
873
  /*  current PKCS#11 flags should be read from the token,
874
   *  but for simplicity assume that user-pin is already initialised -- Andre 2010-10-05
875
   */
876
0
  flags = COSM_TOKEN_FLAG_TOKEN_INITIALIZED
877
0
    | COSM_TOKEN_FLAG_USER_PIN_INITIALIZED
878
0
    | COSM_TOKEN_FLAG_LOGIN_REQUIRED
879
0
    | COSM_TOKEN_FLAG_PRN_GENERATION;
880
881
0
  memset(buf + file->size - 4, 0, 4);
882
0
  *(buf + file->size - 1) = flags % 0x100;
883
0
  *(buf + file->size - 2) = (flags % 0x10000) / 0x100;
884
885
0
  sc_log(ctx,  "Update token info (label:'%s',flags:%X,p15card->flags:%X)", buf, flags, p15card->flags);
886
0
  rv = sc_pkcs15init_update_file(profile, p15card, file, buf, file->size);
887
0
  free(buf);
888
0
  sc_file_free(file);
889
890
0
  if (rv > 0)
891
0
    rv = 0;
892
893
0
  SC_FUNC_RETURN(ctx, 1, rv);
894
0
}
895
896
897
static int
898
cosm_emu_write_info(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
899
    struct sc_pkcs15_object *pin_obj)
900
0
{
901
0
  SC_FUNC_CALLED(p15card->card->ctx, 1);
902
  /* No OpenSC Info file in the native Oberthur card */
903
0
  SC_FUNC_RETURN(p15card->card->ctx, 1, SC_SUCCESS);
904
0
}
905
#endif
906
907
908
static struct sc_pkcs15init_operations
909
sc_pkcs15init_oberthur_operations = {
910
  cosm_erase_card,
911
  NULL,       /* init_card  */
912
  cosm_create_dir,    /* create_dir */
913
  NULL,       /* create_domain */
914
  cosm_select_pin_reference,
915
  cosm_create_pin,
916
  NULL,       /* select_key_reference */
917
  cosm_create_key,    /* create_key */
918
  cosm_store_key,     /* store_key */
919
  cosm_generate_key,    /* generate_key */
920
  NULL,
921
  NULL,       /* encode private/public key */
922
  NULL,       /* finalize_card */
923
  NULL,       /* delete_object */
924
#ifdef ENABLE_OPENSSL
925
  cosm_emu_update_dir,
926
  cosm_emu_update_any_df,
927
  cosm_emu_update_tokeninfo,
928
  cosm_emu_write_info,
929
  NULL,
930
  NULL
931
#else
932
  NULL, NULL, NULL, NULL, NULL,
933
  NULL
934
#endif
935
};
936
937
struct sc_pkcs15init_operations *
938
sc_pkcs15init_get_oberthur_ops(void)
939
449
{
940
449
  return &sc_pkcs15init_oberthur_operations;
941
449
}