Coverage Report

Created: 2026-01-09 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/pkcs15init/pkcs15-rtecp.c
Line
Count
Source
1
/*
2
 * pkcs15-rtecp.c: Rutoken ECP specific operation for PKCS15 initialization
3
 *
4
 * Copyright (C) 2009  Aleksey Samsonov <samsonov@guardant.ru>
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 <assert.h>
24
#include <stddef.h>
25
#include <stdlib.h>
26
27
#include "libopensc/opensc.h"
28
#include "libopensc/cardctl.h"
29
#include "libopensc/log.h"
30
#include "libopensc/pkcs15.h"
31
#include "pkcs15-init.h"
32
#include "profile.h"
33
34
0
#define RTECP_SO_PIN_REF        1
35
0
#define RTECP_USER_PIN_REF      2
36
37
/*
38
 * Erase everything that's on the card
39
 */
40
static int rtecp_erase(sc_profile_t *profile, sc_pkcs15_card_t *p15card)
41
0
{
42
0
  int r;
43
44
0
  if (!profile || !p15card || !p15card->card)
45
0
    return SC_ERROR_INVALID_ARGUMENTS;
46
0
  r = sc_card_ctl(p15card->card, SC_CARDCTL_RTECP_INIT, NULL);
47
0
  if (r == SC_SUCCESS)
48
0
    sc_free_apps(p15card->card);
49
0
  return r;
50
0
}
51
52
static int create_sysdf(sc_profile_t *profile, sc_card_t *card, const char *name)
53
0
{
54
0
  sc_file_t *file;
55
0
  sc_path_t path;
56
0
  int r;
57
58
0
  assert(profile && card && card->ctx && name);
59
0
  r = sc_profile_get_file(profile, name, &file);
60
0
  if (r == SC_SUCCESS)
61
0
  {
62
0
    assert(file);
63
0
    path = file->path;
64
0
    assert(path.len > 2);
65
0
    if (path.len > 2)
66
0
      path.len -= 2;
67
0
    r = sc_select_file(card, &path, NULL);
68
0
    if (r == SC_SUCCESS)
69
0
      r = sc_file_add_acl_entry(file, SC_AC_OP_CREATE,
70
0
          SC_AC_CHV, RTECP_USER_PIN_REF);
71
0
    if (r == SC_SUCCESS)
72
0
      r = sc_file_add_acl_entry(file, SC_AC_OP_DELETE,
73
0
          SC_AC_NEVER, SC_AC_KEY_REF_NONE);
74
0
    if (r == SC_SUCCESS)
75
0
      r = sc_create_file(card, file);
76
0
    sc_file_free(file);
77
0
  }
78
0
  sc_log(card->ctx, 
79
0
    "Create %s failed: %s\n", name, sc_strerror(r));
80
0
  return r;
81
0
}
82
83
/*
84
 * Card-specific initialization of PKCS15 meta-information
85
 */
86
static int rtecp_init(sc_profile_t *profile, sc_pkcs15_card_t *p15card)
87
0
{
88
0
  sc_card_t *card;
89
0
  sc_file_t *file;
90
0
  int r;
91
92
0
  if (!profile || !p15card || !p15card->card || !p15card->card->ctx)
93
0
    return SC_ERROR_INVALID_ARGUMENTS;
94
95
0
  card = p15card->card;
96
97
0
  r = sc_profile_get_file(profile, "MF", &file);
98
0
  LOG_TEST_RET(card->ctx, r, "Get MF info failed");
99
0
  assert(file);
100
0
  r = sc_create_file(card, file);
101
0
  sc_file_free(file);
102
0
  LOG_TEST_RET(card->ctx, r, "Create MF failed");
103
104
0
  r = sc_profile_get_file(profile, "DIR", &file);
105
0
  LOG_TEST_RET(card->ctx, r, "Get DIR file info failed");
106
0
  assert(file);
107
0
  r = sc_create_file(card, file);
108
0
  sc_file_free(file);
109
0
  LOG_TEST_RET(card->ctx, r, "Create DIR file failed");
110
111
0
  create_sysdf(profile, card, "Sys-DF");
112
0
  create_sysdf(profile, card, "SysKey-DF");
113
0
  create_sysdf(profile, card, "PuKey-DF");
114
0
  create_sysdf(profile, card, "PrKey-DF");
115
0
  create_sysdf(profile, card, "SKey-DF");
116
0
  create_sysdf(profile, card, "Cer-DF");
117
0
  create_sysdf(profile, card, "LCHV-DF");
118
119
0
  create_sysdf(profile, card, "Resrv1-DF");
120
0
  create_sysdf(profile, card, "Resrv2-DF");
121
0
  create_sysdf(profile, card, "Resrv3-DF");
122
0
  create_sysdf(profile, card, "Resrv4-DF");
123
0
  create_sysdf(profile, card, "Resrv5-DF");
124
0
  create_sysdf(profile, card, "Resrv6-DF");
125
126
0
  return sc_select_file(card, sc_get_mf_path(), NULL);
127
0
}
128
129
/*
130
 * Create a DF
131
 */
132
static int rtecp_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df)
133
0
{
134
0
  if (!profile || !p15card || !p15card->card || !df)
135
0
    return SC_ERROR_INVALID_ARGUMENTS;
136
0
  return sc_create_file(p15card->card, df);
137
0
}
138
139
/*
140
 * Select a PIN reference
141
 */
142
static int rtecp_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
143
    sc_pkcs15_auth_info_t *auth_info)
144
0
{
145
0
  int pin_ref;
146
147
0
  if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !auth_info)
148
0
    return SC_ERROR_INVALID_ARGUMENTS;
149
150
0
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
151
0
                  return SC_ERROR_OBJECT_NOT_VALID;
152
153
0
  if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
154
0
    pin_ref = RTECP_SO_PIN_REF;
155
0
  else
156
0
    pin_ref = RTECP_USER_PIN_REF;
157
0
  if (auth_info->attrs.pin.reference != pin_ref)
158
0
    LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_NOT_SUPPORTED);
159
160
0
  return SC_SUCCESS;
161
0
}
162
163
/*
164
 * Create a PIN object within the given DF
165
 */
166
static int rtecp_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
167
    sc_file_t *df, sc_pkcs15_object_t *pin_obj,
168
    const unsigned char *pin, size_t pin_len,
169
    const unsigned char *puk, size_t puk_len)
170
0
{
171
0
  sc_context_t *ctx;
172
0
  sc_pkcs15_auth_info_t *auth_info;
173
0
  sc_file_t *file = NULL;
174
  /*                        GCHV min-length Flags Attempts  Reserve */
175
0
  unsigned char prop[]  = { 0x01,       '?', 0x01,     '?', 0, 0 };
176
  /*                  AccessMode Unblock Change             Delete */
177
0
  unsigned char sec[15] = { 0x43,    '?',   '?', 0, 0, 0, 0,  0xFF };
178
0
  char pin_sname[0x10];
179
0
  int r, reset_by_sopin = 0;
180
181
0
  (void)puk; /* no warning */
182
0
  if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !df
183
0
      || !pin_obj || !pin_obj->data || !pin || !pin_len)
184
0
    return SC_ERROR_INVALID_ARGUMENTS;
185
186
0
  ctx = p15card->card->ctx;
187
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
188
189
0
  if (puk_len != 0)
190
0
  {
191
0
    sc_log(ctx,  "Do not enter User unblocking PIN (PUK): %s\n",
192
0
        sc_strerror(SC_ERROR_NOT_SUPPORTED));
193
0
    return SC_ERROR_NOT_SUPPORTED;
194
0
  }
195
196
0
  auth_info = (sc_pkcs15_auth_info_t *)pin_obj->data;
197
0
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
198
0
    return SC_ERROR_OBJECT_NOT_VALID;
199
200
0
  if (auth_info->attrs.pin.reference != RTECP_SO_PIN_REF
201
0
      && auth_info->attrs.pin.reference != RTECP_USER_PIN_REF)
202
0
  {
203
0
    sc_log(ctx,  "PIN reference %i not found in standard"
204
0
        " (Rutoken ECP) PINs\n", auth_info->attrs.pin.reference);
205
0
    return SC_ERROR_NOT_SUPPORTED;
206
0
  }
207
208
0
  snprintf(pin_sname, sizeof(pin_sname), "CHV%i", auth_info->attrs.pin.reference);
209
0
  if (auth_info->attrs.pin.reference == RTECP_USER_PIN_REF)   {
210
0
    r = sc_profile_get_file(profile, pin_sname, &file);
211
0
    if (!r)   {
212
0
      const struct sc_acl_entry *acl = NULL;
213
214
0
      r = sc_pkcs15init_fixup_file(profile, p15card, file);
215
0
      if (r < 0)
216
0
        sc_file_free(file);
217
0
      LOG_TEST_RET(p15card->card->ctx, r, "Cannot fixup the ACLs of PIN file");
218
219
0
      acl = sc_file_get_acl_entry(file, SC_AC_OP_PIN_RESET);
220
0
      if (acl && acl->method == SC_AC_CHV && acl->key_ref == RTECP_SO_PIN_REF)   {
221
0
        sc_log(ctx,  "Allow reset of User PIN with SoPIN\n");
222
0
        reset_by_sopin = 1;
223
0
      }
224
0
      sc_file_free(file);
225
0
    }
226
0
  }
227
228
0
  file = sc_file_new();
229
0
  if (!file)
230
0
    LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
231
0
  file->id = auth_info->attrs.pin.reference;
232
0
  file->size = pin_len;
233
0
  assert(sizeof(sec)/sizeof(sec[0]) > 2);
234
0
  sec[1] = (auth_info->attrs.pin.reference == RTECP_SO_PIN_REF) ? 0xFF : RTECP_SO_PIN_REF;
235
0
  sec[2] = (unsigned char)auth_info->attrs.pin.reference | (reset_by_sopin ? RTECP_SO_PIN_REF : 0);
236
0
  r = sc_file_set_sec_attr(file, sec, sizeof(sec));
237
0
  if (r == SC_SUCCESS)
238
0
  {
239
0
    assert(sizeof(prop)/sizeof(prop[0]) > 3);
240
0
    prop[1] = (unsigned char)auth_info->attrs.pin.min_length;
241
0
    prop[3] = 0x11 * (unsigned char)(auth_info->tries_left & 0x0F);
242
0
    r = sc_file_set_prop_attr(file, prop, sizeof(prop));
243
0
  }
244
0
  if (r == SC_SUCCESS)
245
0
    r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2);
246
0
  if (r == SC_SUCCESS)
247
0
    r = sc_create_file(p15card->card, file);
248
0
  sc_file_free(file);
249
250
0
  if (r == SC_SUCCESS)
251
0
    r = sc_change_reference_data(p15card->card, SC_AC_CHV,
252
0
        auth_info->attrs.pin.reference, NULL, 0, pin, pin_len, NULL);
253
0
  LOG_FUNC_RETURN(ctx, r);
254
0
}
255
256
/*
257
 * Select a reference for a private key object
258
 */
259
static int rtecp_select_key_reference(sc_profile_t *profile,
260
    sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_info_t *key_info)
261
0
{
262
0
  sc_file_t *df;
263
0
  int r;
264
265
0
  if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !key_info)
266
0
    return SC_ERROR_INVALID_ARGUMENTS;
267
268
0
  if (key_info->key_reference <= 0)
269
0
    key_info->key_reference = 1;
270
0
  else if (key_info->key_reference > 0xFF)
271
0
    return SC_ERROR_TOO_MANY_OBJECTS;
272
273
0
  r = sc_profile_get_file(profile, "PrKey-DF", &df);
274
0
  LOG_TEST_RET(p15card->card->ctx, r, "Get PrKey-DF info failed");
275
0
  assert(df);
276
0
  key_info->path = df->path;
277
0
  sc_file_free(df);
278
0
  r = sc_append_file_id(&key_info->path, key_info->key_reference);
279
0
  return r;
280
0
}
281
282
/*
283
 * Create an empty key object
284
 */
285
static int rtecp_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
286
    sc_pkcs15_object_t *obj)
287
0
{
288
0
  sc_context_t *ctx;
289
  /*                              RSA_PRkey/ Adds Miller-
290
   *                              RSA_PUBkey Rabin tests    Attempts Reserve */
291
0
  const unsigned char prkey_prop[]  = { 0x23,          0, 0,    0xAA, 0, 0 };
292
0
  const unsigned char pbkey_prop[]  = { 0x33,          0, 0,    0xAA, 0, 0 };
293
  /*                  GOSTR3410_PRkey/
294
   *                  GOSTR3410_PUBkey  paramset    Attempts Reserve */
295
0
  unsigned char prgkey_prop[] = { 0x03,      '?', 0,    0xAA, 0, 0 };
296
0
  unsigned char pbgkey_prop[] = { 0x13,      '?', 0,    0xAA, 0, 0 };
297
  /*                        AccessMode  - Update  Use  -  -  - Delete */
298
0
  unsigned char prkey_sec[15] = { 0x46, 0,   '?', '?', 0, 0, 0,   '?' };
299
0
  unsigned char pbkey_sec[15] = { 0x46, 0,   '?',   0, 0, 0, 0,   '?' };
300
0
  unsigned char auth_id, paramset;
301
0
  sc_pkcs15_prkey_info_t *key_info;
302
0
  sc_file_t *file;
303
0
  int r;
304
305
0
  if (!profile || !p15card || !p15card->card || !p15card->card->ctx
306
0
      || !obj || !obj->data)
307
0
    return SC_ERROR_INVALID_ARGUMENTS;
308
309
0
  ctx = p15card->card->ctx;
310
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
311
0
  if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA
312
0
      && obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410)
313
0
    return SC_ERROR_NOT_SUPPORTED;
314
0
  if (obj->auth_id.len != 1)
315
0
    return SC_ERROR_INVALID_ARGUMENTS;
316
0
  auth_id = obj->auth_id.value[0];
317
318
0
  key_info = (sc_pkcs15_prkey_info_t *)obj->data;
319
0
  assert(key_info);
320
0
  if ((obj->type == SC_PKCS15_TYPE_PRKEY_RSA
321
0
        && key_info->modulus_length % 128 != 0)
322
0
      || (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410
323
0
        && key_info->modulus_length
324
0
        != SC_PKCS15_GOSTR3410_KEYSIZE))
325
0
  {
326
0
    sc_log(ctx, 
327
0
       "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n",
328
0
       key_info->modulus_length);
329
0
    return SC_ERROR_INVALID_ARGUMENTS;
330
0
  }
331
0
  if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410)
332
0
  {
333
0
    if (key_info->params.len < sizeof(int))
334
0
      return SC_ERROR_INVALID_ARGUMENTS;
335
0
    if (((int*)key_info->params.data)[0] < 1
336
0
        || ((int*)key_info->params.data)[0] > 3)
337
0
      return SC_ERROR_INVALID_ARGUMENTS;
338
0
    paramset = ((unsigned int*)key_info->params.data)[0] & 0x03;
339
0
    assert(sizeof(prgkey_prop)/sizeof(prgkey_prop[0]) > 1);
340
0
    assert(sizeof(pbgkey_prop)/sizeof(pbgkey_prop[0]) > 1);
341
0
    prgkey_prop[1] = 0x10 + (paramset << 4);
342
0
    pbgkey_prop[1] = prgkey_prop[1];
343
0
  }
344
345
0
  r = sc_profile_get_file(profile, "PKCS15-AppDF", &file);
346
0
  LOG_TEST_RET(ctx, r, "Get PKCS15-AppDF info failed");
347
0
  r = sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, auth_id);
348
0
  if (r == SC_SUCCESS)
349
0
    r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE);
350
0
  sc_file_free(file);
351
0
  LOG_TEST_RET(ctx, r, "Authenticate failed");
352
353
0
  file = sc_file_new();
354
0
  if (!file)
355
0
    LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
356
0
  file->id = key_info->key_reference;
357
0
  r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2);
358
359
  /* private key file */
360
0
  if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)
361
0
    file->size = key_info->modulus_length / 8 / 2 * 5 + 8;
362
0
  else
363
0
    file->size = key_info->modulus_length / 8;
364
0
  if (r == SC_SUCCESS)
365
0
  {
366
0
    assert(sizeof(prkey_sec)/sizeof(prkey_sec[0]) > 7);
367
0
    prkey_sec[2] = auth_id;
368
0
    prkey_sec[3] = auth_id;
369
0
    prkey_sec[7] = auth_id;
370
0
    r = sc_file_set_sec_attr(file, prkey_sec, sizeof(prkey_sec));
371
0
  }
372
0
  if (r == SC_SUCCESS)
373
0
  {
374
0
    if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)
375
0
      r = sc_file_set_prop_attr(file, prkey_prop, sizeof(prkey_prop));
376
0
    else
377
0
      r = sc_file_set_prop_attr(file, prgkey_prop,sizeof(prgkey_prop));
378
0
  }
379
0
  if (r == SC_SUCCESS)  {
380
0
    sc_log(ctx, "create private key file id:%04i", file->id);
381
0
    r = sc_create_file(p15card->card, file);
382
0
  }
383
  /* public key file */
384
0
  if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)
385
0
    file->size = key_info->modulus_length / 8 / 2 * 3;
386
0
  else
387
0
    file->size = key_info->modulus_length / 8 * 2;
388
0
  if (r == SC_SUCCESS)
389
0
  {
390
0
    assert(sizeof(pbkey_sec)/sizeof(pbkey_sec[0]) > 7);
391
0
    pbkey_sec[2] = auth_id;
392
0
    pbkey_sec[7] = auth_id;
393
0
    r = sc_file_set_sec_attr(file, pbkey_sec, sizeof(pbkey_sec));
394
0
  }
395
0
  if (r == SC_SUCCESS)
396
0
  {
397
0
    if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)
398
0
      r = sc_file_set_prop_attr(file, pbkey_prop, sizeof(pbkey_prop));
399
0
    else
400
0
      r = sc_file_set_prop_attr(file, pbgkey_prop,sizeof(pbgkey_prop));
401
0
  }
402
0
  if (r == SC_SUCCESS)   {
403
0
    sc_log(ctx, "create public key file id:%04i", file->id);
404
0
    r = sc_create_file(p15card->card, file);
405
0
  }
406
0
  sc_file_free(file);
407
0
  LOG_FUNC_RETURN(ctx, r);
408
0
}
409
410
/*
411
 * Store a key on the card
412
 */
413
static int rtecp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
414
    sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key)
415
0
{
416
0
  sc_card_t *card;
417
0
  sc_pkcs15_prkey_info_t *key_info;
418
0
  sc_file_t *pukey_df;
419
0
  sc_path_t path;
420
0
  unsigned char *buf;
421
0
  size_t buf_len, key_len, len, i;
422
0
  int r;
423
424
0
  if (!profile || !p15card || !p15card->card || !p15card->card->ctx
425
0
      || !obj || !obj->data || !key)
426
0
    return SC_ERROR_INVALID_ARGUMENTS;
427
428
0
  card = p15card->card;
429
0
  SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
430
431
0
  if ((obj->type != SC_PKCS15_TYPE_PRKEY_RSA || key->algorithm != SC_ALGORITHM_RSA)
432
0
      && (obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410
433
0
        || key->algorithm != SC_ALGORITHM_GOSTR3410))
434
0
    return SC_ERROR_NOT_SUPPORTED;
435
436
0
  key_info = (sc_pkcs15_prkey_info_t *)obj->data;
437
0
  assert(key_info);
438
439
0
  if (key->algorithm == SC_ALGORITHM_RSA)
440
0
  {
441
0
    assert(key_info->modulus_length % 128 == 0);
442
0
    len = key_info->modulus_length / 8 / 2;
443
0
    key_len = len * 5 + 8;
444
0
    buf_len = key_len;
445
0
  }
446
0
  else
447
0
  {
448
0
    assert(key_info->modulus_length == SC_PKCS15_GOSTR3410_KEYSIZE);
449
0
    len = key_info->modulus_length / 8;
450
0
    key_len = len;
451
0
    buf_len = len;
452
0
  }
453
0
  if (key->algorithm == SC_ALGORITHM_RSA && (!key->u.rsa.p.data
454
0
      || !key->u.rsa.q.data || !key->u.rsa.iqmp.data
455
0
      || !key->u.rsa.dmp1.data || !key->u.rsa.dmq1.data
456
0
      || !key->u.rsa.modulus.data || !key->u.rsa.exponent.data
457
0
      || key->u.rsa.p.len != len || key->u.rsa.q.len != len
458
0
      || key->u.rsa.iqmp.len != len || key->u.rsa.dmp1.len != len
459
0
      || key->u.rsa.dmq1.len != len || key->u.rsa.modulus.len != 2*len
460
0
      || key->u.rsa.exponent.len > len || key->u.rsa.exponent.len == 0))
461
0
    return SC_ERROR_INVALID_ARGUMENTS;
462
0
  if (key->algorithm == SC_ALGORITHM_GOSTR3410 && (!key->u.gostr3410.d.data
463
0
      || key->u.gostr3410.d.len != len))
464
0
    return SC_ERROR_INVALID_ARGUMENTS;
465
0
  buf = calloc(1, buf_len);
466
0
  if (!buf)
467
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
468
0
  assert(key_len <= buf_len);
469
0
  if (key->algorithm == SC_ALGORITHM_RSA)
470
0
  {
471
    /* p */
472
0
    for (i = 0; i < len; ++i)
473
0
      buf[i] = key->u.rsa.p.data[len - 1 - i];
474
    /* q */
475
0
    for (i = 0; i < len; ++i)
476
0
      buf[len + 4 + i] = key->u.rsa.q.data[len - 1 - i];
477
    /* iqmp */
478
0
    for (i = 0; i < len; ++i)
479
0
      buf[len + 4 + len + 4 + i] = key->u.rsa.iqmp.data[len - 1 - i];
480
    /* dmp1 */
481
0
    for (i = 0; i < len; ++i)
482
0
      buf[len + 4 + len + 4 + len + i] =
483
0
        key->u.rsa.dmp1.data[len - 1 - i];
484
    /* dmq1 */
485
0
    for (i = 0; i < len; ++i)
486
0
      buf[len * 4 + 8 + i] = key->u.rsa.dmq1.data[len - 1 - i];
487
0
  }
488
0
  else
489
0
  {
490
    /* d */
491
0
    for (i = 0; i < len; ++i)
492
0
      buf[i] = key->u.gostr3410.d.data[len - 1 - i];
493
0
  }
494
0
  path = key_info->path;
495
0
  r = sc_select_file(card, &path, NULL);
496
0
  if (r == SC_SUCCESS)
497
0
    r = sc_change_reference_data(card, 0, 0, NULL, 0, buf, key_len, NULL);
498
0
  assert(buf);
499
0
  sc_mem_clear(buf, key_len);
500
  /* store public key */
501
0
  if (key->algorithm == SC_ALGORITHM_RSA)
502
0
    key_len = len * 3;
503
0
  else
504
0
    goto end;
505
0
  assert(key_len <= buf_len);
506
0
  if (key->algorithm == SC_ALGORITHM_RSA)
507
0
  {
508
    /* modulus */
509
0
    for (i = 0; i < 2*len; ++i)
510
0
      buf[i] = key->u.rsa.modulus.data[2*len - 1 - i];
511
    /* exponent */
512
0
    for (i = 0; i < key->u.rsa.exponent.len && i < len; ++i)
513
0
      buf[2 * len + i] = key->u.rsa.exponent.data[
514
0
        key->u.rsa.exponent.len - 1 - i];
515
0
  }
516
0
  if (r == SC_SUCCESS)
517
0
  {
518
0
    r = sc_profile_get_file(profile, "PuKey-DF", &pukey_df);
519
0
    if (r == SC_SUCCESS)
520
0
    {
521
0
      assert(pukey_df);
522
0
      path = pukey_df->path;
523
0
      r = sc_append_file_id(&path, key_info->key_reference);
524
0
      sc_file_free(pukey_df);
525
0
    }
526
0
    else if (card->ctx->debug >= 2)
527
0
      sc_log(card->ctx,  "%s\n", "Get PuKey-DF info failed");
528
0
  }
529
0
  if (r == SC_SUCCESS)
530
0
  {
531
0
    r = sc_select_file(card, &path, NULL);
532
0
    if (r == SC_SUCCESS)
533
0
      r = sc_change_reference_data(card, 0, 0, NULL, 0,
534
0
          buf, key_len, NULL);
535
0
    if (r && card->ctx->debug >= 2)
536
0
      sc_log(card->ctx,  "%s\n", "Store public key failed");
537
0
  }
538
0
end:
539
0
  assert(buf);
540
0
  free(buf);
541
0
  LOG_FUNC_RETURN(card->ctx, r);
542
0
}
543
544
/*
545
 * Generate key
546
 */
547
static int rtecp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
548
    sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey)
549
0
{
550
0
  sc_context_t *ctx;
551
0
  sc_pkcs15_prkey_info_t *key_info;
552
0
  sc_rtecp_genkey_data_t data;
553
0
  int r;
554
555
0
  if (!profile || !p15card || !p15card->card || !p15card->card->ctx
556
0
      || !obj || !obj->data || !pubkey)
557
0
    return SC_ERROR_INVALID_ARGUMENTS;
558
559
0
  ctx = p15card->card->ctx;
560
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
561
0
  switch (obj->type)
562
0
  {
563
0
  case SC_PKCS15_TYPE_PRKEY_RSA:
564
0
    data.type = SC_ALGORITHM_RSA;
565
0
    break;
566
0
  case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
567
0
    data.type = SC_ALGORITHM_GOSTR3410;
568
0
    break;
569
0
  default:
570
0
    return SC_ERROR_NOT_SUPPORTED;
571
0
  }
572
0
  key_info = (sc_pkcs15_prkey_info_t *)obj->data;
573
0
  assert(key_info);
574
0
  data.key_id = key_info->key_reference;
575
0
  assert(data.key_id != 0);
576
0
  switch (data.type)
577
0
  {
578
0
  case SC_ALGORITHM_RSA:
579
0
    assert(key_info->modulus_length % 128 == 0);
580
0
    data.u.rsa.modulus_len = key_info->modulus_length / 8;
581
0
    data.u.rsa.modulus = calloc(1, data.u.rsa.modulus_len);
582
0
    data.u.rsa.exponent_len = key_info->modulus_length / 8 / 2;
583
0
    data.u.rsa.exponent = calloc(1, data.u.rsa.exponent_len);
584
0
    if (!data.u.rsa.modulus || !data.u.rsa.exponent)
585
0
    {
586
0
      free(data.u.rsa.modulus);
587
0
      free(data.u.rsa.exponent);
588
0
      LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
589
0
    }
590
0
    break;
591
0
  case SC_ALGORITHM_GOSTR3410:
592
0
    assert(key_info->modulus_length == SC_PKCS15_GOSTR3410_KEYSIZE);
593
0
    data.u.gostr3410.xy_len = key_info->modulus_length / 8 * 2;
594
0
    data.u.gostr3410.xy = calloc(1, data.u.gostr3410.xy_len);
595
0
    if (!data.u.gostr3410.xy)
596
0
    {
597
0
      free(data.u.gostr3410.xy);
598
0
      LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
599
0
    }
600
0
    break;
601
0
  default:
602
0
    assert(0);
603
0
  }
604
0
  r = sc_card_ctl(p15card->card, SC_CARDCTL_RTECP_GENERATE_KEY, &data);
605
0
  if (r == SC_SUCCESS)
606
0
  {
607
0
    assert(pubkey);
608
0
    pubkey->algorithm = data.type;
609
0
    switch (data.type)
610
0
    {
611
0
    case SC_ALGORITHM_RSA:
612
0
      pubkey->u.rsa.modulus.data = data.u.rsa.modulus;
613
0
      pubkey->u.rsa.modulus.len = data.u.rsa.modulus_len;
614
0
      pubkey->u.rsa.exponent.data = data.u.rsa.exponent;
615
0
      pubkey->u.rsa.exponent.len = data.u.rsa.exponent_len;
616
0
      break;
617
0
    case SC_ALGORITHM_GOSTR3410:
618
0
      pubkey->u.gostr3410.xy.data = data.u.gostr3410.xy;
619
0
      pubkey->u.gostr3410.xy.len = data.u.gostr3410.xy_len;
620
0
      break;
621
0
    }
622
0
  }
623
0
  LOG_FUNC_RETURN(ctx, r);
624
0
}
625
626
/*
627
 * Finalize card
628
 * Ends the initialization phase of the smart card/token
629
 */
630
static int rtecp_finalize(sc_card_t *card)
631
0
{
632
0
  if (!card)
633
0
    return SC_ERROR_INVALID_ARGUMENTS;
634
0
  return sc_card_ctl(card, SC_CARDCTL_RTECP_INIT_END, NULL);
635
0
}
636
637
638
/*
639
 * Delete object
640
 * 
641
 * Applied to private key: used to delete public part internal file
642
 */
643
static int rtecp_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
644
    struct sc_pkcs15_object *obj, const struct sc_path *path)
645
0
{
646
0
  sc_context_t *ctx;
647
0
  sc_file_t *df;
648
0
  sc_path_t pubkey_path;
649
0
  int key_ref;
650
0
  int r;
651
652
0
  if (!profile || !p15card || !p15card->card || !p15card->card->ctx)
653
0
    return SC_ERROR_INVALID_ARGUMENTS;
654
655
0
  ctx = p15card->card->ctx;
656
0
  LOG_FUNC_CALLED(ctx);
657
0
  sc_log(ctx, "delete object: type %X, path %s", obj->type, sc_print_path(path));
658
659
0
  if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY)
660
0
    LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
661
662
0
  key_ref = ((struct sc_pkcs15_prkey_info *)obj->data)->key_reference;
663
0
  sc_log(ctx, "key reference %04i", key_ref);
664
665
0
  r = sc_profile_get_file(profile, "PuKey-DF", &df);
666
0
  LOG_TEST_RET(ctx, r, "Get PuKey-DF info failed");
667
0
  pubkey_path = df->path;
668
0
  sc_file_free(df);
669
670
0
  r = sc_append_file_id(&pubkey_path, key_ref);
671
0
  LOG_TEST_RET(ctx, r, "Append ID to file failed");
672
673
0
  sc_log(ctx, "delete pubkey file %s", sc_print_path(&pubkey_path));
674
0
  r = sc_pkcs15init_delete_by_path(profile, p15card, &pubkey_path);
675
0
  if (r && r != SC_ERROR_FILE_NOT_FOUND)
676
0
    LOG_FUNC_RETURN(ctx, r);
677
678
0
  LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
679
0
}
680
681
682
static struct sc_pkcs15init_operations sc_pkcs15init_rtecp_operations = {
683
  rtecp_erase,                    /* erase_card */
684
  rtecp_init,                     /* init_card */
685
  rtecp_create_dir,               /* create_dir */
686
  NULL,                           /* create_domain */
687
  rtecp_select_pin_reference,     /* select_pin_reference */
688
  rtecp_create_pin,               /* create_pin */
689
  rtecp_select_key_reference,     /* select_key_reference */
690
  rtecp_create_key,               /* create_key */
691
  rtecp_store_key,                /* store_key */
692
  rtecp_generate_key,             /* generate_key */
693
  NULL,                           /* encode_private_key */
694
  NULL,                           /* encode_public_key */
695
  rtecp_finalize,                 /* finalize_card */
696
  rtecp_delete_object,            /* delete_object */
697
  NULL, NULL, NULL, NULL, NULL,   /* pkcs15init emulation */
698
  NULL                            /* sanity_check */
699
};
700
701
struct sc_pkcs15init_operations * sc_pkcs15init_get_rtecp_ops(void)
702
9
{
703
9
  return &sc_pkcs15init_rtecp_operations;
704
9
}
705