Coverage Report

Created: 2025-07-12 06:53

/src/opensc/src/pkcs15init/pkcs15-starcos.c
Line
Count
Source (jump to first uncovered line)
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
251
#define STARCOS_AC_NEVER  0x5f
36
404
#define STARCOS_AC_ALWAYS 0x9f
37
38
469
#define STARCOS_SOPIN_GID 0x01
39
55
#define STARCOS_SOPIN_STATE 0x01
40
1
#define STARCOS_SOPIN_GAC 0x01
41
55
#define STARCOS_SOPIN_LID 0x81
42
1
#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
466
{
48
466
  return sc_card_ctl(p15card->card, SC_CARDCTL_ERASE_CARD, NULL);
49
466
}
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
155
{
55
155
  int is_global = 1;
56
155
  const sc_acl_entry_t *acl;
57
58
155
  if (auth->attrs.pin.flags & SC_PKCS15_PIN_FLAG_LOCAL)
59
136
    is_global = 0;
60
155
  if (!is_global && need_global)
61
12
    return def & 0xff;
62
143
  acl = sc_file_get_acl_entry(file, op);
63
143
  if (acl->method == SC_AC_NONE)
64
119
    return STARCOS_AC_ALWAYS;
65
24
  else if (acl->method == SC_AC_NEVER)
66
1
    return STARCOS_AC_NEVER;
67
23
  else if (acl->method == SC_AC_SYMBOLIC) {
68
2
    if (is_global)
69
1
      return STARCOS_SOPIN_GAC;
70
1
    else
71
1
      return STARCOS_SOPIN_LAC;
72
0
  } else
73
21
    return def;
74
143
}
75
76
77
static int starcos_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card)
78
132
{
79
132
  struct sc_card *card = p15card->card;
80
132
  static const u8 key[]  = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
81
132
  int   ret;
82
132
  sc_starcos_create_data  mf_data, ipf_data;
83
132
  sc_file_t *mf_file, *isf_file, *ipf_file;
84
132
  sc_path_t tpath;
85
132
  u8    *p = mf_data.data.mf.header, tmp = 0;
86
132
  sc_pkcs15_auth_info_t sopin = {0};
87
88
  /* test if we already have a MF */
89
132
  memset(&tpath, 0, sizeof(sc_path_t));
90
132
  tpath.value[0] = 0x3f;
91
132
  tpath.value[1] = 0x00;
92
132
  tpath.len      = 2;
93
132
  tpath.type     = SC_PATH_TYPE_PATH;
94
132
  ret = sc_select_file(card, &tpath, NULL);
95
132
  if (ret == SC_SUCCESS)
96
    /* we already have a MF => return OK */
97
78
    return ret;
98
99
54
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
100
101
  /* get mf profile */
102
54
  ret = sc_profile_get_file(profile, "MF", &mf_file);
103
54
  if (ret < 0)
104
0
    return ret;
105
  /* get size of the isf */
106
54
  ret = sc_profile_get_file(profile, "mf_isf", &isf_file);
107
54
  if (ret < 0) {
108
51
    sc_file_free(mf_file);
109
51
    return ret;
110
51
  }
111
3
  mf_data.type = SC_STARCOS_MF_DATA;
112
3
  memcpy(p, key, 8);
113
3
  p   += 8;
114
3
  *p++ = (mf_file->size  >> 8) & 0xff;
115
3
  *p++ = mf_file->size  & 0xff;
116
3
  *p++ = (isf_file->size >> 8) & 0xff;
117
3
  *p++ = isf_file->size & 0xff;
118
  /* AC CREATE EF   */
119
3
  *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1);
120
  /* AC CREATE KEY  */
121
3
  *p++ = get_so_ac(isf_file, SC_AC_OP_WRITE, &sopin, STARCOS_AC_NEVER,  1);
122
  /* AC CREATE DF   */
123
3
  *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1);
124
  /* AC REGISTER DF */
125
3
  *p++ = get_so_ac(mf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 1);
126
3
  *p++ = 0x00;  /* SM CR:  no */
127
3
  *p++ = 0x00;  /* SM EF:  no */
128
3
  *p = 0x00;  /* SM ISF: no */
129
3
  sc_file_free(mf_file);
130
3
  sc_file_free(isf_file);
131
  /* call CREATE MF  */
132
3
  ret = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &mf_data);
133
3
  if (ret != SC_SUCCESS)
134
2
    return ret;
135
  /* create IPF */
136
  /* get size of the ipf */
137
1
  ret = sc_profile_get_file(profile, "mf_ipf", &ipf_file);
138
1
  if (ret < 0)
139
1
    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
78
{
178
78
  struct sc_card *card = p15card->card;
179
78
  int             ret;
180
78
  sc_starcos_create_data df_data, ipf_data;
181
78
  sc_file_t *isf_file, *ipf_file;
182
78
  u8    *p = df_data.data.df.header, tmp = 0;
183
78
  sc_pkcs15_auth_info_t sopin = {0};
184
185
78
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
186
187
  /* get p15_isf profile */
188
78
  ret = sc_profile_get_file(profile, "p15_isf", &isf_file);
189
78
  if (ret < 0)
190
20
    return ret;
191
192
58
  df_data.type = SC_STARCOS_DF_DATA;
193
58
  memset(p, 0, 25);
194
58
  *p++ = (df->id >> 8) & 0xff;
195
58
  *p++ = df->id & 0xff;
196
58
  *p++ = df->namelen & 0xff;
197
58
  memcpy(p, df->name, (u8) df->namelen);
198
58
  p   += 16;
199
58
  *p++ = (isf_file->size >> 8) & 0xff;
200
58
  *p++ = isf_file->size & 0xff;
201
  /* AC CREATE EF  */
202
58
  *p++ = get_so_ac(df, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 0);
203
  /* AC CREATE KEY */
204
58
  *p++ = get_so_ac(isf_file, SC_AC_OP_WRITE, &sopin, STARCOS_AC_NEVER, 0);
205
58
  *p++ = 0x00;    /* SM EF:  no */
206
58
  *p = 0x00;    /* SM ISF: no */
207
58
  df_data.data.df.size[0] = (df->size >> 8) & 0xff;
208
58
  df_data.data.df.size[1] = df->size & 0xff;
209
58
  sc_file_free(isf_file);
210
  /* call CREATE DF  */
211
58
  ret = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &df_data);
212
58
  if (ret != SC_SUCCESS)
213
28
    return ret;
214
  /* create IPF */
215
30
  ret = sc_select_file(card, &df->path, NULL);
216
30
  if (ret != SC_SUCCESS)
217
1
    return ret;
218
29
  ret = sc_profile_get_file(profile, "p15_ipf", &ipf_file);
219
29
  if (ret < 0)
220
2
    return ret;
221
27
  ipf_data.type = SC_STARCOS_EF_DATA;
222
27
  p = ipf_data.data.ef.header;
223
27
  *p++ = (ipf_file->id >> 8) & 0xff;
224
27
  *p++ = ipf_file->id & 0xff;
225
27
  *p++ = STARCOS_AC_ALWAYS; /* AC READ     */
226
  /* AC WRITE IPF */
227
27
  *p++ = get_so_ac(ipf_file, SC_AC_OP_CREATE, &sopin, STARCOS_AC_ALWAYS, 0);
228
27
  *p++ = STARCOS_AC_NEVER; /* AC ERASE    */
229
27
  *p++ = STARCOS_AC_NEVER; /* AC LOCK     */
230
27
  *p++ = STARCOS_AC_NEVER; /* AC UNLOCK   */
231
27
  *p++ = STARCOS_AC_NEVER; /* AC INCREASE */
232
27
  *p++ = STARCOS_AC_NEVER; /* AC_DECREASE */
233
27
  *p++ = STARCOS_AC_NEVER; /* RFU         */
234
27
  *p++ = STARCOS_AC_NEVER; /* RFU         */
235
27
  *p++ = 0x00;      /* SM          */
236
27
  *p++ = 0x00;      /* SID         */
237
27
  *p++ = 0xA1;      /* IPF         */
238
27
  *p++ = (ipf_file->size >> 8) & 0xff;
239
27
  *p = ipf_file->size & 0xff;
240
27
  ret  = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_FILE, &ipf_data);
241
27
  if (ret != SC_SUCCESS) {
242
4
    sc_file_free(ipf_file);
243
4
    return ret;
244
4
  }
245
  /* init IPF */
246
23
  ret = sc_select_file(card, &ipf_file->path, NULL);
247
23
  sc_file_free(ipf_file);
248
23
  if (ret < 0)
249
2
    return ret;
250
21
  ret = sc_update_binary(card, 0, &tmp, 1, 0);
251
21
  if (ret < 0)
252
2
    return ret;
253
19
  return SC_SUCCESS;
254
21
}
255
256
static int have_onepin(sc_profile_t *profile)
257
503
{
258
503
  sc_pkcs15_auth_info_t sopin = {0};
259
260
503
  sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &sopin);
261
262
503
  if (!(sopin.attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN))
263
371
    return 1;
264
132
  else
265
132
    return 0;
266
503
}
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
49
#define STARCOS_MIN_LPIN_ID 0x83
272
34
#define STARCOS_MAX_LPIN_ID 0x8f
273
21
#define STARCOS_MIN_GPIN_ID 0x03
274
19
#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
490
{
278
490
  int tmp;
279
280
490
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
281
0
    return SC_ERROR_OBJECT_NOT_VALID;
282
283
490
  tmp = auth_info->attrs.pin.reference;
284
285
490
  if (have_onepin(profile)) {
286
    /* we have the onepin profile */
287
359
    auth_info->attrs.pin.reference = STARCOS_SOPIN_GID;
288
359
    return SC_SUCCESS;
289
359
  }
290
291
131
  if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_LOCAL) {
292
    /* use local KID */
293
    /* SO-pin */
294
89
    if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
295
55
      tmp = STARCOS_SOPIN_LID;
296
34
    else {
297
34
      if (tmp < STARCOS_MIN_LPIN_ID)
298
15
        tmp = STARCOS_MIN_LPIN_ID;
299
34
      if (!(tmp & 0x01))
300
        /* odd KIDs for PINs and even KIDs for PUKs */
301
12
        tmp++;
302
34
      if (tmp > STARCOS_MAX_LPIN_ID)
303
19
        return SC_ERROR_TOO_MANY_OBJECTS;
304
34
    }
305
89
  } else {
306
    /* use global KID */
307
    /* SO-pin */
308
42
    if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
309
23
      tmp = STARCOS_SOPIN_GID;
310
19
    else {
311
19
      if (tmp < STARCOS_MIN_GPIN_ID)
312
2
        tmp = STARCOS_MIN_GPIN_ID;
313
19
      if (!(tmp & 0x01))
314
        /* odd KIDs for PINs and even KIDs for PUKs */
315
13
      tmp++;
316
19
      if (tmp > STARCOS_MAX_GPIN_ID)
317
15
        return SC_ERROR_TOO_MANY_OBJECTS;
318
19
    }
319
42
  }
320
97
  auth_info->attrs.pin.reference = tmp;
321
322
97
  return SC_SUCCESS;
323
131
}
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
87
#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
338
{
353
338
  struct sc_card *card = p15card->card;
354
338
  int r, is_local, pin_id, tmp, need_finalize = 0;
355
338
  size_t  akd;
356
338
  sc_file_t            *tfile;
357
338
  const sc_acl_entry_t *acl_entry;
358
338
  sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data;
359
338
  sc_starcos_wkey_data  pin_d, puk_d;
360
338
  u8          tpin[8];
361
362
338
  if (!pin || !pin_len || pin_len > 8)
363
0
    return SC_ERROR_INVALID_ARGUMENTS;
364
365
338
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
366
0
    return SC_ERROR_OBJECT_NOT_VALID;
367
368
338
  is_local = 0x80 & auth_info->attrs.pin.reference;
369
338
  if (is_local)
370
18
    r = sc_select_file(card, &df->path, NULL);
371
320
  else
372
320
    r = sc_select_file(card, &profile->mf_info->file->path, NULL);
373
338
  if (r < 0)
374
267
    return r;
375
  /* get and verify sopin if necessary */
376
71
  r = sc_profile_get_file(profile, "p15_isf", &tfile);
377
71
        if (r < 0)
378
14
                return r;
379
57
  acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE);
380
57
  if (acl_entry->method != SC_AC_NONE) {
381
13
    if ((auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) || have_onepin(profile))
382
12
      need_finalize = 1;
383
1
    else
384
1
      r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE);
385
13
  }
386
57
  sc_file_free(tfile);
387
57
  if (r < 0)
388
1
    return r;
389
390
  /* pad pin with 0 */
391
56
  memset(tpin, 0, 8);
392
56
  memcpy(tpin, pin, pin_len);
393
394
  /* write PIN */
395
56
  tmp    = auth_info->tries_left;
396
56
  pin_id = auth_info->attrs.pin.reference;
397
398
56
  pin_d.mode    = 0;  /* install */
399
56
  pin_d.kid     = (u8) pin_id;
400
56
  pin_d.key     = tpin;
401
56
  pin_d.key_len = 8;
402
56
  pin_d.key_header[0]  = pin_d.kid;
403
56
  pin_d.key_header[1]  = 0;
404
56
  pin_d.key_header[2]  = 8;
405
56
  pin_d.key_header[3]  = STARCOS_AC_ALWAYS;
406
56
  if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
407
3
    pin_d.key_header[4] = STARCOS_SOPIN_STATE;
408
53
  else
409
53
    pin_d.key_header[4] = STARCOS_PINID2STATE(pin_id);
410
56
  pin_d.key_header[5]  = STARCOS_AC_ALWAYS;
411
56
  pin_d.key_header[6]  = ((0x0f & tmp) << 4) | (0x0f & tmp);
412
56
  pin_d.key_header[7]  = 0x00;
413
56
  pin_d.key_header[8]  = 0x00;
414
56
  akd = auth_info->attrs.pin.min_length;
415
56
  if (akd < 4)
416
36
    akd = 4;
417
56
  if (akd > 8)
418
1
    akd = 8;
419
56
  akd--;
420
56
  akd |= 0x08;
421
56
  pin_d.key_header[9]  = akd; /* AKD: standard + every char != 0 +
422
           * pin min length */
423
56
  pin_d.key_header[10] = 0x00;  /* never allow WRITE KEY    */
424
56
  pin_d.key_header[11] = 0x81;  /* key attribute: akd + pin */
425
  /* create/write PIN */
426
56
  r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &pin_d);
427
56
  if (r != SC_SUCCESS)
428
27
    return r;
429
430
29
  if (puk && puk_len) {
431
27
    sc_pkcs15_auth_info_t puk_info = {0};
432
433
27
    if (puk_len > 8)
434
0
      return SC_ERROR_INVALID_ARGUMENTS;
435
27
    memset(tpin, 0, 8);
436
27
    memcpy(tpin, puk, puk_len);
437
438
27
    sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &puk_info);
439
27
    tmp = puk_info.tries_left;
440
441
27
    puk_d.mode    = 0;  /* install */
442
27
    puk_d.kid     = (u8) pin_id + 1;
443
27
    puk_d.key     = tpin;
444
27
    puk_d.key_len = 8;
445
27
    puk_d.key_header[0]  = puk_d.kid;
446
27
    puk_d.key_header[1]  = 0;
447
27
    puk_d.key_header[2]  = 8;
448
27
    puk_d.key_header[3]  = STARCOS_AC_ALWAYS;
449
27
    puk_d.key_header[4]  = ((pin_id & 0x1f) << 3) | 0x05;
450
27
    puk_d.key_header[5]  = 0x01;
451
27
    puk_d.key_header[6]  = ((0x0f & tmp) << 4) | (0x0f & tmp);
452
27
    puk_d.key_header[7]  = 0x0;
453
27
    puk_d.key_header[8]  = 0x0;
454
27
    puk_d.key_header[9]  = 0x0;
455
27
    puk_d.key_header[10] = 0x00;
456
27
    puk_d.key_header[11] = 0x02;
457
    /* create/write PUK */
458
27
    r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &puk_d);
459
27
    if (r != SC_SUCCESS)
460
9
      return r;
461
27
  }
462
463
  /* in case of a global pin: write dummy entry in df isf */
464
20
  if (!is_local) {
465
18
    r = sc_select_file(card, &df->path, NULL);
466
18
    if (r < 0)
467
6
      return r;
468
12
    pin_d.key     = NULL;
469
12
    pin_d.key_len = 0;
470
12
    pin_d.key_header[1] = 0;
471
12
    pin_d.key_header[2] = 0;
472
    /* create/write dummy PIN */
473
12
    r = sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &pin_d);
474
12
    if (r != SC_SUCCESS)
475
4
      return r;
476
12
  }
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
10
  if (need_finalize)
481
4
     r = starcos_finalize_card(card);
482
483
10
  return r;
484
20
}
485
486
/* range of possible key ids for private keys
487
 */
488
924
#define STARCOS_MIN_LPKEY_ID  0x91
489
462
#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
462
{
495
  /* use (local) KIDs 0x91-0x9f for private rsa keys */
496
462
  if (prkey->key_reference < STARCOS_MIN_LPKEY_ID)
497
462
    prkey->key_reference = STARCOS_MIN_LPKEY_ID;
498
462
  if (prkey->key_reference > STARCOS_MAX_LPKEY_ID)
499
0
    return SC_ERROR_TOO_MANY_OBJECTS;
500
462
  return SC_SUCCESS;
501
462
}
502
503
118
#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
13
{
653
13
  int   r;
654
13
  size_t    len, keylen, endpos;
655
13
  u8    *buf, key[280], *p, num_keys;
656
13
  sc_file_t *tfile = NULL;
657
13
  sc_path_t tpath;
658
659
  /* get ipf profile */
660
13
  tpath = kinfo->path;
661
13
  r = sc_profile_get_file_in(profile, &tpath, "p15_ipf", &tfile);
662
13
  if (r < 0)
663
11
    return r;
664
2
  tpath = tfile->path;
665
2
  sc_file_free(tfile);
666
2
  tfile = NULL;
667
2
  r = sc_select_file(card, &tpath, &tfile);
668
2
  if (r != SC_SUCCESS)
669
    /* unable to select ipf */
670
1
    return r;
671
1
  len = tfile->size;
672
1
  sc_file_free(tfile);
673
1
  if (len == 0)
674
1
    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
462
{
728
462
  struct sc_card *card = p15card->card;
729
462
  int r, pin_id;
730
462
  u8  akd = 0, state;
731
732
462
  sc_file_t              *tfile;
733
462
  const sc_acl_entry_t   *acl_entry;
734
462
  sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *)obj->data;
735
462
  sc_starcos_wkey_data    tkey;
736
737
  /* get and verify sopin if necessary */
738
462
  r = sc_profile_get_file(profile, "p15_isf", &tfile);
739
462
        if (r < 0)
740
283
                return r;
741
179
  acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE);
742
179
  if (acl_entry->method  != SC_AC_NONE) {
743
140
    r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE);
744
140
  }
745
39
  else   {
746
39
    r = sc_select_file(card, &tfile->path, NULL);
747
39
  }
748
179
  sc_file_free(tfile);
749
179
  if (r < 0)
750
120
    return r;
751
752
  /* create sc_starcos_wkey_data */
753
59
  tkey.mode    = 0x00;  /* install new key */
754
59
  tkey.kid     = (u8) kinfo->key_reference;
755
59
  tkey.key_header[0] = (u8) kinfo->key_reference;
756
59
  tkey.key_header[1] = (STARCOS_MAX_PR_KEYSIZE >> 8) & 0xff;
757
59
  tkey.key_header[2] = STARCOS_MAX_PR_KEYSIZE & 0xff;
758
759
59
  pin_id = sc_pkcs15init_get_pin_reference(p15card, profile, SC_AC_SYMBOLIC,
760
59
      SC_PKCS15INIT_USER_PIN);
761
59
  if (pin_id < 0)
762
25
    state = STARCOS_AC_ALWAYS;
763
34
  else {
764
34
    state  = STARCOS_PINID2STATE(pin_id); /* get the necessary state */
765
34
    state |= pin_id & 0x80 ? 0x10 : 0x00; /* local vs. global key id */
766
34
  }
767
59
  tkey.key_header[3] = state;   /* AC to access key        */
768
59
  if (obj->user_consent)
769
0
    tkey.key_header[4] = 0x0f; /* do state transition */
770
59
  else
771
59
    tkey.key_header[4] = 0x8f; /* no state transition */
772
59
  tkey.key_header[5] = 0x11; /* require local state == 1 to update key */
773
59
  tkey.key_header[6] = 0x33;
774
59
  tkey.key_header[7] = 0x00;
775
59
  tkey.key_header[8] = 0x09;
776
59
  if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)
777
0
    akd |= 0x10;
778
59
  if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_SIGN)
779
59
    akd |= 0x31; /* allow DS, IA and PKCS11 */
780
59
  if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_SIGNRECOVER)
781
0
    akd |= 0x31; /* allow DS, IA and PKCS11 */
782
59
  if (kinfo->usage & SC_PKCS15_PRKEY_USAGE_DECRYPT ||
783
59
      kinfo->usage & SC_PKCS15_PRKEY_USAGE_UNWRAP)
784
0
    akd |= 0x02;
785
59
  tkey.key_header[9]  = akd;
786
59
  tkey.key_header[10] = 0x03;
787
59
  tkey.key_header[11] = 0xa0;
788
59
  tkey.key     = NULL;
789
59
  tkey.key_len = 0;
790
791
59
  return sc_card_ctl(card, SC_CARDCTL_STARCOS_WRITE_KEY, &tkey);
792
179
}
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
15
{
841
15
  int r;
842
15
  const sc_acl_entry_t   *acl_entry;
843
15
  sc_file_t              *tfile;
844
15
  sc_starcos_gen_key_data gendat;
845
15
  sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data;
846
847
15
  if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA)
848
0
    return SC_ERROR_NOT_SUPPORTED;
849
850
  /* get and verify sopin if necessary */
851
15
  r = sc_profile_get_file(profile, "p15_isf", &tfile);
852
15
        if (r < 0)
853
0
                return r;
854
15
  acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_WRITE);
855
15
  if (acl_entry->method  != SC_AC_NONE) {
856
11
    r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_WRITE);
857
11
  }
858
15
  sc_file_free(tfile);
859
15
  if (r < 0)
860
2
    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
13
  r = starcos_write_pukey(profile, p15card->card, NULL, kinfo);
869
13
  if (r < 0)
870
13
    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
470
{
905
470
  int       r;
906
470
  sc_file_t tfile;
907
470
  sc_path_t tpath;
908
909
  /* SELECT FILE MF */
910
470
  sc_format_path("3F00", &tpath);
911
470
  r = sc_select_file(card, &tpath, NULL);
912
470
  if (r < 0)
913
410
    return r;
914
915
  /* call CREATE END for the MF (ignore errors) */
916
60
  tfile.type = SC_FILE_TYPE_DF;
917
60
  tfile.id   = 0x3f00;
918
60
  r = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_END, &tfile);
919
60
  if (r < 0)
920
33
    sc_log(card->ctx,  "failed to call CREATE END for the MF\n");
921
  /* call CREATE END for the apps (pkcs15) DF */
922
60
  tfile.type = SC_FILE_TYPE_DF;
923
60
  tfile.id   = 0x5015;
924
60
  r = sc_card_ctl(card, SC_CARDCTL_STARCOS_CREATE_END, &tfile);
925
60
  if (r == SC_ERROR_NOT_ALLOWED)
926
    /* card is already finalized */
927
1
    return SC_SUCCESS;
928
59
  return r;
929
60
}
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
1.19k
{
951
1.19k
  return &sc_pkcs15init_starcos_operations;
952
1.19k
}