Coverage Report

Created: 2025-09-05 06:32

/src/opensc/src/pkcs15init/pkcs15-asepcos.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2007  Athena Smartcard Solutions Inc.
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
 */
18
19
#include "config.h"
20
21
#include <sys/types.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include "libopensc/opensc.h"
26
#include "libopensc/cardctl.h"
27
#include "libopensc/log.h"
28
#include "pkcs15-init.h"
29
#include "profile.h"
30
31
/* delete a EF/DF if present. This function does not return an
32
 * error if the requested file is not present.
33
 */
34
static int asepcos_cond_delete(sc_profile_t *pro, sc_pkcs15_card_t *p15card,
35
  const sc_path_t *path)
36
0
{
37
0
  int r;
38
0
  sc_file_t *tfile = NULL;
39
40
0
  r = sc_select_file(p15card->card, path, &tfile);
41
0
  if (r == SC_SUCCESS) {
42
0
    r = sc_pkcs15init_authenticate(pro, p15card, tfile, SC_AC_OP_DELETE_SELF);
43
0
    sc_file_free(tfile);
44
0
    if (r != SC_SUCCESS)
45
0
      return r;
46
0
    r = sc_delete_file(p15card->card, path);
47
0
  } else if (r == SC_ERROR_FILE_NOT_FOUND)
48
0
    r = SC_SUCCESS;
49
0
  return r;
50
0
}
51
52
/* checks whether the file with the transport key exists. If existent
53
 * the transport key is verified and stored in the keycache (as a
54
 * normal user PIN with the same reference).
55
 * @param  profile  profile information for this card
56
 * @param  card     sc_card_t object to use
57
 * @return SC_SUCCESS on success and an error code otherwise
58
 */
59
static int asepcos_check_verify_tpin(sc_profile_t *profile, sc_pkcs15_card_t *p15card)
60
0
{
61
0
  struct sc_context *ctx = p15card->card->ctx;
62
0
  int r;
63
0
  sc_path_t path;
64
65
  /* check whether the file with the transport PIN exists */
66
0
  sc_format_path("3f000001", &path);
67
0
  r = sc_select_file(p15card->card, &path, NULL);
68
0
  if (r == SC_SUCCESS) {
69
    /* try to verify the transport key */
70
0
    sc_file_t *tfile = NULL;
71
72
0
    sc_format_path("3f00", &path);
73
0
    r = sc_profile_get_file_by_path(profile, sc_get_mf_path(), &tfile);
74
0
    if (r != SC_SUCCESS)
75
0
      return r;
76
    /* we need to temporarily disable the SC_CARD_CAP_USE_FCI_AC
77
     * flag to trick sc_pkcs15init_authenticate() to use access
78
     * information form the profile file */
79
0
    p15card->card->caps &= ~SC_CARD_CAP_USE_FCI_AC;
80
0
    r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_CRYPTO);
81
0
    p15card->card->caps |=  SC_CARD_CAP_USE_FCI_AC;
82
0
    sc_file_free(tfile);
83
0
    LOG_TEST_RET(ctx, r, "unable to authenticate for 'CRYPTO' operation");
84
0
  }
85
0
  return SC_SUCCESS;
86
0
}
87
88
/* erase card: erase all EFs/DFs created by OpenSC
89
 * @param  profile  the sc_profile_t object with the configurable profile
90
 *                  information
91
 * @param  card     the card from which the opensc application should be
92
 *                  erased.
93
 * @return SC_SUCCESS on success and an error code otherwise
94
 */
95
static int asepcos_erase(struct sc_profile *profile, sc_pkcs15_card_t *p15card)
96
0
{
97
0
  int r;
98
0
  sc_path_t path;
99
100
  /* TODO: - only remove the OpenSC entry in EF(DIR)
101
   *       - use EF(DIR) to get the DF of the OpenSC
102
   *         pkcs15 application.
103
   */
104
  /* Check whether a transport exists and verify it if present */
105
106
0
  p15card->opts.use_pin_cache = 1;
107
0
  r = asepcos_check_verify_tpin(profile, p15card);
108
0
  if (r != SC_SUCCESS)
109
0
    return r;
110
  /* EF(DIR) */
111
0
  sc_format_path("3f002f00", &path);
112
0
  r = asepcos_cond_delete(profile, p15card, &path);
113
0
  if (r != SC_SUCCESS)
114
0
    return r;
115
  /* DF(PKCS15) */
116
0
  sc_format_path("3f005015", &path);
117
0
  r = asepcos_cond_delete(profile, p15card, &path);
118
0
  if (r != SC_SUCCESS)
119
0
    return r;
120
121
0
  return SC_SUCCESS;
122
0
}
123
124
/* create application DF
125
 * @param  profile  sc_profile_t object with the configurable profile
126
 *                  information
127
 * @param  cardd    sc_card_t object to be used
128
 * @param  df       sc_file_t with the application DF to create
129
 * @return SC_SUCCESS on success and an error value otherwise
130
 */
131
static int asepcos_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
132
  sc_file_t *df)
133
0
{
134
0
  int r;
135
0
  static const u8 pa_acl[] = {0x80,0x01,0x5f,0x90,0x00};
136
0
  sc_file_t *tfile;
137
0
  sc_context_t *ctx = p15card->card->ctx;
138
139
0
  LOG_FUNC_CALLED(ctx);
140
  /* Check whether a transport exists and verify it if present */
141
0
  r = asepcos_check_verify_tpin(profile, p15card);
142
0
  if (r != SC_SUCCESS)
143
0
    return r;
144
  /* As we don't know whether or not a SO-PIN is used to protect the AC
145
   * in the application DF we set the preliminary security attributes
146
   * of the DF(PKCS15) to allow everything. Once a SO-PIN is set
147
   * we tighten security attributes to values specified in the profile.
148
   */
149
0
  sc_file_dup(&tfile, df);
150
  /* we use a separate copy of the sc_file_t object so we don't
151
   * override the permissions specified in the profile */
152
0
  if (tfile == NULL)
153
0
    return SC_ERROR_OUT_OF_MEMORY;
154
0
  r = sc_file_set_sec_attr(tfile, pa_acl, sizeof(pa_acl));
155
0
  if (r != SC_SUCCESS) {
156
0
    sc_file_free(tfile);
157
0
    return r;
158
0
  }
159
  /* create application DF */
160
0
  r = sc_pkcs15init_create_file(profile, p15card, tfile);
161
0
  sc_file_free(tfile);
162
0
  SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
163
0
}
164
165
166
/* select PIN reference: do nothing special, the real PIN reference if
167
 * determined when the PIN is created. This is just helper function to
168
 * determine the next best file id of the PIN file.
169
 */
170
static int asepcos_select_pin_reference(sc_profile_t *profile,
171
    sc_pkcs15_card_t *p15card, sc_pkcs15_auth_info_t *auth_info)
172
0
{
173
0
  if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
174
0
    return SC_SUCCESS;
175
0
  if (auth_info->attrs.pin.reference <= 0)
176
0
    auth_info->attrs.pin.reference = 1;
177
  /* as we want to use <fileid of PIN> + 1 for the PUK we need to
178
   * ensure that all references are odd => if the reference is
179
   * even add one */
180
0
  if ((auth_info->attrs.pin.reference & 1) == 0)
181
0
    auth_info->attrs.pin.reference++;
182
0
        return SC_SUCCESS;
183
0
}
184
185
/* asepcos_pinid_to_akn: returns the AKN of a PIN EF
186
 * This functions calls SELECT FILE and extracts the AKN from the
187
 * proprietary FCP attributes.
188
 * @param  card    sc_card_t object to use
189
 * @param  fileid  IN  file id of the PIN file
190
 * @param  akn     OUT the AKN of the PIN
191
 * @return SC_SUCCESS on success and an error code otherwise
192
 */
193
static int asepcos_pinid_to_akn(sc_card_t *card, int fileid, int *akn)
194
0
{
195
0
  int r;
196
0
  u8  fid[2];
197
0
  sc_path_t path;
198
0
  sc_file_t *nfile = NULL;
199
200
0
  fid[0] = (fileid >> 8) & 0xff;
201
0
  fid[1] = fileid & 0xff;
202
0
  r = sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, 0);
203
0
  if (r != SC_SUCCESS)
204
0
    return r;
205
0
  r = sc_select_file(card, &path, &nfile);
206
0
  if (r != SC_SUCCESS)
207
0
    return r;
208
0
  if (nfile->prop_attr == NULL || nfile->prop_attr_len != 11) {
209
0
    sc_log(card->ctx,  "unable to determine AKN");
210
0
    sc_file_free(nfile);
211
0
    return SC_ERROR_INTERNAL;
212
0
  }
213
0
  *akn = nfile->prop_attr[10];
214
0
  sc_file_free(nfile);
215
0
  return SC_SUCCESS;
216
0
}
217
218
static int asepcos_do_store_pin(sc_profile_t *profile, sc_card_t *card,
219
  sc_pkcs15_auth_info_t *auth_info, const u8* pin, size_t pinlen,
220
  int puk, int pinid)
221
0
{
222
0
  sc_file_t *nfile = NULL;
223
0
  u8  buf[64], sbuf[64], *p = buf, *q = sbuf;
224
0
  int r, akn = 0;
225
226
0
  if (auth_info == NULL || auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
227
0
    return SC_ERROR_OBJECT_NOT_VALID;
228
229
  /* outer tag */
230
0
  *p++ = 0x85;
231
0
  p++;
232
  /* as a file id for pin with use 0x00:<key id> */
233
0
  *p++ = (pinid >> 8) & 0xff;
234
0
  *p++ = pinid & 0xff;
235
  /* pin length */
236
0
  if (pinlen < 4 || pinlen > 16) {
237
0
    sc_log(card->ctx,  "invalid PIN length");
238
0
    return SC_ERROR_INVALID_ARGUMENTS;
239
0
  }
240
0
  *p++ = 0x00;
241
0
  *p++ = pinlen & 0xff;
242
  /* max tries */
243
0
  *p++ = auth_info->tries_left & 0xff;
244
  /* algorithm id and key key usage and padding bytes */
245
0
  *p++ = 0x00;
246
0
  *p++ = 0x00;
247
  /* key attributes (SO PIN) */
248
0
  *p++ = 0x00;
249
  /* the PIN */
250
0
  *p++ = 0x81;
251
0
  *p++ = pinlen & 0xff;
252
0
  memcpy(p, pin, pinlen);
253
0
  p += pinlen;
254
  /* set outer length */
255
0
  buf[1] = p - buf - 2;
256
257
0
  nfile = sc_file_new();
258
0
  if (nfile == NULL)
259
0
    return SC_ERROR_OUT_OF_MEMORY;
260
0
  nfile->type = SC_FILE_TYPE_INTERNAL_EF;
261
0
  nfile->id   = pinid & 0xffff;
262
0
  r = sc_file_set_prop_attr(nfile, buf, p - buf);
263
0
  if (r != SC_SUCCESS) {
264
0
    sc_file_free(nfile);
265
0
    return r;
266
0
  }
267
268
  /* set security attributes */
269
0
  *q++ = 0x80;
270
0
  *q++ = 0x01;
271
0
  *q++ = 0x92;
272
0
  *q++ = 0xa0;
273
0
  q++;
274
0
  *q++ = 0x89;
275
0
  *q++ = 0x03;
276
0
  *q++ = (pinid >> 16) & 0xff;
277
0
  *q++ = (pinid >> 8 ) & 0xff;
278
0
  *q++ = pinid & 0xff;
279
0
  if (puk != 0) {
280
0
    *q++ = 0x89;
281
0
    *q++ = 0x03;
282
0
    *q++ = (puk >> 16) & 0xff;
283
0
    *q++ = (puk >> 8 ) & 0xff;
284
0
    *q++ = puk & 0xff;
285
0
  }
286
0
  sbuf[4] = q - sbuf - 5;
287
  /* we need to set the security attributes separately as PIN itself
288
   * is used to protect the UPDATE access permission.
289
   */
290
0
  r = sc_file_set_sec_attr(nfile, sbuf, q - sbuf);
291
0
  if (r != SC_SUCCESS) {
292
0
    sc_file_free(nfile);
293
0
    return r;
294
0
  }
295
296
0
  r = sc_create_file(card, nfile);
297
0
  sc_file_free(nfile);
298
0
  if (r != SC_SUCCESS) {
299
0
    sc_log(card->ctx,  "unable to create PIN file");
300
0
    return r;
301
0
  }
302
  /* get AKN of the newly created PIN  */
303
0
  r = asepcos_pinid_to_akn(card, pinid, &akn);
304
0
  if (r != SC_SUCCESS)
305
0
    return r;
306
  /* use the AKN as reference */
307
0
  auth_info->attrs.pin.reference = akn;
308
  /* set the correct PIN length */
309
0
  auth_info->attrs.pin.min_length    = 4;
310
0
  auth_info->attrs.pin.stored_length = pinlen;
311
0
  auth_info->attrs.pin.max_length    = 16;
312
313
0
  return r;
314
0
}
315
316
/* simple function to detect whether or not the "onepin" profile is used
317
 * (copied from pkcs15-starcos.c).
318
 */
319
static int have_onepin(sc_profile_t *profile)
320
0
{
321
0
        sc_pkcs15_auth_info_t sopin = {0};
322
323
0
        sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
324
325
0
        if (!(sopin.attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN))
326
0
                return 1;
327
0
        else
328
0
                return 0;
329
0
}
330
331
332
/* create PIN and, if specified, PUK files
333
 * @param  profile  profile information for this card
334
 * @param  card     sc_card_t object to use
335
 * @param  pin_obj  sc_pkcs15_object_t for the PIN
336
 * @param  pin      PIN value
337
 * @param  len_len  PIN length
338
 * @param  puk      PUK value (optional)
339
 * @param  puk_len  PUK length (optional)
340
 * @return SC_SUCCESS on success and an error code otherwise
341
 */
342
static int asepcos_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
343
  sc_file_t *df, sc_pkcs15_object_t *pin_obj,
344
  const u8 *pin, size_t pin_len, const u8 *puk, size_t puk_len)
345
0
{
346
0
  sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data;
347
0
  struct sc_card *card = p15card->card;
348
0
  int       r, pid, puk_id;
349
0
  sc_path_t tpath = df->path;
350
0
  sc_file_t *tfile = NULL;
351
0
  sc_context_t *ctx = p15card->card->ctx;
352
353
0
  LOG_FUNC_CALLED(ctx);
354
0
  if (!pin || !pin_len)
355
0
    return SC_ERROR_INVALID_ARGUMENTS;
356
357
0
  if (auth_info == NULL || auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
358
0
          return SC_ERROR_OBJECT_NOT_VALID;
359
360
0
  pid = (auth_info->attrs.pin.reference & 0xff) | (int)(((tpath.len >> 1) - 1) << 16);
361
362
  /* get the ACL of the application DF */
363
0
  r = sc_select_file(card, &df->path, &tfile);
364
0
  if (r != SC_SUCCESS)
365
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
366
  /* verify the PIN protecting the CREATE acl (if necessary) */
367
0
  r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_CREATE);
368
0
  sc_file_free(tfile);
369
0
  if (r != SC_SUCCESS) {
370
0
    sc_log(card->ctx,  "unable to create PIN file, insufficient rights");
371
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
372
0
  }
373
374
0
  do {
375
0
    sc_path_t pin_path;
376
0
    memset(&pin_path, 0, sizeof(sc_path_t));
377
0
    pin_path.type = SC_PATH_TYPE_FILE_ID;
378
    /* XXX: check the pkcs15 structure whether this file id
379
     * is already used */
380
0
    r = sc_append_file_id(&pin_path, pid & 0xff);
381
0
    if (r != SC_SUCCESS)
382
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
383
0
    r = sc_select_file(card, &pin_path, NULL);
384
0
    if (r == SC_SUCCESS)
385
0
      pid += 2;
386
0
    else if (r != SC_ERROR_FILE_NOT_FOUND) {
387
0
      sc_log(card->ctx,  "error selecting PIN file");
388
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
389
0
    }
390
0
  } while (r != SC_ERROR_FILE_NOT_FOUND);
391
392
0
  if (puk != NULL && puk_len != 0) {
393
    /* Create PUK (if specified). Note: we need to create the PUK
394
     * the PIN as the PUK fileid is used in the PIN acl.
395
     */
396
0
    struct sc_pkcs15_auth_info puk_ainfo = {0};
397
398
0
    if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
399
0
      sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PUK, &puk_ainfo);
400
0
    else
401
0
      sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &puk_ainfo);
402
403
    /* If a PUK we use "file id of the PIN" + 1  as the file id
404
     * of the PUK.
405
     */
406
0
    puk_id = pid + 1;
407
0
    r = asepcos_do_store_pin(profile, card, &puk_ainfo, puk, puk_len, 0, puk_id);
408
0
    if (r != SC_SUCCESS)
409
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
410
0
  } else
411
0
    puk_id = 0;
412
413
0
  r = asepcos_do_store_pin(profile, card, auth_info, pin, pin_len, puk_id, pid);
414
0
  if (r != SC_SUCCESS)
415
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
416
417
0
#if 1
418
0
  if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN ||
419
0
      (have_onepin(profile) && pid == 0x010001)) {
420
0
    sc_cardctl_asepcos_activate_file_t st;
421
    /* Once the SO PIN or ,in case of the "onepin" profile", the
422
     * first USER PIN has been set we can tighten the ACLs of
423
     * the application DF.
424
     */
425
0
    sc_log(card->ctx,  "finalizing application DF");
426
0
    r = sc_select_file(card, &df->path, NULL);
427
0
    if (r != SC_SUCCESS)
428
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
429
    /* remove symbolic references from the ACLs */
430
0
    r = sc_pkcs15init_fixup_file(profile, p15card, df);
431
0
    if (r != SC_SUCCESS)
432
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
433
0
    r = sc_card_ctl(card, SC_CARDCTL_ASEPCOS_SET_SATTR, df);
434
0
    if (r != SC_SUCCESS) {
435
0
      sc_log(card->ctx,  "unable to change the security attributes");
436
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
437
0
    }
438
    /* finally activate the application DF (fix ACLs) */
439
    /* 1. select MF */
440
0
    r = sc_select_file(card, sc_get_mf_path(), NULL);
441
0
    if (r != SC_SUCCESS)
442
0
      return r;
443
    /* 2. activate the application DF */
444
0
    st.fileid = df->id;
445
0
    st.is_ef  = 0;
446
0
    r = sc_card_ctl(card, SC_CARDCTL_ASEPCOS_ACTIVATE_FILE, &st);
447
0
    if (r != SC_SUCCESS) {
448
0
      sc_log(card->ctx,  "unable to activate DF");
449
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
450
0
    }
451
0
  }
452
0
#endif
453
454
#ifdef asepcos_USE_PIN_PATH
455
  /* using the real path to the PIN file would be nice but unfortunately
456
   * it currently causes some problems with the keycache code
457
   */
458
  r = sc_append_file_id(&tpath, pid & 0xff);
459
  if (r != SC_SUCCESS)
460
    return r;
461
  auth_info->path = tpath;
462
#endif
463
0
  SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
464
0
}
465
466
/* internal wrapper for sc_pkcs15init_authenticate()
467
 * @param  profile  information for this card
468
 * @param  card     sc_card_t object to use
469
 * @param  path     path to the EF/DF for which the credential is required
470
 * @param  op       the required access method
471
 * @return SC_SUCCESS on success and an error code otherwise
472
 */
473
static int asepcos_do_authenticate(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
474
  const sc_path_t *path, int op)
475
0
{
476
0
  int r;
477
0
  sc_file_t *prkey = NULL;
478
0
  r = sc_profile_get_file_by_path(profile, path, &prkey);
479
0
  if (r != SC_SUCCESS) {
480
0
    sc_log(p15card->card->ctx,  "unable to find file in profile");
481
0
    return r;
482
0
  }
483
484
0
  r = sc_pkcs15init_authenticate(profile, p15card, prkey, op);
485
0
  sc_file_free(prkey);
486
0
  if (r != SC_SUCCESS) {
487
0
    sc_log(p15card->card->ctx,  "unable to authenticate");
488
0
    return r;
489
0
  }
490
0
  return SC_SUCCESS;
491
0
}
492
493
494
0
#define SET_TLV_LENGTH(p,l) do { \
495
0
          if ((l) < 128) \
496
0
            *(p)++ = (l) & 0x7f; \
497
0
          else if ((l) < 256) { \
498
0
            *(p)++ = 0x81; \
499
0
            *(p)++ = (l) & 0xff; \
500
0
          } else { \
501
0
            *(p)++ = 0x82; \
502
0
            *(p)++ = ((l) >> 8 ) & 0xff; \
503
0
            *(p)++ = (l) & 0xff; \
504
0
          } \
505
0
        } while(0)
506
507
static int asepcos_do_create_key(sc_card_t *card, size_t ksize, int fileid,
508
  const u8 *keydata, size_t kdlen)
509
0
{
510
0
  int       r;
511
0
  size_t    len;
512
0
  sc_file_t *nfile = NULL;
513
0
  u8        buf[1024], *p = buf;
514
515
0
  if (sizeof(buf) < kdlen + 12)
516
0
    return SC_ERROR_BUFFER_TOO_SMALL;
517
518
0
  *p++ = 0x85;
519
0
  *p++ = 0x82;
520
0
  p   += 2;
521
  /* file id */
522
0
  *p++ = (fileid >> 8) & 0xff;
523
0
  *p++ = fileid & 0xff;
524
  /* key size */
525
0
  *p++ = (ksize >> 8) & 0xff;
526
0
  *p++ = ksize & 0xff;
527
  /* max attempts */
528
0
  *p++ = 0x03;
529
  /* key attributes */
530
0
  *p++ = 0xc0;
531
0
  *p++ = 0x80;
532
0
  *p++ = 0x00;
533
  /* key parts */
534
0
  memcpy(p, keydata, kdlen);
535
0
  p   += kdlen;
536
  /* set outer TLV length */
537
0
  len = p - buf - 4;
538
0
  buf[2] = (len >> 8) & 0xff;
539
0
  buf[3] = len & 0xff;
540
541
0
  nfile = sc_file_new();
542
0
  if (nfile == NULL)
543
0
    return SC_ERROR_OUT_OF_MEMORY;
544
0
  nfile->type = SC_FILE_TYPE_INTERNAL_EF;
545
0
  nfile->id   = fileid & 0xffff;
546
0
  r = sc_file_set_prop_attr(nfile, buf, p - buf);
547
0
  if (r != SC_SUCCESS) {
548
0
    sc_log(card->ctx,  "unable to set key prop. attributes");
549
0
    sc_file_free(nfile);
550
0
    return r;
551
0
  }
552
553
0
  r = sc_create_file(card, nfile);
554
0
  sc_file_free(nfile);
555
0
  if (r != SC_SUCCESS) {
556
0
    sc_log(card->ctx,  "unable to create key file");
557
0
    return r;
558
0
  }
559
0
  return r;
560
0
}
561
562
/* creates a key file
563
 */
564
static int asepcos_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
565
  sc_pkcs15_object_t *obj)
566
0
{
567
0
  sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
568
0
  int       r;
569
0
  size_t    len;
570
0
  u8        buf[512], *p = buf;
571
0
  size_t    blen = kinfo->modulus_length / 8;
572
0
  int       afileid = -1,
573
0
            fileid = (kinfo->path.value[kinfo->path.len-2]) << 8 |
574
0
                     kinfo->path.value[kinfo->path.len-1];
575
576
0
  if (obj->auth_id.len != 0) {
577
    /* the key is protected by a PIN */
578
0
    sc_pkcs15_object_t *pin;
579
0
    struct sc_pkcs15_auth_info *auth_info;
580
0
    sc_cardctl_asepcos_akn2fileid_t st;
581
582
0
    r = sc_pkcs15_find_pin_by_auth_id(p15card, &obj->auth_id, &pin);
583
0
    if (r != SC_SUCCESS) {
584
0
      sc_log(p15card->card->ctx,  "unable to determine reference for the PIN");
585
0
      return r;
586
0
    }
587
588
0
    auth_info = (struct sc_pkcs15_auth_info *)pin->data;
589
590
0
    st.akn = auth_info->attrs.pin.reference;
591
0
    r = sc_card_ctl(p15card->card, SC_CARDCTL_ASEPCOS_AKN2FILEID, &st);
592
0
    if (r != SC_SUCCESS) {
593
0
      sc_log(p15card->card->ctx,  "unable to determine file id of the PIN");
594
0
      return r;
595
0
    }
596
0
    afileid = st.fileid;
597
0
  }
598
599
  /* authenticate if necessary */
600
0
  r = asepcos_do_authenticate(profile, p15card, &profile->df_info->file->path, SC_AC_OP_CREATE);
601
0
  if (r != SC_SUCCESS)
602
0
    return r;
603
604
  /* first: create private key (file id = 0x0100 | <ref & 0xff>) */
605
  /* key parts */
606
0
  *p++ = 0xc1;
607
0
  *p++ = 0x82;
608
0
  p   += 2;
609
  /* public exponent */
610
0
  *p++ = 0x90;
611
0
  SET_TLV_LENGTH(p, 3);
612
0
  memset(p, 0xff, 3);
613
0
  p   += 3;
614
  /* primes p, q */
615
0
  *p++ = 0x93;
616
0
  SET_TLV_LENGTH(p, blen);
617
0
  memset(p, 0xff, blen);
618
0
  p += blen;
619
620
  /* key TLV length */
621
0
  len = p - buf - 4;
622
0
  buf[2] = (len >> 8) & 0xff;
623
0
  buf[3] = len & 0xff;
624
625
  /* security attributes */
626
0
  *p++ = 0x80;
627
0
  *p++ = 0x01;
628
0
  *p++ = 0xa2;    /* compute signature and generate key pair */
629
0
  if (afileid > 0) {
630
0
    *p++ = 0xa0;
631
0
    *p++ = 0x05;
632
0
    *p++ = 0x89;
633
0
    *p++ = 0x03;
634
0
    *p++ = (afileid >> 16) & 0xff;
635
0
    *p++ = (afileid >> 8 ) & 0xff;
636
0
    *p++ = afileid & 0xff;
637
0
  } else {
638
0
    *p++ = 0x90;
639
0
    *p++ = 0x00;
640
0
  }
641
642
0
  r = asepcos_do_create_key(p15card->card, kinfo->modulus_length, fileid, buf, p - buf);
643
0
  if (r != SC_SUCCESS) {
644
0
    sc_log(p15card->card->ctx,  "unable to create private key file");
645
0
    return r;
646
0
  }
647
648
0
  kinfo->key_reference = fileid & 0xFF;
649
0
  return r;
650
0
}
651
652
/* stores a rsa private key in a internal EF
653
 */
654
static int asepcos_do_store_rsa_key(sc_pkcs15_card_t *p15card, sc_profile_t *profile,
655
  sc_pkcs15_object_t *obj, sc_pkcs15_prkey_info_t *kinfo,
656
  struct sc_pkcs15_prkey_rsa *key)
657
0
{
658
0
  int       r;
659
0
  size_t    klen;
660
0
  u8        buf[512], *p = buf;
661
0
  sc_path_t tpath;
662
0
  sc_cardctl_asepcos_change_key_t ckdata;
663
664
  /* authenticate if necessary */
665
0
  if (obj->auth_id.len != 0) {
666
0
    r = asepcos_do_authenticate(profile, p15card, &kinfo->path, SC_AC_OP_UPDATE);
667
0
    if (r != SC_SUCCESS)
668
0
      return r;
669
0
  }
670
671
  /* select the rsa private key */
672
0
  memset(&tpath, 0, sizeof(sc_path_t));
673
0
  tpath.type = SC_PATH_TYPE_FILE_ID;
674
0
  tpath.len  = 2;
675
0
  tpath.value[0] = kinfo->path.value[kinfo->path.len-2];
676
0
  tpath.value[1] = kinfo->path.value[kinfo->path.len-1];
677
0
  r = sc_select_file(p15card->card, &tpath, NULL);
678
0
  if (r != SC_SUCCESS) {
679
0
    sc_log(p15card->card->ctx,  "unable to select rsa key file");
680
0
    return r;
681
0
  }
682
683
  /* store key parts in buffer */
684
0
  *p++ = 0xc1;
685
0
  *p++ = 0x82;
686
0
  p   += 2;
687
  /* public exponent */
688
0
  *p++ = 0x90;
689
0
  SET_TLV_LENGTH(p, key->exponent.len);
690
0
  memcpy(p, key->exponent.data, key->exponent.len);
691
0
  p   += key->exponent.len;
692
  /* primes p, q */
693
0
  *p++ = 0x93;
694
0
  SET_TLV_LENGTH(p, (key->p.len + key->q.len));
695
0
  memcpy(p, key->p.data, key->p.len);
696
0
  p += key->p.len;
697
0
  memcpy(p, key->q.data, key->q.len);
698
0
  p += key->q.len;
699
700
  /* key TLV length */
701
0
  klen = p - buf - 4;
702
0
  buf[2] = (klen >> 8) & 0xff;
703
0
  buf[3] = klen & 0xff;
704
705
0
  ckdata.data    = buf;
706
0
  ckdata.datalen = p - buf;
707
708
0
  r = sc_card_ctl(p15card->card, SC_CARDCTL_ASEPCOS_CHANGE_KEY, &ckdata);
709
0
  if (r != SC_SUCCESS) {
710
0
    sc_log(p15card->card->ctx,  "unable to change key data");
711
0
    return r;
712
0
  }
713
714
0
  return SC_SUCCESS;
715
0
}
716
717
/* Stores an external (RSA) on the card.
718
 * @param  profile  profile information for this card
719
 * @param  card     sc_card_t object to use
720
 * @param  obj      sc_pkcs15_object_t object with pkcs15 information
721
 * @param  key      the private key
722
 * @return SC_SUCCESS on success and an error code otherwise
723
 */
724
static int asepcos_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
725
  sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key)
726
0
{
727
0
  sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
728
729
0
  if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
730
0
    sc_log(p15card->card->ctx,  "only RSA is currently supported");
731
0
    return SC_ERROR_NOT_SUPPORTED;
732
0
  }
733
734
0
  return asepcos_do_store_rsa_key(p15card, profile, obj, kinfo, &key->u.rsa);
735
0
}
736
737
/* Generates a new (RSA) key pair using an existing key file.
738
 * @param  profile  IN profile information for this card
739
 * @param  card     IN sc_card_t object to use
740
 * @param  obj      IN sc_pkcs15_object_t object with pkcs15 information
741
 * @param  pukkey   OUT the newly created public key
742
 * @return SC_SUCCESS on success and an error code otherwise
743
 */
744
static int asepcos_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
745
  sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey)
746
0
{
747
0
  int r;
748
0
  sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
749
0
  sc_card_t *card = p15card->card;
750
0
  sc_apdu_t apdu;
751
0
  sc_path_t tpath;
752
0
  u8  rbuf[SC_MAX_APDU_BUFFER_SIZE],
753
0
      sbuf[SC_MAX_APDU_BUFFER_SIZE];
754
755
  /* authenticate if necessary */
756
0
  r = asepcos_do_authenticate(profile, p15card, &kinfo->path, SC_AC_OP_UPDATE);
757
0
  if (r != SC_SUCCESS)
758
0
    return r;
759
760
  /* select the rsa private key */
761
0
  memset(&tpath, 0, sizeof(sc_path_t));
762
0
  tpath.type = SC_PATH_TYPE_FILE_ID;
763
0
  tpath.len  = 2;
764
0
  tpath.value[0] = kinfo->path.value[kinfo->path.len-2];
765
0
  tpath.value[1] = kinfo->path.value[kinfo->path.len-1];
766
0
  r = sc_select_file(card, &tpath, NULL);
767
0
  if (r != SC_SUCCESS) {
768
0
    sc_log(card->ctx,  "unable to select rsa key file");
769
0
    return r;
770
0
  }
771
772
0
  sbuf[0] = 0x01;
773
0
  sbuf[1] = 0x00;
774
0
  sbuf[2] = 0x01;
775
776
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x46, 0x00, 0x00);
777
0
  apdu.lc      = 3;
778
0
  apdu.datalen = 3;
779
0
  apdu.data    = sbuf;
780
0
  apdu.le      = 256;
781
0
  apdu.resplen = sizeof(rbuf);
782
0
  apdu.resp    = rbuf;
783
784
0
  r = sc_transmit_apdu(card, &apdu);
785
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
786
0
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) {
787
0
    sc_log(card->ctx,  "error creating key");
788
0
    return SC_ERROR_INTERNAL;
789
0
  }
790
791
0
  pubkey->u.rsa.modulus.len  = apdu.resplen;
792
0
  pubkey->u.rsa.modulus.data = malloc(apdu.resplen);
793
0
  if (pubkey->u.rsa.modulus.data == NULL)
794
0
    return SC_ERROR_OUT_OF_MEMORY;
795
0
  memcpy(pubkey->u.rsa.modulus.data, apdu.resp, apdu.resplen);
796
797
0
  pubkey->u.rsa.exponent.len  = 3;
798
0
  pubkey->u.rsa.exponent.data = malloc(3);
799
0
  if (pubkey->u.rsa.exponent.data == NULL)
800
0
    return SC_ERROR_OUT_OF_MEMORY;
801
0
  memcpy(pubkey->u.rsa.exponent.data, sbuf, 3);
802
803
0
  kinfo->key_reference = tpath.value[1];
804
0
  return SC_SUCCESS;
805
0
}
806
807
808
static struct sc_pkcs15init_operations sc_pkcs15init_asepcos_operations = {
809
  asepcos_erase,
810
  NULL,       /* init_card */
811
  asepcos_create_dir,
812
  NULL,       /* create_domain */
813
  asepcos_select_pin_reference,
814
  asepcos_create_pin,
815
  NULL,       /* select key reference */
816
  asepcos_create_key,
817
  asepcos_store_key,
818
  asepcos_generate_key,
819
  NULL, NULL,       /* encode private/public key */
820
  NULL,       /* finalize_card */
821
  NULL,         /* delete_object */
822
  NULL, NULL, NULL, NULL, NULL,   /* pkcs15init emulation */
823
  NULL        /* sanity_check */
824
};
825
826
struct sc_pkcs15init_operations * sc_pkcs15init_get_asepcos_ops(void)
827
0
{
828
0
  return &sc_pkcs15init_asepcos_operations;
829
0
}