Coverage Report

Created: 2025-07-01 06:08

/src/opensc/src/libopensc/pkcs15-starcos-esign.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * PKCS15 emulation layer for Giesecke & Devrient StarCOS 3.x cards 
3
 * with eSign application
4
 *
5
 * Copyright (C) 2022, jozsefd
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 "common/compat_strlcpy.h"
27
#include "internal.h"
28
#include "log.h"
29
#include "pkcs15.h"
30
#include "cards.h"
31
32
#include <stdlib.h>
33
#include <string.h>
34
35
/* compile time option: define ENABLE_ESIGN_ISSUER_CONTAINERS to enable containers holding the issuer certificates */
36
37
static const char name_Card[] = "ESIGN";
38
static const char name_Vendor[] = "Giesecke & Devrient";
39
static const char name_ESign[] = "ESIGN";
40
static const unsigned char aid_ESIGN[] = {0xA0, 0x00, 0x00, 0x02, 0x45, 0x53, 0x69, 0x67, 0x6E};
41
42
typedef struct cdata_st {
43
  const char *label;
44
  int authority;
45
  const char *path;
46
  const char *id;
47
  int obj_flags;
48
} cdata, *pcdata;
49
50
typedef struct pdata_st {
51
  const char *id;
52
  const char *label;
53
  const char *path;
54
  int ref;
55
  int type;
56
  unsigned int maxlen;
57
  unsigned int minlen;
58
  unsigned int storedlen;
59
  int flags;
60
  int tries_left;
61
  int max_tries;
62
  const char pad_char;
63
  int obj_flags;
64
} pindata, *ppindata;
65
66
typedef struct prdata_st {
67
  const char *id;
68
  const char *label;
69
  unsigned int modulus_len;
70
  int usage;
71
  const char *path;
72
  int ref;
73
  const char *auth_id;
74
  int obj_flags;
75
} prdata, *pprdata;
76
77
typedef struct container_st {
78
  const char *id;
79
  const pcdata certdata;
80
  const ppindata pindata;
81
  const pprdata prdata;
82
} container;
83
84
#define USAGE_NONREP SC_PKCS15_PRKEY_USAGE_NONREPUDIATION
85
0
#define USAGE_KE     SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
86
0
         SC_PKCS15_PRKEY_USAGE_DECRYPT | \
87
0
         SC_PKCS15_PRKEY_USAGE_WRAP | \
88
0
         SC_PKCS15_PRKEY_USAGE_UNWRAP
89
0
#define USAGE_AUT SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
90
0
          SC_PKCS15_PRKEY_USAGE_DECRYPT | \
91
0
          SC_PKCS15_PRKEY_USAGE_WRAP | \
92
0
          SC_PKCS15_PRKEY_USAGE_UNWRAP | \
93
0
          SC_PKCS15_PRKEY_USAGE_SIGN
94
0
#define USER_PIN  SC_PKCS15_PIN_FLAG_INITIALIZED | \
95
0
        SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | \
96
0
        SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL | \
97
0
        SC_PKCS15_PIN_AUTH_TYPE_PIN
98
99
static int
100
get_cert_size(sc_card_t *card, sc_path_t *path, size_t *psize)
101
0
{
102
0
  int r;
103
0
  sc_file_t *file = NULL;
104
105
0
  r = sc_select_file(card, path, &file);
106
0
  LOG_TEST_RET(card->ctx, r, "Failed to select EF certificate");
107
108
0
  *psize = file->size;
109
0
  sc_file_free(file);
110
111
0
  return SC_SUCCESS;
112
0
}
113
114
static int
115
add_app(sc_pkcs15_card_t *p15card, const container *containers, int container_count)
116
0
{
117
0
  int i, containers_added = 0, r = SC_SUCCESS;
118
0
  ppindata installed_pins[4];
119
0
  size_t installed_pin_count = 0;
120
0
  sc_card_t *card = p15card->card;
121
122
0
  LOG_FUNC_CALLED(card->ctx);
123
124
0
  for (i = 0; i < container_count; i++) {
125
0
    struct sc_pkcs15_cert_info cert_info;
126
0
    struct sc_pkcs15_object cert_obj;
127
0
    size_t cert_size;
128
129
0
    memset(&cert_info, 0, sizeof(cert_info));
130
0
    memset(&cert_obj, 0, sizeof(cert_obj));
131
132
0
    sc_pkcs15_format_id(containers[i].id, &cert_info.id);
133
0
    cert_info.authority = containers[i].certdata->authority;
134
0
    sc_format_path(containers[i].certdata->path, &cert_info.path);
135
136
0
    r = get_cert_size(card, &cert_info.path, &cert_size);
137
0
    if ( r != SC_SUCCESS ) {
138
0
      sc_log(card->ctx, "Failed to determine size of certificate %s, ignoring container", containers[i].certdata->label);
139
0
      continue;
140
0
    }
141
142
0
    strlcpy(cert_obj.label, containers[i].certdata->label, sizeof(cert_obj.label));
143
0
    cert_obj.flags = containers[i].certdata->obj_flags;
144
145
0
    r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
146
0
    LOG_TEST_RET(card->ctx, r, "Failed to add certificate");
147
148
0
    if (containers[i].pindata != 0) {
149
0
      size_t j;
150
0
      int is_pin_installed = 0;
151
152
      /* A pin object could be used by more than 1 container, ensure it is added only once */
153
0
      for (j = 0; j < installed_pin_count; j++) {
154
0
        if (installed_pins[j] == containers[i].pindata) {
155
0
          is_pin_installed = 1;
156
0
          break;
157
0
        }
158
0
      }
159
160
0
      if (!is_pin_installed) {
161
0
        struct sc_pkcs15_auth_info pin_info;
162
0
        struct sc_pkcs15_object pin_obj;
163
164
0
        if (installed_pin_count < (int)(sizeof(installed_pins) / sizeof(ppindata))) {
165
0
          installed_pins[installed_pin_count++] = containers[i].pindata;
166
0
        } else {
167
0
          sc_log(card->ctx, "Warning: cannot add more than 4 pins");
168
0
          continue;
169
0
        }
170
171
0
        memset(&pin_info, 0, sizeof(pin_info));
172
0
        memset(&pin_obj, 0, sizeof(pin_obj));
173
174
0
        sc_pkcs15_format_id(containers[i].pindata->id, &pin_info.auth_id);
175
0
        pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
176
0
        pin_info.attrs.pin.reference = containers[i].pindata->ref;
177
0
        pin_info.attrs.pin.flags = containers[i].pindata->flags;
178
0
        pin_info.attrs.pin.type = containers[i].pindata->type;
179
0
        pin_info.attrs.pin.min_length = containers[i].pindata->minlen;
180
0
        pin_info.attrs.pin.stored_length = containers[i].pindata->storedlen;
181
0
        pin_info.attrs.pin.max_length = containers[i].pindata->maxlen;
182
0
        pin_info.attrs.pin.pad_char = containers[i].pindata->pad_char;
183
0
        if (containers[i].pindata->path != NULL)
184
0
          sc_format_path(containers[i].pindata->path, &pin_info.path);
185
0
        pin_info.tries_left = -1;
186
0
        pin_info.max_tries = containers[i].pindata->max_tries;
187
188
0
        strlcpy(pin_obj.label, containers[i].pindata->label, sizeof(pin_obj.label));
189
0
        pin_obj.flags = containers[i].pindata->obj_flags;
190
191
0
        r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
192
0
        LOG_TEST_RET(card->ctx, r, "Failed to add PIN object");
193
0
      }
194
0
    }
195
196
0
    if (containers[i].prdata != 0) {
197
0
      struct sc_pkcs15_prkey_info prkey_info;
198
0
      struct sc_pkcs15_object prkey_obj;
199
0
      int modulus_len = containers[i].prdata->modulus_len;
200
0
      memset(&prkey_info, 0, sizeof(prkey_info));
201
0
      memset(&prkey_obj, 0, sizeof(prkey_obj));
202
203
0
      sc_pkcs15_format_id(containers[i].id, &prkey_info.id);
204
0
      prkey_info.usage = containers[i].prdata->usage;
205
0
      prkey_info.native = 1;
206
0
      prkey_info.key_reference = containers[i].prdata->ref;
207
0
      prkey_info.modulus_length = modulus_len;
208
0
      sc_format_path(containers[i].prdata->path, &prkey_info.path);
209
210
0
      strlcpy(prkey_obj.label, containers[i].prdata->label, sizeof(prkey_obj.label));
211
0
      prkey_obj.flags = containers[i].prdata->obj_flags;
212
0
      if (containers[i].prdata->auth_id) {
213
0
        sc_pkcs15_format_id(containers[i].prdata->auth_id, &prkey_obj.auth_id);
214
0
      }
215
216
0
      r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
217
0
      LOG_TEST_RET(card->ctx, r, "Failed to add RSA prkey");
218
0
    }
219
220
0
    containers_added++;
221
0
  }
222
223
0
  if (containers_added == 0) {
224
0
    r = SC_ERROR_INVALID_CARD;
225
0
  } else {
226
0
    r = SC_SUCCESS;
227
0
  }
228
229
0
  LOG_FUNC_RETURN(card->ctx, r);
230
0
}
231
232
/*
233
 * adds the PKCS15 objects of the ESIGN application. The app may contain
234
 * 1) Authentication container
235
 *  - 2048-bit RSA key
236
 *  - CH certificate
237
 * 2) Encryption container
238
 *  - 2048-bit RSA key
239
 *  - CH certificate
240
 * 3) Authentication Issuer container
241
 *  - issuer certificate
242
 * 3) Encryption Issuer container
243
 *  - issuer certificate
244
 * Depending on the card profile, some containers may be missing.
245
 * Both RSA keys are protected with the UserPIN. The app may have a PUK, not
246
 * supported by this emulator.
247
 * 
248
 * The issuer certificates are not included by default, define ENABLE_ESIGN_ISSUER_CONTAINERS
249
 * to enable them.
250
 */
251
static int
252
starcos_add_esign_app(sc_pkcs15_card_t *p15card)
253
0
{
254
0
  static cdata auth_cert = {"C.CH.AUT", 0, "3F00060843F1", "1", 0};
255
0
  static cdata encr_cert = {"C.CH.ENC", 0, "3F0006084301", "2", 0};
256
#ifdef ENABLE_ESIGN_ISSUER_CONTAINERS
257
  const cdata auth_root_cert = { "C.RootCA_Auth", 1, "3F00060843F0", "3", 0 };
258
  const cdata encr_root_cert = { "C.RootCA_Enc", 1, "3F0006084300", "4", 0 };
259
#endif
260
261
0
  static prdata auth_key = {"1", "PrK.CH.AUT", 2048, USAGE_AUT, "3F000608", 0x81, "1", SC_PKCS15_CO_FLAG_PRIVATE};
262
0
  static prdata encr_key = {"2", "PrK.CH.ENC", 2048, USAGE_KE, "3F000608", 0x83, "1", SC_PKCS15_CO_FLAG_PRIVATE};
263
264
0
  static pindata auth_pin = {"1", "UserPIN", "3F00", 0x01, SC_PKCS15_PIN_TYPE_UTF8, 16, 6, 0,
265
0
      USER_PIN, -1, 3, 0x00, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE};
266
267
0
  static pindata auth_pin_v35 = {"1", "UserPIN", "3F00", 0x06, SC_PKCS15_PIN_TYPE_UTF8, 16, 6, 0,
268
0
      USER_PIN, -1, 3, 0x00, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE};
269
270
0
  ppindata auth = (p15card->card->type == SC_CARD_TYPE_STARCOS_V3_5_ESIGN) ? &auth_pin_v35 : &auth_pin;
271
272
0
  const container containers[] = {
273
0
      {"1", &auth_cert, auth, &auth_key},
274
0
      {"2", &encr_cert, auth, &encr_key},
275
#ifdef ENABLE_ESIGN_ISSUER_CONTAINERS
276
      { "3", &auth_root_cert, 0, 0 },
277
      { "4", &encr_root_cert, 0, 0 },
278
#endif
279
0
  };
280
281
0
  return add_app(p15card, containers, sizeof(containers) / sizeof(container));
282
0
}
283
284
static int
285
starcos_esign_init(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
286
0
{
287
0
  sc_card_t *card = p15card->card;
288
0
  sc_context_t *ctx = card->ctx;
289
0
  const char *label = name_Card;
290
0
  int r;
291
0
  int apps_added = 0;
292
293
0
  SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
294
295
0
  if (card->type != SC_CARD_TYPE_STARCOS_V3_4_ESIGN && card->type != SC_CARD_TYPE_STARCOS_V3_5_ESIGN) {
296
0
    return SC_ERROR_WRONG_CARD;
297
0
  }
298
299
0
  if (aid == NULL) {
300
    // no aid: in this case all emulated apps are added, currently only the esign_app
301
0
    r = starcos_add_esign_app(p15card);
302
0
    if (r == SC_SUCCESS)
303
0
      apps_added++;
304
0
  } else {
305
    // aid specified: only the matching app is added
306
0
    if (aid->len == sizeof(aid_ESIGN) && memcmp(aid->value, aid_ESIGN, sizeof(aid_ESIGN)) == 0) {
307
0
      r = starcos_add_esign_app(p15card);
308
0
      if (r == SC_SUCCESS) {
309
0
        label = name_ESign;
310
0
        apps_added++;
311
0
      }
312
0
    }
313
314
0
    if (apps_added > 0) {
315
      // pkcs11 requires the file_app
316
0
      struct sc_path path;
317
0
      struct sc_file *file = NULL;
318
0
      sc_path_set(&path, SC_PATH_TYPE_DF_NAME, aid->value, aid->len, 0, 0);
319
0
      r = sc_select_file(card, &path, &file);
320
0
      if (r != SC_SUCCESS || !file)
321
0
        return SC_ERROR_INTERNAL;
322
0
      sc_file_free(p15card->file_app);
323
0
      p15card->file_app = file;
324
0
    }
325
0
  }
326
327
0
  if (apps_added == 0) {
328
0
    LOG_TEST_RET(ctx, SC_ERROR_WRONG_CARD, "No supported app found on this card");
329
0
  }
330
331
0
  sc_pkcs15_free_tokeninfo(p15card->tokeninfo);
332
333
0
  p15card->tokeninfo = sc_pkcs15_tokeninfo_new();
334
0
  if (!p15card->tokeninfo) {
335
0
    LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "unable to create tokeninfo struct");
336
0
  } else {
337
0
    sc_serial_number_t serial;
338
0
    char serial_hex[SC_MAX_SERIALNR * 2 + 2];
339
0
    r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
340
0
    LOG_TEST_RET(ctx, r, "Failed to query card serial number");
341
342
0
    r = sc_bin_to_hex(serial.value, serial.len, serial_hex, sizeof serial_hex, 0);
343
0
    LOG_TEST_RET(ctx, r, "Failed to convert S/N to hex");
344
0
    p15card->tokeninfo->serial_number = strdup(serial_hex);
345
0
    p15card->tokeninfo->label = strdup(label);
346
0
    p15card->tokeninfo->manufacturer_id = strdup(name_Vendor);
347
0
    p15card->tokeninfo->flags = SC_PKCS15_TOKEN_READONLY;
348
0
  }
349
350
0
  LOG_FUNC_RETURN(ctx, SC_SUCCESS);
351
0
}
352
353
int
354
sc_pkcs15emu_starcos_esign_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
355
0
{
356
0
  int r = SC_ERROR_WRONG_CARD;
357
358
0
  if (!p15card || !p15card->card || !p15card->card->ctx)
359
0
    return SC_ERROR_INVALID_ARGUMENTS;
360
361
0
  r = starcos_esign_init(p15card, aid);
362
0
  LOG_FUNC_RETURN(p15card->card->ctx, r);
363
0
}