Coverage Report

Created: 2026-10-17 06:29

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