Coverage Report

Created: 2025-10-13 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/pkcs15init/pkcs15-starcos.c
Line
Count
Source
1
/*
2
 * Starcos SPK 2.3 specific operation for PKCS15 initialization
3
 *
4
 * Copyright (C) 2004 Nils Larsch <larsch@trustcenter.de>
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#include "config.h"
22
23
#include <sys/types.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <assert.h>
27
#include <stdarg.h>
28
29
#include "libopensc/log.h"
30
#include "libopensc/opensc.h"
31
#include "libopensc/cardctl.h"
32
#include "pkcs15-init.h"
33
#include "profile.h"
34
35
0
#define STARCOS_AC_NEVER  0x5f
36
0
#define STARCOS_AC_ALWAYS 0x9f
37
38
0
#define STARCOS_SOPIN_GID 0x01
39
0
#define STARCOS_SOPIN_STATE 0x01
40
0
#define STARCOS_SOPIN_GAC 0x01
41
0
#define STARCOS_SOPIN_LID 0x81
42
0
#define STARCOS_SOPIN_LAC 0x11;
43
44
static int starcos_finalize_card(sc_card_t *card);
45
46
static int starcos_erase_card(struct sc_profile *pro, sc_pkcs15_card_t *p15card)
47
0
{
48
0
  return sc_card_ctl(p15card->card, SC_CARDCTL_ERASE_CARD, NULL);
49
0
}
50
51
static u8 get_so_ac(const sc_file_t *file, unsigned int op,
52
  const sc_pkcs15_auth_info_t *auth, unsigned int def,
53
  unsigned int need_global)
54
0
{
55
0
  int is_global = 1;
56
0
  const sc_acl_entry_t *acl;
57
58
0
  if (auth->attrs.pin.flags & SC_PKCS15_PIN_FLAG_LOCAL)
59
0
    is_global = 0;
60
0
  if (!is_global && need_global)
61
0
    return def & 0xff;
62
0
  acl = sc_file_get_acl_entry(file, op);
63
0
  if (acl->method == SC_AC_NONE)
64
0
    return STARCOS_AC_ALWAYS;
65
0
  else if (acl->method == SC_AC_NEVER)
66
0
    return STARCOS_AC_NEVER;
67
0
  else if (acl->method == SC_AC_SYMBOLIC) {
68
0
    if (is_global)
69
0
      return STARCOS_SOPIN_GAC;
70
0
    else
71
0
      return STARCOS_SOPIN_LAC;
72
0
  } else
73
0
    return def;
74
0
}
75
76
77
static int starcos_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card)
78
0
{
79
0
  struct sc_card *card = p15card->card;
80
0
  static const u8 key[]  = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
81
0
  int   ret;
82
0
  sc_starcos_create_data  mf_data, ipf_data;
83
0
  sc_file_t *mf_file, *isf_file, *ipf_file;
84
0
  sc_path_t tpath;
85
0
  u8    *p = mf_data.data.mf.header, tmp = 0;
86
0
  sc_pkcs15_auth_info_t sopin = {0};
87
88
  /* test if we already have a MF */
89
0
  memset(&tpath, 0, sizeof(sc_path_t));
90
0
  tpath.value[0] = 0x3f;
91
0
  tpath.value[1] = 0x00;
92
0
  tpath.len      = 2;
93
0
  tpath.type     = SC_PATH_TYPE_PATH;
94
0
  ret = sc_select_file(card, &tpath, NULL);
95
0
  if (ret == SC_SUCCESS)
96
    /* we already have a MF => return OK */
97
0
    return ret;
98
99
0
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
100
101
  /* get mf profile */
102
0
  ret = sc_profile_get_file(profile, "MF", &mf_file);
103
0
  if (ret < 0)
104
0
    return ret;
105
  /* get size of the isf */
106
0
  ret = sc_profile_get_file(profile, "mf_isf", &isf_file);
107
0
  if (ret < 0) {
108
0
    sc_file_free(mf_file);
109
0
    return ret;
110
0
  }
111
0
  mf_data.type = SC_STARCOS_MF_DATA;
112
0
  memcpy(p, key, 8);
113
0
  p   += 8;
114
0
  *p++ = (mf_file->size  >> 8) & 0xff;
115
0
  *p++ = mf_file->size  & 0xff;
116
0
  *p++ = (isf_file->size >> 8) & 0xff;
117
0
  *p++ = isf_file->size & 0xff;
118
  /* AC CREATE EF   */
119
0
  *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1);
120
  /* AC CREATE KEY  */
121
0
  *p++ = get_so_ac(isf_file, SC_AC_OP_WRITE, &sopin, STARCOS_AC_NEVER,  1);
122
  /* AC CREATE DF   */
123
0
  *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1);
124
  /* AC REGISTER DF */
125
0
  *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1);
126
0
  *p++ = 0x00;  /* SM CR:  no */
127
0
  *p++ = 0x00;  /* SM EF:  no */
128
0
  *p = 0x00;  /* SM ISF: no */
129
0
  sc_file_free(mf_file);
130
0
  sc_file_free(isf_file);
131
  /* call CREATE MF  */
132
0
  ret = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &mf_data);
133
0
  if (ret != SC_SUCCESS)
134
0
    return ret;
135
  /* create IPF */
136
  /* get size of the ipf */
137
0
  ret = sc_profile_get_file(profile, "mf_ipf", &ipf_file);
138
0
  if (ret < 0)
139
0
    return ret;
140
0
  ipf_data.type = SC_STARCOS_EF_DATA;
141
0
  p = ipf_data.data.ef.header;
142
0
  *p++ = (ipf_file->id >> 8) & 0xff;
143
0
  *p++ = ipf_file->id & 0xff;
144
0
  *p++ = STARCOS_AC_ALWAYS; /* AC READ: always */
145
  /* AC WRITE IPF */
146
0
  *p++ = get_so_ac(ipf_file,SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1);
147
0
  *p++ = STARCOS_AC_NEVER; /* AC ERASE    */
148
0
  *p++ = STARCOS_AC_NEVER; /* AC LOCK     */
149
0
  *p++ = STARCOS_AC_NEVER; /* AC UNLOCK   */
150
0
  *p++ = STARCOS_AC_NEVER; /* AC INCREASE */
151
0
  *p++ = STARCOS_AC_NEVER; /* AC_DECREASE */
152
0
  *p++ = STARCOS_AC_NEVER; /* RFU         */
153
0
  *p++ = STARCOS_AC_NEVER; /* RFU         */
154
0
  *p++ = 0x00;      /* SM          */
155
0
  *p++ = 0x00;      /* SID         */
156
0
  *p++ = 0xA1;      /* IPF         */
157
0
  *p++ = (ipf_file->size >> 8) & 0xff;
158
0
  *p = ipf_file->size & 0xff;
159
0
  ret  = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &ipf_data);
160
0
  if (ret != SC_SUCCESS) {
161
0
    sc_file_free(ipf_file);
162
0
    return ret;
163
0
  }
164
  /* init IPF */
165
0
  ret = sc_select_file(card, &ipf_file->path, NULL);
166
0
  sc_file_free(ipf_file);
167
0
  if (ret < 0)
168
0
    return ret;
169
0
  ret = sc_update_binary(card, 0, &tmp, 1, 0);
170
0
  if (ret < 0)
171
0
    return ret;
172
0
  return SC_SUCCESS;
173
0
}
174
175
static int starcos_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
176
  sc_file_t *df)
177
0
{
178
0
  struct sc_card *card = p15card->card;
179
0
  int             ret;
180
0
  sc_starcos_create_data df_data, ipf_data;
181
0
  sc_file_t *isf_file, *ipf_file;
182
0
  u8    *p = df_data.data.df.header, tmp = 0;
183
0
  sc_pkcs15_auth_info_t sopin = {0};
184
185
0
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
186
187
  /* get p15_isf profile */
188
0
  ret = sc_profile_get_file(profile, "p15_isf", &isf_file);
189
0
  if (ret < 0)
190
0
    return ret;
191
192
0
  df_data.type = SC_STARCOS_DF_DATA;
193
0
  memset(p, 0, 25);
194
0
  *p++ = (df->id >> 8) & 0xff;
195
0
  *p++ = df->id & 0xff;
196
0
  *p++ = df->namelen & 0xff;
197
0
  memcpy(p, df->name, (u8) df->namelen);
198
0
  p   += 16;
199
0
  *p++ = (isf_file->size >> 8) & 0xff;
200
0
  *p++ = isf_file->size & 0xff;
201
  /* AC CREATE EF  */
202
0
  *p++ = get_so_ac(df, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 0);
203
  /* AC CREATE KEY */
204
0
  *p++ = get_so_ac(isf_file, SC_AC_OP_WRITE, &sopin, STARCOS_AC_NEVER, 0);
205
0
  *p++ = 0x00;    /* SM EF:  no */
206
0
  *p = 0x00;    /* SM ISF: no */
207
0
  df_data.data.df.size[0] = (df->size >> 8) & 0xff;
208
0
  df_data.data.df.size[1] = df->size & 0xff;
209
0
  sc_file_free(isf_file);
210
  /* call CREATE DF  */
211
0
  ret = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &df_data);
212
0
  if (ret != SC_SUCCESS)
213
0
    return ret;
214
  /* create IPF */
215
0
  ret = sc_select_file(card, &df->path, NULL);
216
0
  if (ret != SC_SUCCESS)
217
0
    return ret;
218
0
  ret = sc_profile_get_file(profile, "p15_ipf", &ipf_file);
219
0
  if (ret < 0)
220
0
    return ret;
221
0
  ipf_data.type = SC_STARCOS_EF_DATA;
222
0
  p = ipf_data.data.ef.header;
223
0
  *p++ = (ipf_file->id >> 8) & 0xff;
224
0
  *p++ = ipf_file->id & 0xff;
225
0
  *p++ = STARCOS_AC_ALWAYS; /* AC READ     */
226
  /* AC WRITE IPF */
227
0
  *p++ = get_so_ac(ipf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 0);
228
0
  *p++ = STARCOS_AC_NEVER; /* AC ERASE    */
229
0
  *p++ = STARCOS_AC_NEVER; /* AC LOCK     */
230
0
  *p++ = STARCOS_AC_NEVER; /* AC UNLOCK   */
231
0
  *p++ = STARCOS_AC_NEVER; /* AC INCREASE */
232
0
  *p++ = STARCOS_AC_NEVER; /* AC_DECREASE */
233
0
  *p++ = STARCOS_AC_NEVER; /* RFU         */
234
0
  *p++ = STARCOS_AC_NEVER; /* RFU         */
235
0
  *p++ = 0x00;      /* SM          */
236
0
  *p++ = 0x00;      /* SID         */
237
0
  *p++ = 0xA1;      /* IPF         */
238
0
  *p++ = (ipf_file->size >> 8) & 0xff;
239
0
  *p = ipf_file->size & 0xff;
240
0
  ret  = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &ipf_data);
241
0
  if (ret != SC_SUCCESS) {
242
0
    sc_file_free(ipf_file);
243
0
    return ret;
244
0
  }
245
  /* init IPF */
246
0
  ret = sc_select_file(card, &ipf_file->path, NULL);
247
0
  sc_file_free(ipf_file);
248
0
  if (ret < 0)
249
0
    return ret;
250
0
  ret = sc_update_binary(card, 0, &tmp, 1, 0);
251
0
  if (ret < 0)
252
0
    return ret;
253
0
  return SC_SUCCESS;
254
0
}
255
256
static int have_onepin(sc_profile_t *profile)
257
0
{
258
0
  sc_pkcs15_auth_info_t sopin = {0};
259
260
0
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
261
262
0
  if (!(sopin.attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN))
263
0
    return 1;
264
0
  else
265
0
    return 0;
266
0
}
267
268
/* range of possible key ids for pins (note: the key id of the puk
269
 * is the key id of the pin plus one)
270
 */
271
0
#define STARCOS_MIN_LPIN_ID 0x83
272
0
#define STARCOS_MAX_LPIN_ID 0x8f
273
0
#define STARCOS_MIN_GPIN_ID 0x03
274
0
#define STARCOS_MAX_GPIN_ID 0x0f
275
static int starcos_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
276
  sc_pkcs15_auth_info_t *auth_info)
277
0
{
278
0
  int tmp;
279
280
0
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
281
0
    return SC_ERROR_OBJECT_NOT_VALID;
282
283
0
  tmp = auth_info->attrs.pin.reference;
284
285
0
  if (have_onepin(profile)) {
286
    /* we have the onepin profile */
287
0
    auth_info->attrs.pin.reference = STARCOS_SOPIN_GID;
288
0
    return SC_SUCCESS;
289
0
  }
290
291
0
  if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_LOCAL) {
292
    /* use local KID */
293
    /* SO-pin */
294
0
    if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
295
0
      tmp = STARCOS_SOPIN_LID;
296
0
    else {
297
0
      if (tmp < STARCOS_MIN_LPIN_ID)
298
0
        tmp = STARCOS_MIN_LPIN_ID;
299
0
      if (!(tmp & 0x01))
300
        /* odd KIDs for PINs and even KIDs for PUKs */
301
0
        tmp++;
302
0
      if (tmp > STARCOS_MAX_LPIN_ID)
303
0
        return SC_ERROR_TOO_MANY_OBJECTS;
304
0
    }
305
0
  } else {
306
    /* use global KID */
307
    /* SO-pin */
308
0
    if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
309
0
      tmp = STARCOS_SOPIN_GID;
310
0
    else {
311
0
      if (tmp < STARCOS_MIN_GPIN_ID)
312
0
        tmp = STARCOS_MIN_GPIN_ID;
313
0
      if (!(tmp & 0x01))
314
        /* odd KIDs for PINs and even KIDs for PUKs */
315
0
      tmp++;
316
0
      if (tmp > STARCOS_MAX_GPIN_ID)
317
0
        return SC_ERROR_TOO_MANY_OBJECTS;
318
0
    }
319
0
  }
320
0
  auth_info->attrs.pin.reference = tmp;
321
322
0
  return SC_SUCCESS;
323
0
}
324
325
/* About STARCOS_PINID2STATE
326
 * Starcos SPK 2.3 uses a state machine to control the access
327
 * to files or keys. This means that the access to a certain
328
 * object is granted if the current state (of either the current
329
 * DF or the MF) is =, <, >= or != a specified state (see
330
 * Starcos S 2.1 manual). To map the pkcs15 access control model
331
 *(one object is protected by one pin etc.) to the Starcos S 2.1
332
 * model the following approach is used:
333
 * the pin with the key id 3 (or 0x81) sets the global (or local)
334
 * state to 15 (note: 16 is the lowest initial state).
335
 * the pin with the key id 4 (or 0x82) is reserved for the PUK
336
 * the pin with the key id 5 (or 0x83) sets the global (or local)
337
 * state to 14.
338
 * ...
339
 * Note: the key id 1 and 2 (or local 0x81 and 0x82) is used for
340
 * the 'SO-pin' which sets the state to 0x01.
341
 * XXX: some card operations, like terminate card usage are only
342
 * possible in state 0x00
343
 *
344
 * Nils
345
 */
346
0
#define STARCOS_PINID2STATE(a)  (((a) == STARCOS_SOPIN_GID) ? STARCOS_SOPIN_STATE : (0x0f - ((0x0f & (a)) >> 1)))
347
348
static int starcos_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
349
  sc_file_t *df, sc_pkcs15_object_t *pin_obj,
350
  const unsigned char *pin, size_t pin_len,
351
  const unsigned char *puk, size_t puk_len)
352
0
{
353
0
  struct sc_card *card = p15card->card;
354
0
  int r, is_local, pin_id, tmp, need_finalize = 0;
355
0
  size_t  akd;
356
0
  sc_file_t            *tfile;
357
0
  const sc_acl_entry_t *acl_entry;
358
0
  sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data;
359
0
  sc_starcos_wkey_data  pin_d, puk_d;
360
0
  u8          tpin[8];
361
362
0
  if (!pin || !pin_len || pin_len > 8)
363
0
    return SC_ERROR_INVALID_ARGUMENTS;
364
365
0
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
366
0
    return SC_ERROR_OBJECT_NOT_VALID;
367
368
0
  is_local = 0x80 & auth_info->attrs.pin.reference;
369
0
  if (is_local)
370
0
    r = sc_select_file(card, &df->path, NULL);
371
0
  else
372
0
    r = sc_select_file(card, &profile->mf_info->file->path, NULL);
373
0
  if (r < 0)
374
0
    return r;
375
  /* get and verify sopin if necessary */
376
0
  r = sc_profile_get_file(profile, "p15_isf", &tfile);
377
0
        if (r < 0)
378
0
                return r;
379
0
  acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE);
380
0
  if (acl_entry->method != SC_AC_NONE) {
381
0
    if ((auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) || have_onepin(profile))
382
0
      need_finalize = 1;
383
0
    else
384
0
      r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE);
385
0
  }
386
0
  sc_file_free(tfile);
387
0
  if (r < 0)
388
0
    return r;
389
390
  /* pad pin with 0 */
391
0
  memset(tpin, 0, 8);
392
0
  memcpy(tpin, pin, pin_len);
393
394
  /* write PIN */
395
0
  tmp    = auth_info->tries_left;
396
0
  pin_id = auth_info->attrs.pin.reference;
397
398
0
  pin_d.mode    = 0;  /* install */
399
0
  pin_d.kid     = (u8) pin_id;
400
0
  pin_d.key     = tpin;
401
0
  pin_d.key_len = 8;
402
0
  pin_d.key_header[0]  = pin_d.kid;
403
0
  pin_d.key_header[1]  = 0;
404
0
  pin_d.key_header[2]  = 8;
405
0
  pin_d.key_header[3]  = STARCOS_AC_ALWAYS;
406
0
  if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
407
0
    pin_d.key_header[4] = STARCOS_SOPIN_STATE;
408
0
  else
409
0
    pin_d.key_header[4] = STARCOS_PINID2STATE(pin_id);
410
0
  pin_d.key_header[5]  = STARCOS_AC_ALWAYS;
411
0
  pin_d.key_header[6]  = ((0x0f & tmp) << 4) | (0x0f & tmp);
412
0
  pin_d.key_header[7]  = 0x00;
413
0
  pin_d.key_header[8]  = 0x00;
414
0
  akd = auth_info->attrs.pin.min_length;
415
0
  if (akd < 4)
416
0
    akd = 4;
417
0
  if (akd > 8)
418
0
    akd = 8;
419
0
  akd--;
420
0
  akd |= 0x08;
421
0
  pin_d.key_header[9]  = akd; /* AKD: standard + every char != 0 +
422
           * pin min length */
423
0
  pin_d.key_header[10] = 0x00;  /* never allow WRITE KEY    */
424
0
  pin_d.key_header[11] = 0x81;  /* key attribute: akd + pin */
425
  /* create/write PIN */
426
0
  r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &pin_d);
427
0
  if (r != SC_SUCCESS)
428
0
    return r;
429
430
0
  if (puk && puk_len) {
431
0
    sc_pkcs15_auth_info_t puk_info = {0};
432
433
0
    if (puk_len > 8)
434
0
      return SC_ERROR_INVALID_ARGUMENTS;
435
0
    memset(tpin, 0, 8);
436
0
    memcpy(tpin, puk, puk_len);
437
438
0
    sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &puk_info);
439
0
    tmp = puk_info.tries_left;
440
441
0
    puk_d.mode    = 0;  /* install */
442
0
    puk_d.kid     = (u8) pin_id + 1;
443
0
    puk_d.key     = tpin;
444
0
    puk_d.key_len = 8;
445
0
    puk_d.key_header[0]  = puk_d.kid;
446
0
    puk_d.key_header[1]  = 0;
447
0
    puk_d.key_header[2]  = 8;
448
0
    puk_d.key_header[3]  = STARCOS_AC_ALWAYS;
449
0
    puk_d.key_header[4]  = ((pin_id & 0x1f) << 3) | 0x05;
450
0
    puk_d.key_header[5]  = 0x01;
451
0
    puk_d.key_header[6]  = ((0x0f & tmp) << 4) | (0x0f & tmp);
452
0
    puk_d.key_header[7]  = 0x0;
453
0
    puk_d.key_header[8]  = 0x0;
454
0
    puk_d.key_header[9]  = 0x0;
455
0
    puk_d.key_header[10] = 0x00;
456
0
    puk_d.key_header[11] = 0x02;
457
    /* create/write PUK */
458
0
    r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &puk_d);
459
0
    if (r != SC_SUCCESS)
460
0
      return r;
461
0
  }
462
463
  /* in case of a global pin: write dummy entry in df isf */
464
0
  if (!is_local) {
465
0
    r = sc_select_file(card, &df->path, NULL);
466
0
    if (r < 0)
467
0
      return r;
468
0
    pin_d.key     = NULL;
469
0
    pin_d.key_len = 0;
470
0
    pin_d.key_header[1] = 0;
471
0
    pin_d.key_header[2] = 0;
472
    /* create/write dummy PIN */
473
0
    r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &pin_d);
474
0
    if (r != SC_SUCCESS)
475
0
      return r;
476
0
  }
477
478
  /* in case of a SOPIN: if AC WRITE KEY is protected by the
479
   * SOPIN, call starcos_finalize_card to activate the ACs  */
480
0
  if (need_finalize)
481
0
     r = starcos_finalize_card(card);
482
483
0
  return r;
484
0
}
485
486
/* range of possible key ids for private keys
487
 */
488
0
#define STARCOS_MIN_LPKEY_ID  0x91
489
0
#define STARCOS_MAX_LPKEY_ID  0x9f
490
#define STARCOS_MIN_GPKEY_ID  0x11
491
#define STARCOS_MAX_GPKEY_ID  0x1f
492
static int starcos_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
493
  sc_pkcs15_prkey_info_t *prkey)
494
0
{
495
  /* use (local) KIDs 0x91-0x9f for private rsa keys */
496
0
  if (prkey->key_reference < STARCOS_MIN_LPKEY_ID)
497
0
    prkey->key_reference = STARCOS_MIN_LPKEY_ID;
498
0
  if (prkey->key_reference > STARCOS_MAX_LPKEY_ID)
499
0
    return SC_ERROR_TOO_MANY_OBJECTS;
500
0
  return SC_SUCCESS;
501
0
}
502
503
0
#define STARCOS_MAX_PR_KEYSIZE  370
504
505
static int starcos_encode_prkey(struct sc_pkcs15_prkey_rsa *rsa, u8 *buf)
506
0
{
507
0
  size_t  i = 0;
508
0
  u8  *p = buf;
509
510
  /* clear key buffer */
511
0
  memset(buf, 0, STARCOS_MAX_PR_KEYSIZE);
512
513
0
  if (rsa->p.len && rsa->q.len && rsa->dmp1.len &&
514
0
    rsa->dmq1.len && rsa->iqmp.len) {
515
    /* CRT RSA key     */
516
    /* get number of 0x00 bytes */
517
0
    i = STARCOS_MAX_PR_KEYSIZE - rsa->p.len - rsa->q.len -
518
0
        rsa->dmp1.len - rsa->dmq1.len - 45 - rsa->p.len;
519
520
    /* key format list */
521
0
    *p++ = 0x0c;
522
0
    *p++ = 0x91;
523
0
    *p++ = (u8) rsa->p.len;
524
0
    *p++ = 0x92;
525
0
    *p++ = (u8) rsa->q.len;
526
0
    *p++ = 0x94;
527
0
    *p++ = (u8) rsa->dmp1.len + 16;
528
0
    *p++ = 0x95;
529
0
    *p++ = (u8) rsa->dmq1.len + 16;
530
0
    *p++ = 0x97;
531
0
    *p++ = (u8) rsa->p.len;
532
0
    *p++ = 0x00;
533
0
    *p++ = (u8) i;
534
    /* copy key components */
535
0
    for (i = rsa->q.len; i != 0; i--)
536
0
      *p++ = rsa->q.data[i - 1];
537
0
    for (i = rsa->p.len; i != 0; i--)
538
0
      *p++ = rsa->p.data[i - 1];
539
0
    for (i = 16; i != 0; i--)
540
0
      *p++ = 0x00;
541
0
    for (i = rsa->dmp1.len; i != 0; i--)
542
0
      *p++ = rsa->dmq1.data[i - 1];
543
0
    for (i = 16; i != 0; i--)
544
0
      *p++ = 0x00;
545
0
    for (i = rsa->dmq1.len; i != 0; i--)
546
0
      *p++ = rsa->dmp1.data[i - 1];
547
0
    for (i = rsa->iqmp.len; i != 0; i--)
548
0
      *p++ = rsa->iqmp.data[i - 1];
549
0
    for (i = rsa->p.len - rsa->iqmp.len; i != 0; i--)
550
0
      *p++ = 0x00;
551
0
  } else if (rsa->modulus.len && rsa->d.len) {
552
    /* normal RSA key  */
553
0
    i = STARCOS_MAX_PR_KEYSIZE - 7 - rsa->modulus.len
554
0
                    - rsa->d.len - 16;
555
    /* key format list */
556
0
    *p++ = 6;
557
0
    *p++ = 0x90;
558
0
    *p++ = (u8) rsa->modulus.len;
559
0
    *p++ = 0x93;
560
0
    *p++ = (u8) rsa->d.len + 16;
561
0
    *p++ = 0x00;
562
0
    *p++ = (u8) i;
563
    /* copy key components */
564
0
    for (i = rsa->modulus.len; i != 0; i--)
565
0
      *p++ = rsa->modulus.data[i - 1];
566
0
    for (i = 16; i != 0; i--)
567
0
      *p++ = 0x00;
568
0
    for (i = rsa->d.len; i != 0; i--)
569
0
      *p++ = rsa->d.data[i - 1];
570
0
  } else
571
0
    return SC_ERROR_INTERNAL;
572
573
0
  return SC_SUCCESS;
574
0
}
575
576
/* XXX the whole IPF stuff doesn't really work very well */
577
/** starcos_ipf_get_lastpos
578
 * returns the offset to the first byte after the last key
579
 */
580
static size_t starcos_ipf_get_lastpos(u8 *ipf, size_t ipf_len)
581
0
{
582
0
  size_t  num_keys, tmp;
583
0
  u8  *p = ipf;
584
585
0
  if (!ipf || ipf_len < 13)
586
0
    return 0;
587
0
  num_keys = *p++; /* the first bytes contains the number of keys*/
588
0
  if (num_keys == 0xff)
589
0
    num_keys = 0;
590
0
  if (!num_keys)
591
0
    return 1;
592
0
  while (num_keys--) {
593
0
    size_t offset = p - ipf;  /* note: p > ipf */
594
    /* get offset to the next key header */
595
0
    tmp = 12 + (p[1] << 8) + p[2];
596
0
    if (tmp + offset > ipf_len)
597
0
      return 0;
598
0
    p += tmp;
599
0
  }
600
601
0
  return p - ipf;
602
0
}
603
604
static int starcos_encode_pukey(struct sc_pkcs15_prkey_rsa *rsa, u8 *buf,
605
  sc_pkcs15_prkey_info_t *kinfo)
606
0
{
607
0
  size_t  i = 0;
608
0
  u8  *p = buf;
609
610
  /* if rsa == NULL return key header for key generation    */
611
0
  if (!rsa) {
612
0
    if (!buf)
613
      /* if buf == NULL return length of the encoded key */
614
0
      return 12 + (int)(kinfo->modulus_length >> 3);
615
0
    *p++ = 0x06;      /* length key header */
616
0
    *p++ = 0x01;      /* CHA byte */
617
0
    *p++ = 0x01;
618
0
    *p++ = 0x10;      /* RSA: n   */
619
0
    *p++ = (kinfo->modulus_length >> 3) & 0xff;
620
0
    *p++ = 0x13;      /* RSA: e   */
621
0
    *p++ = 0x04;
622
0
    *p = (u8) kinfo->key_reference; /* CHA byte */
623
0
  } else {
624
    /* encode normal public key  */
625
0
    int mod_len = (int)rsa->modulus.len  & 0xff,
626
0
      exp_len = (int)rsa->exponent.len & 0xff;
627
628
0
    if (!buf)
629
0
      return 8 + mod_len + exp_len + 1;
630
631
0
    *p++ = 0x06;      /* length key header */
632
0
    *p++ = 0x01;      /* CHA byte */
633
0
    *p++ = 0x01;
634
0
    *p++ = 0x10;      /* RSA: n   */
635
0
    *p++ = mod_len;
636
0
    *p++ = 0x13;      /* RSA: e   */
637
0
    *p++ = exp_len + 1;
638
0
    *p++ = (u8) kinfo->key_reference; /* CHA byte */
639
    /* copy modulus  */
640
0
    for (i = mod_len; i != 0; i--)
641
0
      *p++ = rsa->modulus.data[i - 1];
642
    /* copy exponent */
643
0
    for (i = exp_len; i != 0; i--)
644
0
      *p++ = rsa->exponent.data[i - 1];
645
0
    *p = 0x00;
646
0
  }
647
0
  return SC_SUCCESS;
648
0
}
649
650
static int starcos_write_pukey(sc_profile_t *profile, sc_card_t *card,
651
   struct sc_pkcs15_prkey_rsa *rsa, sc_pkcs15_prkey_info_t *kinfo)
652
0
{
653
0
  int   r;
654
0
  size_t    len, keylen, endpos;
655
0
  u8    *buf, key[280], *p, num_keys;
656
0
  sc_file_t *tfile = NULL;
657
0
  sc_path_t tpath;
658
659
  /* get ipf profile */
660
0
  tpath = kinfo->path;
661
0
  r = sc_profile_get_file_in(profile, &tpath, "p15_ipf", &tfile);
662
0
  if (r < 0)
663
0
    return r;
664
0
  tpath = tfile->path;
665
0
  sc_file_free(tfile);
666
0
  tfile = NULL;
667
0
  r = sc_select_file(card, &tpath, &tfile);
668
0
  if (r != SC_SUCCESS)
669
    /* unable to select ipf */
670
0
    return r;
671
0
  len = tfile->size;
672
0
  sc_file_free(tfile);
673
0
  if (len == 0)
674
0
    return SC_ERROR_INTERNAL;
675
0
  buf = malloc(len);
676
0
  if (!buf)
677
0
    return SC_ERROR_OUT_OF_MEMORY;
678
  /* read the complete IPF */
679
0
  r = sc_read_binary(card, 0, buf, len, 0);
680
0
  if (r < 0 || r != (int)len) {
681
0
    free(buf);
682
0
    return r;
683
0
  }
684
  /* get/fix number of keys */
685
0
  num_keys = buf[0];
686
0
  if (num_keys == 0xff)
687
0
    num_keys = 0;
688
  /* encode public key */
689
0
  keylen = starcos_encode_pukey(rsa, NULL, kinfo);
690
0
  if (!keylen) {
691
0
    free(buf);
692
0
    return SC_ERROR_INTERNAL;
693
0
  }
694
0
  p = key;
695
0
  *p++ = (u8) kinfo->key_reference;
696
0
  *p++ = (keylen >> 8) & 0xff;
697
0
  *p++ = keylen & 0xff;
698
0
  *p++ = STARCOS_AC_ALWAYS; /* AC WRITE etc XXX */
699
0
  *p++ = 0x0f;
700
0
  *p++ = 0;
701
0
  *p++ = 0x09;      /* ALGO XXX */
702
0
  *p++ = 0x4a;      /* AKD  XXX */
703
0
  *p++ = ((keylen >> 8) & 0xff) | 0x80;
704
0
  *p++ = keylen & 0xff;
705
0
  r = starcos_encode_pukey(rsa, p, kinfo);
706
0
  if (r != SC_SUCCESS) {
707
0
    free(buf);
708
0
    return SC_ERROR_INTERNAL;
709
0
  }
710
0
  p   += keylen;
711
0
  *p++ = 0x04;        /* CPI */
712
0
  *p = (u8) kinfo->key_reference; /* CHA */
713
  /* updated IPF (XXX: currently append only) */
714
0
  num_keys++;
715
0
  r = sc_update_binary(card, 0, &num_keys, 1, 0);
716
0
  if (r < 0) {
717
0
    free(buf);
718
0
    return r;
719
0
  }
720
0
  endpos = starcos_ipf_get_lastpos(buf, len);
721
0
  free(buf);
722
0
  return sc_update_binary(card, (unsigned)endpos, key, keylen + 12, 0);
723
0
}
724
725
static int starcos_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
726
  sc_pkcs15_object_t *obj)
727
0
{
728
0
  struct sc_card *card = p15card->card;
729
0
  int r, pin_id;
730
0
  u8  akd = 0, state;
731
732
0
  sc_file_t              *tfile;
733
0
  const sc_acl_entry_t   *acl_entry;
734
0
  sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *)obj->data;
735
0
  sc_starcos_wkey_data    tkey;
736
737
  /* get and verify sopin if necessary */
738
0
  r = sc_profile_get_file(profile, "p15_isf", &tfile);
739
0
        if (r < 0)
740
0
                return r;
741
0
  acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE);
742
0
  if (acl_entry->method  != SC_AC_NONE) {
743
0
    r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE);
744
0
  }
745
0
  else   {
746
0
    r = sc_select_file(card, &tfile->path, NULL);
747
0
  }
748
0
  sc_file_free(tfile);
749
0
  if (r < 0)
750
0
    return r;
751
752
  /* create sc_starcos_wkey_data */
753
0
  tkey.mode    = 0x00;  /* install new key */
754
0
  tkey.kid     = (u8) kinfo->key_reference;
755
0
  tkey.key_header[0] = (u8) kinfo->key_reference;
756
0
  tkey.key_header[1] = (STARCOS_MAX_PR_KEYSIZE >> 8) & 0xff;
757
0
  tkey.key_header[2] = STARCOS_MAX_PR_KEYSIZE & 0xff;
758
759
0
  pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, SC_AC_SYMBOLIC,
760
0
      SC_PKCS15INIT_USER_PIN);
761
0
  if (pin_id < 0)
762
0
    state = STARCOS_AC_ALWAYS;
763
0
  else {
764
0
    state  = STARCOS_PINID2STATE(pin_id); /* get the necessary state */
765
0
    state |= pin_id & 0x80 ? 0x10 : 0x00; /* local vs. global key id */
766
0
  }
767
0
  tkey.key_header[3] = state;   /* AC to access key        */
768
0
  if (obj->user_consent)
769
0
    tkey.key_header[4] = 0x0f; /* do state transition */
770
0
  else
771
0
    tkey.key_header[4] = 0x8f; /* no state transition */
772
0
  tkey.key_header[5] = 0x11; /* require local state == 1 to update key */
773
0
  tkey.key_header[6] = 0x33;
774
0
  tkey.key_header[7] = 0x00;
775
0
  tkey.key_header[8] = 0x09;
776
0
  if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)
777
0
    akd |= 0x10;
778
0
  if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_SIGN)
779
0
    akd |= 0x31; /* allow DS, IA and PKCS11 */
780
0
  if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_SIGNRECOVER)
781
0
    akd |= 0x31; /* allow DS, IA and PKCS11 */
782
0
  if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_DECRYPT ||
783
0
      kinfo->usage & SC_PKCS15_PRKEY_USAGE_UNWRAP)
784
0
    akd |= 0x02;
785
0
  tkey.key_header[9]  = akd;
786
0
  tkey.key_header[10] = 0x03;
787
0
  tkey.key_header[11] = 0xa0;
788
0
  tkey.key     = NULL;
789
0
  tkey.key_len = 0;
790
791
0
  return sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &tkey);
792
0
}
793
794
static int starcos_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
795
  sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key)
796
0
{
797
0
  int     r;
798
0
  u8  key_buf[STARCOS_MAX_PR_KEYSIZE];
799
800
0
  sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
801
0
  const sc_acl_entry_t   *acl_entry;
802
0
  sc_file_t              *tfile;
803
0
  struct sc_pkcs15_prkey_rsa *rsa = &key->u.rsa;
804
0
  sc_starcos_wkey_data tkey;
805
806
0
  if (key->algorithm != SC_ALGORITHM_RSA)
807
    /* ignore non-RSA keys */
808
0
    return SC_ERROR_INVALID_ARGUMENTS;
809
810
  /* create sc_starcos_wkey_data */
811
0
  if (starcos_encode_prkey(rsa, key_buf))
812
0
    return SC_ERROR_INTERNAL;
813
814
  /* get and verify sopin if necessary */
815
0
  r = sc_profile_get_file(profile, "p15_isf", &tfile);
816
0
        if (r < 0)
817
0
                return r;
818
0
  acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE);
819
0
  if (acl_entry->method  != SC_AC_NONE) {
820
0
    r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE);
821
0
  }
822
0
  sc_file_free(tfile);
823
0
  if (r < 0)
824
0
    return r;
825
826
0
  tkey.mode    = 0x01;  /* update key */
827
0
  tkey.kid     = (u8) kinfo->key_reference;
828
0
  tkey.key     = key_buf;
829
0
  tkey.key_len = STARCOS_MAX_PR_KEYSIZE;
830
831
0
  r = sc_card_ctl(p15card->card, SC_CARDCTL_STARCOS_WRITE_KEY, &tkey);
832
0
  if (r != SC_SUCCESS)
833
0
    return r;
834
  /* store public key in the IPF */
835
0
  return starcos_write_pukey(profile, p15card->card, rsa, kinfo);
836
0
}
837
838
static int starcos_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
839
    sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey)
840
0
{
841
0
  int r;
842
0
  const sc_acl_entry_t   *acl_entry;
843
0
  sc_file_t              *tfile;
844
0
  sc_starcos_gen_key_data gendat;
845
0
  sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
846
847
0
  if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA)
848
0
    return SC_ERROR_NOT_SUPPORTED;
849
850
  /* get and verify sopin if necessary */
851
0
  r = sc_profile_get_file(profile, "p15_isf", &tfile);
852
0
        if (r < 0)
853
0
                return r;
854
0
  acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE);
855
0
  if (acl_entry->method  != SC_AC_NONE) {
856
0
    r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE);
857
0
  }
858
0
  sc_file_free(tfile);
859
0
  if (r < 0)
860
0
    return r;
861
862
  /* XXX It would be better to write the public key header
863
   * in the IPF when the private key header is created, but
864
   * as we don't know the size of the exponent at this time
865
   * we would waste space.
866
   */
867
  /* create (empty) public key entry */
868
0
  r = starcos_write_pukey(profile, p15card->card, NULL, kinfo);
869
0
  if (r < 0)
870
0
    return r;
871
  /* generate key pair */
872
0
  gendat.key_id     = (u8) kinfo->key_reference;
873
0
  gendat.key_length = (size_t) kinfo->modulus_length;
874
0
  gendat.modulus    = NULL;
875
0
  r = sc_card_ctl(p15card->card, SC_CARDCTL_STARCOS_GENERATE_KEY, &gendat);
876
0
  if (r != SC_SUCCESS)
877
0
    return r;
878
  /* get the modulus via READ PUBLIC KEY */
879
0
  if (pubkey) {
880
0
    u8 *buf;
881
0
    struct sc_pkcs15_pubkey_rsa *rsa = &pubkey->u.rsa;
882
    /* set the modulus */
883
0
    rsa->modulus.data = gendat.modulus;
884
0
    rsa->modulus.len  = kinfo->modulus_length >> 3;
885
    /* set the exponent (always 0x10001) */
886
0
    buf = malloc(3);
887
0
    if (!buf)
888
0
      return SC_ERROR_OUT_OF_MEMORY;
889
0
    buf[0] = 0x01;
890
0
    buf[1] = 0x00;
891
0
    buf[2] = 0x01;
892
0
    rsa->exponent.data = buf;
893
0
    rsa->exponent.len  = 3;
894
895
0
    pubkey->algorithm = SC_ALGORITHM_RSA;
896
0
  } else
897
    /* free public key */
898
0
    free(gendat.modulus);
899
900
0
  return SC_SUCCESS;
901
0
}
902
903
static int starcos_finalize_card(sc_card_t *card)
904
0
{
905
0
  int       r;
906
0
  sc_file_t tfile;
907
0
  sc_path_t tpath;
908
909
  /* SELECT FILE MF */
910
0
  sc_format_path("3F00", &tpath);
911
0
  r = sc_select_file(card, &tpath, NULL);
912
0
  if (r < 0)
913
0
    return r;
914
915
  /* call CREATE END for the MF (ignore errors) */
916
0
  tfile.type = SC_FILE_TYPE_DF;
917
0
  tfile.id   = 0x3f00;
918
0
  r = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_END, &tfile);
919
0
  if (r < 0)
920
0
    sc_log(card->ctx,  "failed to call CREATE END for the MF\n");
921
  /* call CREATE END for the apps (pkcs15) DF */
922
0
  tfile.type = SC_FILE_TYPE_DF;
923
0
  tfile.id   = 0x5015;
924
0
  r = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_END, &tfile);
925
0
  if (r == SC_ERROR_NOT_ALLOWED)
926
    /* card is already finalized */
927
0
    return SC_SUCCESS;
928
0
  return r;
929
0
}
930
931
static struct sc_pkcs15init_operations sc_pkcs15init_starcos_operations = {
932
  starcos_erase_card,
933
  starcos_init_card,
934
  starcos_create_dir,
935
  NULL,       /* create_domain */
936
  starcos_pin_reference,
937
  starcos_create_pin,
938
  starcos_key_reference,
939
  starcos_create_key,
940
  starcos_store_key,
941
  starcos_generate_key,
942
  NULL, NULL,     /* encode private/public key */
943
  starcos_finalize_card,
944
  NULL,         /* delete_object */
945
  NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */
946
  NULL        /* sanity_check */
947
};
948
949
struct sc_pkcs15init_operations *sc_pkcs15init_get_starcos_ops(void)
950
0
{
951
0
  return &sc_pkcs15init_starcos_operations;
952
0
}