1 /*
2 * pkcs15-syn.c: PKCS #15 emulation of non-pkcs15 cards
3 *
4 * Copyright (C) 2003 Olaf Kirch <okir@suse.de>
5 * 2004 Nils Larsch <nlarsch@betrusted.com>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #if HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <assert.h>
30
31 #include "common/libscdl.h"
32 #include "internal.h"
33 #include "asn1.h"
34 #include "pkcs15.h"
35 #include "pkcs15-syn.h"
36
37 struct sc_pkcs15_emulator_handler builtin_emulators[] = {
38 { "westcos", sc_pkcs15emu_westcos_init_ex },
39 { "openpgp", sc_pkcs15emu_openpgp_init_ex },
40 { "starcert", sc_pkcs15emu_starcert_init_ex },
41 { "tcos", sc_pkcs15emu_tcos_init_ex },
42 { "esteid", sc_pkcs15emu_esteid_init_ex },
43 { "itacns", sc_pkcs15emu_itacns_init_ex },
44 { "PIV-II", sc_pkcs15emu_piv_init_ex },
45 { "cac", sc_pkcs15emu_cac_init_ex },
46 { "idprime", sc_pkcs15emu_idprime_init_ex },
47 { "gemsafeGPK", sc_pkcs15emu_gemsafeGPK_init_ex },
48 { "gemsafeV1", sc_pkcs15emu_gemsafeV1_init_ex },
49 { "actalis", sc_pkcs15emu_actalis_init_ex },
50 { "atrust-acos",sc_pkcs15emu_atrust_acos_init_ex},
51 { "tccardos", sc_pkcs15emu_tccardos_init_ex },
52 { "entersafe", sc_pkcs15emu_entersafe_init_ex },
53 { "pteid", sc_pkcs15emu_pteid_init_ex },
54 { "oberthur", sc_pkcs15emu_oberthur_init_ex },
55 { "sc-hsm", sc_pkcs15emu_sc_hsm_init_ex },
56 { "dnie", sc_pkcs15emu_dnie_init_ex },
57 { "gids", sc_pkcs15emu_gids_init_ex },
58 { "iasecc", sc_pkcs15emu_iasecc_init_ex },
59 { "jpki", sc_pkcs15emu_jpki_init_ex },
60 { "coolkey", sc_pkcs15emu_coolkey_init_ex },
61 { "din66291", sc_pkcs15emu_din_66291_init_ex },
62 { "esteid2018", sc_pkcs15emu_esteid2018_init_ex },
63 { "cardos", sc_pkcs15emu_cardos_init_ex },
64
65 { NULL, NULL }
66 };
67
68 static int parse_emu_block(sc_pkcs15_card_t *, struct sc_aid *, scconf_block *);
69 static sc_pkcs15_df_t * sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card,
70 unsigned int type);
71
72 static const char *builtin_name = "builtin";
73 static const char *func_name = "sc_pkcs15_init_func";
74 static const char *exfunc_name = "sc_pkcs15_init_func_ex";
75
76 // FIXME: have a flag in card->flags to indicate the same
sc_pkcs15_is_emulation_only(sc_card_t * card)77 int sc_pkcs15_is_emulation_only(sc_card_t *card)
78 {
79 switch (card->type) {
80 case SC_CARD_TYPE_MCRD_ESTEID_V30:
81 case SC_CARD_TYPE_GEMSAFEV1_PTEID:
82 case SC_CARD_TYPE_OPENPGP_V1:
83 case SC_CARD_TYPE_OPENPGP_V2:
84 case SC_CARD_TYPE_OPENPGP_GNUK:
85 case SC_CARD_TYPE_OPENPGP_V3:
86 case SC_CARD_TYPE_SC_HSM:
87 case SC_CARD_TYPE_SC_HSM_SOC:
88 case SC_CARD_TYPE_DNIE_BASE:
89 case SC_CARD_TYPE_DNIE_BLANK:
90 case SC_CARD_TYPE_DNIE_ADMIN:
91 case SC_CARD_TYPE_DNIE_USER:
92 case SC_CARD_TYPE_DNIE_TERMINATED:
93 case SC_CARD_TYPE_IASECC_GEMALTO:
94 case SC_CARD_TYPE_IASECC_CPX:
95 case SC_CARD_TYPE_IASECC_CPXCL:
96 case SC_CARD_TYPE_PIV_II_GENERIC:
97 case SC_CARD_TYPE_PIV_II_HIST:
98 case SC_CARD_TYPE_PIV_II_NEO:
99 case SC_CARD_TYPE_PIV_II_YUBIKEY4:
100 case SC_CARD_TYPE_ESTEID_2018:
101 case SC_CARD_TYPE_CARDOS_V5_0:
102 case SC_CARD_TYPE_CARDOS_V5_3:
103
104 return 1;
105 default:
106 return 0;
107 }
108 }
109
110 int
sc_pkcs15_bind_synthetic(sc_pkcs15_card_t * p15card,struct sc_aid * aid)111 sc_pkcs15_bind_synthetic(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
112 {
113 sc_context_t *ctx = p15card->card->ctx;
114 scconf_block *conf_block, **blocks, *blk;
115 int i, r = SC_ERROR_WRONG_CARD;
116
117 SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
118 conf_block = NULL;
119
120 conf_block = sc_get_conf_block(ctx, "framework", "pkcs15", 1);
121
122 if (!conf_block) {
123 /* no conf file found => try builtin drivers */
124 sc_log(ctx, "no conf file (or section), trying all builtin emulators");
125 for (i = 0; builtin_emulators[i].name; i++) {
126 sc_log(ctx, "trying %s", builtin_emulators[i].name);
127 r = builtin_emulators[i].handler(p15card, aid);
128 if (r == SC_SUCCESS)
129 /* we got a hit */
130 goto out;
131 }
132 } else {
133 /* we have a conf file => let's use it */
134 int builtin_enabled;
135 const scconf_list *list, *item;
136
137 builtin_enabled = scconf_get_bool(conf_block, "enable_builtin_emulation", 1);
138 list = scconf_find_list(conf_block, "builtin_emulators"); /* FIXME: rename to enabled_emulators */
139
140 if (builtin_enabled && list) {
141 /* get the list of enabled emulation drivers */
142 for (item = list; item; item = item->next) {
143 /* go through the list of builtin drivers */
144 const char *name = item->data;
145
146 sc_log(ctx, "trying %s", name);
147 for (i = 0; builtin_emulators[i].name; i++)
148 if (!strcmp(builtin_emulators[i].name, name)) {
149 r = builtin_emulators[i].handler(p15card, aid);
150 if (r == SC_SUCCESS)
151 /* we got a hit */
152 goto out;
153 }
154 }
155 }
156 else if (builtin_enabled) {
157 sc_log(ctx, "no emulator list in config file, trying all builtin emulators");
158 for (i = 0; builtin_emulators[i].name; i++) {
159 sc_log(ctx, "trying %s", builtin_emulators[i].name);
160 r = builtin_emulators[i].handler(p15card, aid);
161 if (r == SC_SUCCESS)
162 /* we got a hit */
163 goto out;
164 }
165 }
166
167 /* search for 'emulate foo { ... }' entries in the conf file */
168 sc_log(ctx, "searching for 'emulate foo { ... }' blocks");
169 blocks = scconf_find_blocks(ctx->conf, conf_block, "emulate", NULL);
170 sc_log(ctx, "Blocks: %p", blocks);
171 for (i = 0; blocks && (blk = blocks[i]) != NULL; i++) {
172 const char *name = blk->name->data;
173 sc_log(ctx, "trying %s", name);
174 r = parse_emu_block(p15card, aid, blk);
175 if (r == SC_SUCCESS) {
176 free(blocks);
177 goto out;
178 }
179 }
180 if (blocks)
181 free(blocks);
182 }
183
184 out:
185 if (r == SC_SUCCESS) {
186 p15card->magic = SC_PKCS15_CARD_MAGIC;
187 p15card->flags |= SC_PKCS15_CARD_FLAG_EMULATED;
188 } else {
189 if (r != SC_ERROR_WRONG_CARD)
190 sc_log(ctx, "Failed to load card emulator: %s", sc_strerror(r));
191 }
192
193 LOG_FUNC_RETURN(ctx, r);
194 }
195
196
parse_emu_block(sc_pkcs15_card_t * p15card,struct sc_aid * aid,scconf_block * conf)197 static int parse_emu_block(sc_pkcs15_card_t *p15card, struct sc_aid *aid, scconf_block *conf)
198 {
199 sc_card_t *card = p15card->card;
200 sc_context_t *ctx = card->ctx;
201 void *handle = NULL;
202 int (*init_func)(sc_pkcs15_card_t *);
203 int (*init_func_ex)(sc_pkcs15_card_t *, struct sc_aid *);
204 int r;
205 const char *driver, *module_name;
206
207 driver = conf->name->data;
208
209 init_func = NULL;
210 init_func_ex = NULL;
211
212 module_name = scconf_get_str(conf, "module", builtin_name);
213 if (!strcmp(module_name, "builtin")) {
214 int i;
215
216 /* This function is built into libopensc itself.
217 * Look it up in the table of emulators */
218 module_name = driver;
219 for (i = 0; builtin_emulators[i].name; i++) {
220 if (!strcmp(builtin_emulators[i].name, module_name)) {
221 init_func_ex = builtin_emulators[i].handler;
222 break;
223 }
224 }
225 } else {
226 const char *(*get_version)(void);
227 const char *name = NULL;
228 void *address;
229 unsigned int major = 0, minor = 0, fix = 0;
230
231 sc_log(ctx, "Loading %s", module_name);
232
233 /* try to open dynamic library */
234 handle = sc_dlopen(module_name);
235 if (!handle) {
236 sc_log(ctx, "unable to open dynamic library '%s': %s",
237 module_name, sc_dlerror());
238 return SC_ERROR_INTERNAL;
239 }
240
241 /* try to get version of the driver/api */
242 get_version = (const char *(*)(void)) sc_dlsym(handle, "sc_driver_version");
243 if (get_version) {
244 if (3 != sscanf(get_version(), "%u.%u.%u", &major, &minor, &fix)) {
245 sc_log(ctx, "unable to get modules version number");
246 sc_dlclose(handle);
247 return SC_ERROR_INTERNAL;
248 }
249 }
250
251 if (!get_version || (major == 0 && minor <= 9 && fix < 3)) {
252 /* no sc_driver_version function => assume old style
253 * init function (note: this should later give an error
254 */
255 /* get the init function name */
256 name = scconf_get_str(conf, "function", func_name);
257
258 address = sc_dlsym(handle, name);
259 if (address)
260 init_func = (int (*)(sc_pkcs15_card_t *)) address;
261 } else {
262 name = scconf_get_str(conf, "function", exfunc_name);
263
264 address = sc_dlsym(handle, name);
265 if (address)
266 init_func_ex = (int (*)(sc_pkcs15_card_t *, struct sc_aid *)) address;
267 }
268 }
269 /* try to initialize the pkcs15 structures */
270 if (init_func_ex)
271 r = init_func_ex(p15card, aid);
272 else if (init_func)
273 r = init_func(p15card);
274 else
275 r = SC_ERROR_WRONG_CARD;
276
277 if (r >= 0) {
278 sc_log(card->ctx, "%s succeeded, card bound", module_name);
279 p15card->dll_handle = handle;
280 } else {
281 sc_log(card->ctx, "%s failed: %s", module_name, sc_strerror(r));
282 /* clear pkcs15 card */
283 sc_pkcs15_card_clear(p15card);
284 if (handle)
285 sc_dlclose(handle);
286 }
287
288 return r;
289 }
290
sc_pkcs15emu_get_df(sc_pkcs15_card_t * p15card,unsigned int type)291 static sc_pkcs15_df_t * sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card,
292 unsigned int type)
293 {
294 sc_pkcs15_df_t *df;
295 sc_file_t *file;
296 int created = 0;
297
298 while (1) {
299 for (df = p15card->df_list; df; df = df->next) {
300 if (df->type == type) {
301 if (created)
302 df->enumerated = 1;
303 return df;
304 }
305 }
306
307 assert(created == 0);
308
309 file = sc_file_new();
310 if (!file)
311 return NULL;
312 sc_format_path("11001101", &file->path);
313 sc_pkcs15_add_df(p15card, type, &file->path);
314 sc_file_free(file);
315 created++;
316 }
317 }
318
sc_pkcs15emu_add_pin_obj(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_auth_info_t * in_pin)319 int sc_pkcs15emu_add_pin_obj(sc_pkcs15_card_t *p15card,
320 const sc_pkcs15_object_t *obj, const sc_pkcs15_auth_info_t *in_pin)
321 {
322 sc_pkcs15_auth_info_t pin = *in_pin;
323
324 pin.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
325 if(!pin.auth_method) /* or SC_AC_NONE */
326 pin.auth_method = SC_AC_CHV;
327
328 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_AUTH_PIN, obj, &pin);
329 }
330
sc_pkcs15emu_add_rsa_prkey(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_prkey_info_t * in_key)331 int sc_pkcs15emu_add_rsa_prkey(sc_pkcs15_card_t *p15card,
332 const sc_pkcs15_object_t *obj, const sc_pkcs15_prkey_info_t *in_key)
333 {
334 sc_pkcs15_prkey_info_t key = *in_key;
335
336 if (key.access_flags == 0)
337 key.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
338 | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
339 | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
340 | SC_PKCS15_PRKEY_ACCESS_LOCAL;
341
342 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PRKEY_RSA, obj, &key);
343 }
344
sc_pkcs15emu_add_rsa_pubkey(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_pubkey_info_t * in_key)345 int sc_pkcs15emu_add_rsa_pubkey(sc_pkcs15_card_t *p15card,
346 const sc_pkcs15_object_t *obj, const sc_pkcs15_pubkey_info_t *in_key)
347 {
348 sc_pkcs15_pubkey_info_t key = *in_key;
349
350 if (key.access_flags == 0)
351 key.access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
352
353 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PUBKEY_RSA, obj, &key);
354 }
355
sc_pkcs15emu_add_ec_prkey(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_prkey_info_t * in_key)356 int sc_pkcs15emu_add_ec_prkey(sc_pkcs15_card_t *p15card,
357 const sc_pkcs15_object_t *obj, const sc_pkcs15_prkey_info_t *in_key)
358 {
359 sc_pkcs15_prkey_info_t key = *in_key;
360
361 if (key.access_flags == 0)
362 key.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
363 | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
364 | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
365 | SC_PKCS15_PRKEY_ACCESS_LOCAL;
366
367 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PRKEY_EC, obj, &key);
368 }
369
sc_pkcs15emu_add_ec_pubkey(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_pubkey_info_t * in_key)370 int sc_pkcs15emu_add_ec_pubkey(sc_pkcs15_card_t *p15card,
371 const sc_pkcs15_object_t *obj, const sc_pkcs15_pubkey_info_t *in_key)
372 {
373 sc_pkcs15_pubkey_info_t key = *in_key;
374
375 if (key.access_flags == 0)
376 key.access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
377
378 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PUBKEY_EC, obj, &key);
379 }
380
sc_pkcs15emu_add_eddsa_prkey(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_prkey_info_t * in_key)381 int sc_pkcs15emu_add_eddsa_prkey(sc_pkcs15_card_t *p15card,
382 const sc_pkcs15_object_t *obj, const sc_pkcs15_prkey_info_t *in_key)
383 {
384 sc_pkcs15_prkey_info_t key = *in_key;
385
386 if (key.access_flags == 0)
387 key.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
388 | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
389 | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
390 | SC_PKCS15_PRKEY_ACCESS_LOCAL;
391
392 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PRKEY_EDDSA, obj, &key);
393 }
394
sc_pkcs15emu_add_eddsa_pubkey(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_pubkey_info_t * in_key)395 int sc_pkcs15emu_add_eddsa_pubkey(sc_pkcs15_card_t *p15card,
396 const sc_pkcs15_object_t *obj, const sc_pkcs15_pubkey_info_t *in_key)
397 {
398 sc_pkcs15_pubkey_info_t key = *in_key;
399
400 if (key.access_flags == 0)
401 key.access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
402
403 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PUBKEY_EDDSA, obj, &key);
404 }
405
sc_pkcs15emu_add_xeddsa_prkey(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_prkey_info_t * in_key)406 int sc_pkcs15emu_add_xeddsa_prkey(sc_pkcs15_card_t *p15card,
407 const sc_pkcs15_object_t *obj, const sc_pkcs15_prkey_info_t *in_key)
408 {
409 sc_pkcs15_prkey_info_t key = *in_key;
410
411 if (key.access_flags == 0)
412 key.access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
413 | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
414 | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
415 | SC_PKCS15_PRKEY_ACCESS_LOCAL;
416
417 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PRKEY_XEDDSA, obj, &key);
418 }
419
sc_pkcs15emu_add_xeddsa_pubkey(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_pubkey_info_t * in_key)420 int sc_pkcs15emu_add_xeddsa_pubkey(sc_pkcs15_card_t *p15card,
421 const sc_pkcs15_object_t *obj, const sc_pkcs15_pubkey_info_t *in_key)
422 {
423 sc_pkcs15_pubkey_info_t key = *in_key;
424
425 if (key.access_flags == 0)
426 key.access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
427
428 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_PUBKEY_XEDDSA, obj, &key);
429 }
430
sc_pkcs15emu_add_x509_cert(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_cert_info_t * cert)431 int sc_pkcs15emu_add_x509_cert(sc_pkcs15_card_t *p15card,
432 const sc_pkcs15_object_t *obj, const sc_pkcs15_cert_info_t *cert)
433 {
434 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_CERT_X509, obj, cert);
435 }
436
sc_pkcs15emu_add_data_object(sc_pkcs15_card_t * p15card,const sc_pkcs15_object_t * obj,const sc_pkcs15_data_info_t * data)437 int sc_pkcs15emu_add_data_object(sc_pkcs15_card_t *p15card,
438 const sc_pkcs15_object_t *obj, const sc_pkcs15_data_info_t *data)
439 {
440 return sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, obj, data);
441 }
442
sc_pkcs15emu_object_add(sc_pkcs15_card_t * p15card,unsigned int type,const sc_pkcs15_object_t * in_obj,const void * data)443 int sc_pkcs15emu_object_add(sc_pkcs15_card_t *p15card, unsigned int type,
444 const sc_pkcs15_object_t *in_obj, const void *data)
445 {
446 sc_pkcs15_object_t *obj;
447 unsigned int df_type;
448 size_t data_len;
449
450 SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
451
452 obj = calloc(1, sizeof(*obj));
453 if (!obj) {
454 LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
455 }
456
457 memcpy(obj, in_obj, sizeof(*obj));
458 obj->type = type;
459
460 switch (type & SC_PKCS15_TYPE_CLASS_MASK) {
461 case SC_PKCS15_TYPE_AUTH:
462 df_type = SC_PKCS15_AODF;
463 data_len = sizeof(struct sc_pkcs15_auth_info);
464 break;
465 case SC_PKCS15_TYPE_PRKEY:
466 df_type = SC_PKCS15_PRKDF;
467 data_len = sizeof(struct sc_pkcs15_prkey_info);
468 break;
469 case SC_PKCS15_TYPE_PUBKEY:
470 df_type = SC_PKCS15_PUKDF;
471 data_len = sizeof(struct sc_pkcs15_pubkey_info);
472 break;
473 case SC_PKCS15_TYPE_CERT:
474 df_type = SC_PKCS15_CDF;
475 data_len = sizeof(struct sc_pkcs15_cert_info);
476 break;
477 case SC_PKCS15_TYPE_DATA_OBJECT:
478 df_type = SC_PKCS15_DODF;
479 data_len = sizeof(struct sc_pkcs15_data_info);
480 break;
481 default:
482 sc_log(p15card->card->ctx, "Unknown PKCS15 object type %d", type);
483 free(obj);
484 LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_INVALID_ARGUMENTS);
485 }
486
487 obj->data = calloc(1, data_len);
488 if (obj->data == NULL) {
489 free(obj);
490 LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY);
491 }
492 memcpy(obj->data, data, data_len);
493
494 obj->df = sc_pkcs15emu_get_df(p15card, df_type);
495 sc_pkcs15_add_object(p15card, obj);
496
497 LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
498 }
499
500