Coverage Report

Created: 2026-06-10 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/pkcs15-srbeid.c
Line
Count
Source
1
/*
2
 * pkcs15-srbeid.c: PKCS#15 emulation for Serbian cards using the
3
 *                 CardEdge PKI applet.
4
 *
5
 * Copyright (C) 2026 LibreSCRS contributors
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#ifdef HAVE_CONFIG_H
23
#include "config.h"
24
#endif
25
26
#include <stdlib.h>
27
#include <string.h>
28
29
#ifdef ENABLE_ZLIB
30
#include "compression.h"
31
#endif
32
#include "card-srbeid.h"
33
#include "internal.h"
34
#include "log.h"
35
#include "pkcs15.h"
36
37
/* CardEdge cmapfile constants. */
38
108
#define CE_CMAP_RECORD_SIZE 86u
39
50
#define CE_CMAP_FLAGS_OFFSET  80u
40
9
#define CE_CMAP_SIG_SIZE_OFFSET 82u
41
27
#define CE_CMAP_KX_SIZE_OFFSET  84u
42
50
#define CE_CMAP_VALID_CONTAINER 0x01u
43
30
#define CE_KEY_KIND_PRIVATE 1u
44
521
#define CE_AT_KEYEXCHANGE 1u
45
61
#define CE_AT_SIGNATURE   2u
46
253
#define CE_PKI_ROOT_DIR_FID 0x7000u
47
6.14k
#define CE_DIR_HEADER_SIZE  10u
48
5.77k
#define CE_DIR_ENTRY_SIZE 12u
49
50
/* CardEdge PIN constants */
51
184
#define CE_PIN_REFERENCE  0x80u
52
184
#define CE_PIN_MAX_LENGTH 8u
53
54
/* Private key FID formula. */
55
static unsigned int
56
ce_private_key_fid(unsigned int cont_idx,
57
    unsigned int key_pair_id)
58
30
{
59
30
  return CE_KEYS_BASE_FID | ((cont_idx << 4) & 0x0FF0u) | ((key_pair_id << 2) & 0x000Cu) | CE_KEY_KIND_PRIVATE;
60
30
}
61
62
/*
63
 * Select FID and read the entire file into a malloc'd buffer.
64
 * Uses sc_select_file() (dispatched to card driver's select_file which
65
 * handles CardEdge's proprietary FCI) and sc_read_binary().
66
 *
67
 * *out_len receives the byte count; caller must free() the buffer.
68
 * Returns SC_SUCCESS or a negative SC_ERROR_* code.
69
 */
70
static int
71
srbeid_read_file(sc_card_t *card, unsigned int fid,
72
    u8 **buf_out, size_t *out_len)
73
722
{
74
722
  sc_path_t path = {0};
75
722
  sc_file_t *file = NULL;
76
722
  u8 *buf;
77
722
  int r;
78
79
722
  *buf_out = NULL;
80
722
  *out_len = 0;
81
82
722
  path.value[0] = (u8)((fid >> 8) & 0xFF);
83
722
  path.value[1] = (u8)(fid & 0xFF);
84
722
  path.len = 2;
85
722
  path.type = SC_PATH_TYPE_FILE_ID;
86
87
722
  r = sc_select_file(card, &path, &file);
88
722
  if (r < 0)
89
253
    return r;
90
91
469
  if (!file || file->size == 0) {
92
8
    sc_file_free(file);
93
8
    return SC_SUCCESS;
94
8
  }
95
96
461
  if (file->size > 65536) {
97
0
    sc_file_free(file);
98
0
    return SC_ERROR_INVALID_DATA;
99
0
  }
100
101
461
  buf = malloc(file->size);
102
461
  if (!buf) {
103
0
    sc_file_free(file);
104
0
    return SC_ERROR_OUT_OF_MEMORY;
105
0
  }
106
107
461
  r = sc_read_binary(card, 0, buf, file->size, 0);
108
461
  sc_file_free(file);
109
461
  if (r < 0) {
110
30
    free(buf);
111
30
    return r;
112
30
  }
113
114
431
  *buf_out = buf;
115
431
  *out_len = (size_t)r;
116
431
  return SC_SUCCESS;
117
461
}
118
119
/* One entry from a CardEdge directory file. */
120
typedef struct ce_dir_entry {
121
  char name[9]; /* 8-char name + NUL */
122
  unsigned fid;
123
  int is_dir;
124
} ce_dir_entry_t;
125
126
/*
127
 * Parse a CardEdge directory file into an array of ce_dir_entry_t.
128
 *
129
 * CardEdge directories use a proprietary binary format:
130
 *   [10-byte header] [12-byte entries...]
131
 * This is NOT ISO 7816-4 EF.DIR (ASN.1 BER-TLV application templates),
132
 * so standard sc_enum_apps() / iso7816_read_ef_dir() cannot be used.
133
 *
134
 * *entries_out: caller must free().  Returns entry count or -1 on error.
135
 */
136
static int
137
ce_parse_dir(const u8 *data, size_t len, ce_dir_entry_t **entries_out)
138
367
{
139
367
  size_t count, i;
140
367
  ce_dir_entry_t *entries;
141
142
367
  *entries_out = NULL;
143
367
  if (len < CE_DIR_HEADER_SIZE)
144
6
    return -1;
145
146
361
  count = (size_t)data[6] | ((size_t)data[7] << 8);
147
361
  if (count == 0)
148
1
    return 0;
149
150
  /* Bound count against buffer size before allocation. */
151
360
  if (count > (len - CE_DIR_HEADER_SIZE) / CE_DIR_ENTRY_SIZE)
152
14
    return -1;
153
154
346
  entries = calloc(count, sizeof(ce_dir_entry_t));
155
346
  if (!entries)
156
0
    return -1;
157
158
5.76k
  for (i = 0; i < count; i++) {
159
5.41k
    size_t off = CE_DIR_HEADER_SIZE + i * CE_DIR_ENTRY_SIZE;
160
5.41k
    int k;
161
162
    /* Name: up to 8 ASCII chars, may not be NUL-terminated on card. */
163
5.41k
    memcpy(entries[i].name, data + off, 8);
164
5.41k
    entries[i].name[8] = '\0';
165
    /* Strip trailing spaces/NULs. */
166
5.41k
    k = 7;
167
10.8k
    while (k >= 0 && (entries[i].name[k] == ' ' || entries[i].name[k] == '\0'))
168
5.39k
      entries[i].name[k--] = '\0';
169
5.41k
    entries[i].fid = (unsigned)data[off + 8] | ((unsigned)data[off + 9] << 8);
170
5.41k
    entries[i].is_dir = (data[off + 10] != 0);
171
5.41k
  }
172
173
346
  *entries_out = entries;
174
346
  return (int)count;
175
346
}
176
177
typedef struct cert_entry {
178
  char label[32];
179
  unsigned cert_fid;
180
  unsigned key_fid;
181
  unsigned key_size_bits;
182
  unsigned cont_id;
183
  unsigned key_pair_id; /* CE_AT_KEYEXCHANGE or CE_AT_SIGNATURE */
184
} cert_entry_t;
185
186
/* Select AID_PKCS15 and enumerate certificates from mscp/cmapfile.
187
 * *certs_out: caller must free().  Returns cert count or negative error. */
188
static int
189
srbeid_enum_certs(sc_card_t *card, cert_entry_t **certs_out)
190
267
{
191
267
  u8 *dir_buf = NULL, *mscp_buf = NULL, *cmap_buf = NULL;
192
267
  size_t dir_len = 0, mscp_len = 0, cmap_len = 0;
193
267
  ce_dir_entry_t *root_entries = NULL, *mscp_entries = NULL;
194
267
  int root_count = 0, mscp_count = 0;
195
267
  unsigned mscp_fid = 0, cmap_fid = 0;
196
267
  cert_entry_t *certs = NULL;
197
267
  int ncerts = 0, cap = 8;
198
267
  int r, i;
199
267
  size_t cmap_offset = 0, cmap_nrec = 0;
200
201
267
  *certs_out = NULL;
202
203
  /* Select PKI applet. */
204
267
  if (iso7816_select_aid(card, AID_PKCS15, AID_PKCS15_LEN, NULL, NULL) != SC_SUCCESS) {
205
14
    r = SC_ERROR_CARD_CMD_FAILED;
206
14
    goto out;
207
14
  }
208
209
  /* Read root directory (FID 0x7000). */
210
253
  r = srbeid_read_file(card, CE_PKI_ROOT_DIR_FID, &dir_buf, &dir_len);
211
253
  if (r < 0)
212
26
    goto out;
213
214
227
  root_count = ce_parse_dir(dir_buf, dir_len, &root_entries);
215
227
  if (root_count < 0) {
216
19
    r = SC_ERROR_INVALID_DATA;
217
19
    goto out;
218
19
  }
219
220
1.43k
  for (i = 0; i < root_count; i++) {
221
1.36k
    if (root_entries[i].is_dir && strcmp(root_entries[i].name, "mscp") == 0) {
222
141
      mscp_fid = root_entries[i].fid;
223
141
      break;
224
141
    }
225
1.36k
  }
226
208
  if (mscp_fid == 0) {
227
67
    r = SC_ERROR_FILE_NOT_FOUND;
228
67
    goto out;
229
67
  }
230
231
  /* Read mscp directory. */
232
141
  r = srbeid_read_file(card, mscp_fid, &mscp_buf, &mscp_len);
233
141
  if (r < 0)
234
1
    goto out;
235
236
140
  mscp_count = ce_parse_dir(mscp_buf, mscp_len, &mscp_entries);
237
140
  if (mscp_count < 0) {
238
1
    r = SC_ERROR_INVALID_DATA;
239
1
    goto out;
240
1
  }
241
242
139
  certs = calloc((size_t)cap, sizeof(cert_entry_t));
243
139
  if (!certs) {
244
0
    r = SC_ERROR_OUT_OF_MEMORY;
245
0
    goto out;
246
0
  }
247
248
3.48k
  for (i = 0; i < mscp_count; i++) {
249
3.34k
    ce_dir_entry_t *e = &mscp_entries[i];
250
3.34k
    if (e->is_dir)
251
2.20k
      continue;
252
253
1.14k
    if (strcmp(e->name, "cmapfile") == 0) {
254
65
      cmap_fid = e->fid;
255
1.08k
    } else if (strlen(e->name) == 5) {
256
369
      unsigned kp_id;
257
369
      const char *lbl;
258
259
369
      if (strncmp(e->name, "kxc", 3) == 0) {
260
212
        kp_id = CE_AT_KEYEXCHANGE;
261
212
        lbl = "Key Exchange Certificate";
262
212
      } else if (strncmp(e->name, "ksc", 3) == 0) {
263
61
        kp_id = CE_AT_SIGNATURE;
264
61
        lbl = "Digital Signature Certificate";
265
96
      } else {
266
96
        continue;
267
96
      }
268
269
273
      if (ncerts >= cap) {
270
2
        cert_entry_t *tmp = realloc(certs,
271
2
            (size_t)(cap * 2) * sizeof(cert_entry_t));
272
2
        if (!tmp) {
273
0
          r = SC_ERROR_OUT_OF_MEMORY;
274
0
          goto out;
275
0
        }
276
2
        certs = tmp;
277
2
        cap *= 2;
278
2
      }
279
280
273
      certs[ncerts].cont_id = (unsigned)(e->name[3] - '0') * 10 + (unsigned)(e->name[4] - '0');
281
273
      certs[ncerts].cert_fid = e->fid;
282
273
      certs[ncerts].key_pair_id = kp_id;
283
273
      snprintf(certs[ncerts].label, sizeof(certs[ncerts].label), "%s", lbl);
284
273
      ncerts++;
285
273
    }
286
1.14k
  }
287
288
  /* Read cmapfile and resolve key FIDs. */
289
139
  if (cmap_fid != 0) {
290
55
    r = srbeid_read_file(card, cmap_fid, &cmap_buf, &cmap_len);
291
55
    if (r == SC_SUCCESS) {
292
      /* Optional 2-byte prefix present when (len-2) is a multiple of 86. */
293
32
      if (cmap_len >= 2 && (cmap_len - 2) % CE_CMAP_RECORD_SIZE == 0)
294
3
        cmap_offset = 2;
295
32
      cmap_nrec = (cmap_len - cmap_offset) / CE_CMAP_RECORD_SIZE;
296
32
    }
297
55
  }
298
299
412
  for (i = 0; i < ncerts; i++) {
300
273
    unsigned ci = certs[i].cont_id;
301
302
273
    if (cmap_buf && ci < cmap_nrec) {
303
50
      size_t rec = cmap_offset + (size_t)ci * CE_CMAP_RECORD_SIZE;
304
50
      u8 flags = cmap_buf[rec + CE_CMAP_FLAGS_OFFSET];
305
306
50
      if (flags & CE_CMAP_VALID_CONTAINER) {
307
36
        size_t sz_off = (certs[i].key_pair_id == CE_AT_KEYEXCHANGE)
308
36
                ? rec + CE_CMAP_KX_SIZE_OFFSET
309
36
                : rec + CE_CMAP_SIG_SIZE_OFFSET;
310
36
        unsigned kbits = (unsigned)cmap_buf[sz_off] | ((unsigned)cmap_buf[sz_off + 1] << 8);
311
36
        if (kbits != 0) {
312
30
          certs[i].key_size_bits = kbits;
313
30
          certs[i].key_fid = ce_private_key_fid(ci, certs[i].key_pair_id);
314
30
        }
315
36
      }
316
50
    }
317
273
    sc_log(card->ctx,
318
273
        "srbeid: cert[%d] \"%s\" cert_fid=0x%04x key_fid=0x%04x key_size=%u",
319
273
        i, certs[i].label, certs[i].cert_fid,
320
273
        certs[i].key_fid, certs[i].key_size_bits);
321
273
  }
322
323
139
  *certs_out = certs;
324
139
  certs = NULL;
325
139
  r = ncerts;
326
327
267
out:
328
267
  free(dir_buf);
329
267
  free(mscp_buf);
330
267
  free(cmap_buf);
331
267
  free(root_entries);
332
267
  free(mscp_entries);
333
267
  free(certs);
334
267
  return r;
335
139
}
336
337
/*
338
 * Read the raw (possibly zlib-compressed) cert file and return DER bytes.
339
 *
340
 * CardEdge cert file layout:
341
 *   [CardFS len prefix: 2 bytes LE]
342
 *   [0x01 0x00] [uncompressed len: 2 bytes LE] [zlib data]  — compressed
343
 *   OR [0x30 ...]                                            — raw DER
344
 */
345
static int
346
srbeid_read_cert_der(sc_card_t *card, unsigned cert_fid,
347
    u8 **der_out, size_t *der_len_out)
348
273
{
349
273
  u8 *raw = NULL;
350
273
  size_t raw_len = 0;
351
273
  const u8 *data;
352
273
  size_t dlen;
353
273
  int r;
354
355
273
  *der_out = NULL;
356
273
  *der_len_out = 0;
357
358
273
  r = srbeid_read_file(card, cert_fid, &raw, &raw_len);
359
273
  if (r < 0)
360
233
    return r;
361
362
40
  if (raw_len < 6) {
363
11
    free(raw);
364
11
    return SC_ERROR_INVALID_DATA;
365
11
  }
366
367
  /* Skip 2-byte CardFS length prefix. */
368
29
  data = raw + 2;
369
29
  dlen = raw_len - 2;
370
371
29
  if (dlen >= 4 && data[0] == 0x01 && data[1] == 0x00) {
372
    /* zlib-compressed DER */
373
3
#ifdef ENABLE_ZLIB
374
3
    size_t uncompressed_len = (size_t)data[2] | ((size_t)data[3] << 8);
375
3
    u8 *der = NULL;
376
377
3
    r = sc_decompress_alloc(&der, &uncompressed_len,
378
3
        data + 4, dlen - 4, COMPRESSION_ZLIB);
379
3
    if (r != SC_SUCCESS) {
380
3
      sc_log(card->ctx, "srbeid: zlib decompress failed (ret=%d)", r);
381
3
      free(raw);
382
3
      return SC_ERROR_INVALID_DATA;
383
3
    }
384
0
    *der_out = der;
385
0
    *der_len_out = uncompressed_len;
386
#else
387
    sc_log(card->ctx, "srbeid: cert is zlib-compressed but zlib not available");
388
    free(raw);
389
    return SC_ERROR_NOT_SUPPORTED;
390
#endif
391
26
  } else if (dlen >= 1 && data[0] == 0x30) {
392
    /* Uncompressed DER (ASN.1 SEQUENCE tag). */
393
3
    u8 *der = malloc(dlen);
394
3
    if (!der) {
395
0
      free(raw);
396
0
      return SC_ERROR_OUT_OF_MEMORY;
397
0
    }
398
3
    memcpy(der, data, dlen);
399
3
    *der_out = der;
400
3
    *der_len_out = dlen;
401
23
  } else {
402
23
    sc_log(card->ctx,
403
23
        "srbeid: cert FID 0x%04x: unknown format (byte0=0x%02x)",
404
23
        cert_fid, data[0]);
405
23
    free(raw);
406
23
    return SC_ERROR_INVALID_DATA;
407
23
  }
408
409
3
  free(raw);
410
3
  return SC_SUCCESS;
411
29
}
412
413
static int
414
sc_pkcs15emu_srbeid_init(sc_pkcs15_card_t *p15card)
415
267
{
416
267
  sc_card_t *card = p15card->card;
417
267
  cert_entry_t *certs = NULL;
418
267
  int ncerts, i, r = SC_SUCCESS;
419
420
267
  sc_log(card->ctx, "srbeid: pkcs15 bind");
421
422
267
  ncerts = srbeid_enum_certs(card, &certs);
423
267
  if (ncerts < 0) {
424
128
    sc_log(card->ctx, "srbeid: cert enumeration failed: %d", ncerts);
425
128
    return ncerts;
426
128
  }
427
139
  if (ncerts == 0) {
428
47
    sc_log(card->ctx, "srbeid: no certificates found");
429
47
    goto out;
430
47
  }
431
432
  /* Set card label and manufacturer. */
433
92
  set_string(&p15card->tokeninfo->label, "Serbian CardEdge");
434
92
  set_string(&p15card->tokeninfo->manufacturer_id, "CardEdge");
435
436
  /* Query PIN tries_left via card driver's pin_cmd. */
437
92
  {
438
92
    struct sc_pin_cmd_data pin_data = {0};
439
440
92
    pin_data.cmd = SC_PIN_CMD_GET_INFO;
441
92
    pin_data.pin_type = SC_AC_CHV;
442
92
    pin_data.pin_reference = CE_PIN_REFERENCE;
443
92
    pin_data.pin1.tries_left = -1;
444
445
    /* Best-effort: failure to query PIN status is not fatal. */
446
92
    sc_pin_cmd(card, &pin_data);
447
92
    sc_log(card->ctx, "srbeid: PIN tries_left=%d", pin_data.pin1.tries_left);
448
449
    /* ---- PIN auth object ----
450
     * Must be registered before private keys so auth_id links work. */
451
92
    {
452
92
      sc_pkcs15_auth_info_t auth_info = {0};
453
92
      sc_pkcs15_object_t auth_obj = {0};
454
455
92
      auth_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
456
92
      auth_info.auth_method = SC_AC_CHV;
457
92
      auth_info.tries_left = pin_data.pin1.tries_left;
458
92
      auth_info.attrs.pin.reference = CE_PIN_REFERENCE;
459
92
      auth_info.attrs.pin.min_length = 4;
460
92
      auth_info.attrs.pin.max_length = CE_PIN_MAX_LENGTH;
461
92
      auth_info.attrs.pin.stored_length = CE_PIN_MAX_LENGTH;
462
92
      auth_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
463
92
      auth_info.attrs.pin.pad_char = 0x00;
464
92
      auth_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_INITIALIZED | SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_NEEDS_PADDING;
465
92
      auth_info.path.aid.len = AID_PKCS15_LEN;
466
92
      memcpy(auth_info.path.aid.value, AID_PKCS15, AID_PKCS15_LEN);
467
92
      auth_info.auth_id.len = 1;
468
92
      auth_info.auth_id.value[0] = 1;
469
470
92
      strncpy(auth_obj.label, "User PIN", sizeof(auth_obj.label) - 1);
471
92
      auth_obj.auth_id.len = 0;
472
92
      auth_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
473
474
92
      r = sc_pkcs15emu_add_pin_obj(p15card, &auth_obj, &auth_info);
475
92
      if (r < 0) {
476
0
        sc_log(card->ctx, "srbeid: add PIN obj failed: %d", r);
477
0
        goto out;
478
0
      }
479
92
    }
480
92
  }
481
482
365
  for (i = 0; i < ncerts; i++) {
483
273
    sc_pkcs15_prkey_info_t key_info = {0};
484
273
    sc_pkcs15_object_t key_obj = {0};
485
273
    sc_pkcs15_cert_info_t cert_info = {0};
486
273
    sc_pkcs15_object_t cert_obj = {0};
487
273
    u8 *der = NULL;
488
273
    size_t der_len = 0;
489
273
    int is_kxc = (certs[i].key_pair_id == CE_AT_KEYEXCHANGE);
490
491
    /* ---- Private key object ---- */
492
493
273
    key_info.id.len = 1;
494
273
    key_info.id.value[0] = (u8)(i + 1);
495
273
    key_info.native = 1;
496
273
    key_info.key_reference = (int)certs[i].key_fid;
497
273
    key_info.modulus_length = certs[i].key_size_bits
498
273
                ? certs[i].key_size_bits
499
273
                : 2048;
500
501
    /*
502
     * Key usage flags by type:
503
     *   kxc (AT_KEYEXCHANGE) — encryption / key wrapping / decryption + signing
504
     *                          (TLS client auth uses the key exchange cert for signing)
505
     *   ksc (AT_SIGNATURE)   — digital signature / non-repudiation only
506
     */
507
273
    if (is_kxc) {
508
212
      key_info.usage = SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_WRAP | SC_PKCS15_PRKEY_USAGE_UNWRAP | SC_PKCS15_PRKEY_USAGE_SIGN;
509
212
    } else {
510
61
      key_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
511
61
    }
512
513
    /*
514
     * Set only the AID on key_info.path (path.len stays 0).
515
     * This makes select_key_file() select the PKI applet via AID
516
     * before calling set_security_env(), without appending a file
517
     * path that would fail on CardEdge's non-TLV FCI.
518
     *
519
     * The key FID is passed via key_info.key_reference and
520
     * reconstructed in set_security_env() from the low byte.
521
     */
522
273
    key_info.path.aid.len = AID_PKCS15_LEN;
523
273
    memcpy(key_info.path.aid.value, AID_PKCS15, AID_PKCS15_LEN);
524
525
273
    strncpy(key_obj.label, certs[i].label, sizeof(key_obj.label) - 1);
526
273
    key_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
527
273
    key_obj.auth_id.len = 1;
528
273
    key_obj.auth_id.value[0] = 1;
529
530
273
    r = sc_pkcs15emu_add_rsa_prkey(p15card, &key_obj, &key_info);
531
273
    if (r < 0) {
532
0
      sc_log(card->ctx, "srbeid: add prkey[%d] failed: %d", i, r);
533
0
      goto out;
534
0
    }
535
536
    /* ---- Certificate object ---- */
537
273
    if (srbeid_read_cert_der(card, certs[i].cert_fid, &der, &der_len) < 0) {
538
270
      sc_log(card->ctx, "srbeid: could not read cert[%d] DER", i);
539
270
      continue;
540
270
    }
541
542
3
    cert_info.id.len = 1;
543
3
    cert_info.id.value[0] = (u8)(i + 1);
544
3
    cert_info.authority = 0;
545
546
    /* Store DER directly in the PKCS#15 value buffer. */
547
3
    cert_info.value.value = der; /* ownership transferred */
548
3
    cert_info.value.len = der_len;
549
550
3
    strncpy(cert_obj.label, certs[i].label, sizeof(cert_obj.label) - 1);
551
552
3
    r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
553
3
    if (r < 0) {
554
0
      sc_log(card->ctx, "srbeid: add cert[%d] failed: %d", i, r);
555
0
      free(der);
556
0
      goto out;
557
0
    }
558
    /* der ownership now belongs to p15card; do not free. */
559
3
  }
560
561
92
  sc_log(card->ctx, "srbeid: pkcs15 bind OK (%d certs)", ncerts);
562
563
139
out:
564
139
  free(certs);
565
139
  return r;
566
92
}
567
568
int
569
sc_pkcs15emu_srbeid_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
570
6.63k
{
571
6.63k
  (void)aid;
572
573
6.63k
  if (p15card->card->type != SC_CARD_TYPE_SRBEID_BASE)
574
6.37k
    return SC_ERROR_WRONG_CARD;
575
576
267
  return sc_pkcs15emu_srbeid_init(p15card);
577
6.63k
}