diff --git a/src/libopensc/module.c b/src/libopensc/module.c index 7becd787..e6623f3a 100644 --- a/src/libopensc/module.c +++ b/src/libopensc/module.c @@ -70,7 +70,7 @@ int sc_module_get_address(struct sc_context *ctx, void *mod_handle, void **sym_a if (address == NULL) { if (ctx->debug) /* TODO: scdl_error */ - sc_debug(ctx, "sc_module_get_address: unknown error"); + sc_debug(ctx, "sc_module_get_address: unable to get symbol %s\n", sym_name); return SC_ERROR_UNKNOWN; } *sym_address = address; diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 0d37e467..71119d15 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -865,6 +865,13 @@ struct sc_card_error { extern const char *sc_get_version(void); +#define IMPLEMENT_DRIVER_VERSION(a) \ + static const char *drv_version = (a); \ + const char *sc_driver_version()\ + { \ + return drv_version; \ + } + extern struct sc_reader_driver *sc_get_pcsc_driver(void); extern struct sc_reader_driver *sc_get_ctapi_driver(void); extern struct sc_reader_driver *sc_get_openct_driver(void); diff --git a/src/libopensc/pkcs15-esteid.c b/src/libopensc/pkcs15-esteid.c index 343118bf..4a5554af 100644 --- a/src/libopensc/pkcs15-esteid.c +++ b/src/libopensc/pkcs15-esteid.c @@ -197,3 +197,40 @@ sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card) } return 0; } + +static const char *atr1 = "3B:FE:94:00:FF:80:B1:FA:45:1F:03:45:73:74:45:49:44:20:76:65:72:20:31:2E:30:43"; +static const char *atr2 = "3B:6E:00:FF:45:73:74:45:49:44:20:76:65:72:20:31:2E:30"; + +static int esteid_detect_card(sc_pkcs15_card_t *p15card) +{ + u8 buf[SC_MAX_ATR_SIZE]; + size_t len = sizeof(buf); + sc_card_t *card = p15card->card; + + /* XXX: save type of the micardo card in the card structure */ + if (sc_hex_to_bin(atr1, buf, &len)) + return SC_ERROR_INTERNAL; + if (len == card->atr_len && !memcmp(card->atr, buf, len)) + return SC_SUCCESS; + len = sizeof(buf); + if (sc_hex_to_bin(atr2, buf, &len)) + return SC_ERROR_INTERNAL; + if (len == card->atr_len && !memcmp(card->atr, buf, len)) + return SC_SUCCESS; + + return SC_ERROR_WRONG_CARD; +} + +int sc_pkcs15emu_esteid_init_ex(sc_pkcs15_card_t *p15card, + sc_pkcs15emu_opt_t *opts) +{ + + if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK) + return sc_pkcs15emu_esteid_init(p15card); + else { + int r = esteid_detect_card(p15card); + if (r) + return SC_ERROR_WRONG_CARD; + return sc_pkcs15emu_esteid_init(p15card); + } +} diff --git a/src/libopensc/pkcs15-infocamere.c b/src/libopensc/pkcs15-infocamere.c index 3aed50db..f38ffe93 100644 --- a/src/libopensc/pkcs15-infocamere.c +++ b/src/libopensc/pkcs15-infocamere.c @@ -73,7 +73,7 @@ sc_pkcs15emu_infocamere_init(sc_pkcs15_card_t *p15card) int r; size_t len_chn, len_iccsn; - sc_format_path("2F02", &path); + sc_format_path("3F002F02", &path); r = sc_select_file(card, &path, &file); @@ -262,9 +262,33 @@ sc_pkcs15emu_infocamere_init(sc_pkcs15_card_t *p15card) return 0; -failed: sc_error(card->ctx, "Failed to initialize Infocamere SPK2.3 emulation: %s\n", - sc_strerror(r)); +failed: + if (r != SC_ERROR_WRONG_CARD) + sc_error(card->ctx, "Failed to initialize Infocamere SPK2.3 emulation: %s\n", sc_strerror(r)); return r; } +static int infocamere_detect_card(sc_pkcs15_card_t *p15card) +{ + sc_card_t *card = p15card->card; + + /* check if we have the correct card OS */ + if (strcmp(card->name, "STARCOS SPK 2.3")) + return SC_ERROR_WRONG_CARD; + return SC_SUCCESS; +} + + +int sc_pkcs15emu_infocamere_init_ex(sc_pkcs15_card_t *p15card, + sc_pkcs15emu_opt_t *opts) +{ + if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK) + return sc_pkcs15emu_infocamere_init(p15card); + else { + int r = infocamere_detect_card(p15card); + if (r) + return SC_ERROR_WRONG_CARD; + return sc_pkcs15emu_infocamere_init(p15card); + } +} diff --git a/src/libopensc/pkcs15-netkey.c b/src/libopensc/pkcs15-netkey.c index 0468bfb0..9a2a4481 100644 --- a/src/libopensc/pkcs15-netkey.c +++ b/src/libopensc/pkcs15-netkey.c @@ -194,3 +194,33 @@ failed: sc_debug(card->ctx, "Failed to initialize TeleSec Netkey E4 emulation: %s\n", sc_strerror(r)); return r; } + +static int netkey_detect_card(sc_pkcs15_card_t *p15card) +{ + int r; + sc_path_t path; + sc_card_t *card = p15card->card; + + /* check if we have the correct card OS */ + if (strcmp(card->name, "TCOS")) + return SC_ERROR_WRONG_CARD; + /* check if we have a df01 DF */ + sc_format_path("3F00DF01", &path); + r = sc_select_file(card, &path, NULL); + if (r < 0) + return SC_ERROR_WRONG_CARD; + return SC_SUCCESS; +} + +int sc_pkcs15emu_netkey_init_ex(sc_pkcs15_card_t *p15card, + sc_pkcs15emu_opt_t *opts) +{ + if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK) + return sc_pkcs15emu_netkey_init(p15card); + else { + int r = netkey_detect_card(p15card); + if (r) + return SC_ERROR_WRONG_CARD; + return sc_pkcs15emu_netkey_init(p15card); + } +} diff --git a/src/libopensc/pkcs15-openpgp.c b/src/libopensc/pkcs15-openpgp.c index 591ff397..d2713121 100644 --- a/src/libopensc/pkcs15-openpgp.c +++ b/src/libopensc/pkcs15-openpgp.c @@ -201,3 +201,21 @@ failed: sc_error(card->ctx, "Failed to initialize OpenPGP emulation: %s\n", return r; } + +static int openpgp_detect_card(sc_pkcs15_card_t *p15card) +{ + return strcmp(p15card->card->name, "OpenPGP"); +} + +int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *p15card, + sc_pkcs15emu_opt_t *opts) +{ + if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK) + return sc_pkcs15emu_openpgp_init(p15card); + else { + int r = openpgp_detect_card(p15card); + if (r) + return SC_ERROR_WRONG_CARD; + return sc_pkcs15emu_openpgp_init(p15card); + } +} diff --git a/src/libopensc/pkcs15-starcert.c b/src/libopensc/pkcs15-starcert.c index 6804f0d0..98c4ca39 100644 --- a/src/libopensc/pkcs15-starcert.c +++ b/src/libopensc/pkcs15-starcert.c @@ -98,7 +98,7 @@ const prdata prkeys[] = { { NULL, NULL, 0, 0, NULL, 0, NULL, 0} }; -int get_cert_len(sc_card_t *card, sc_path_t *path) +static int get_cert_len(sc_card_t *card, sc_path_t *path) { int r; u8 buf[8]; @@ -117,6 +117,32 @@ int get_cert_len(sc_card_t *card, sc_path_t *path) return 1; } +static int starcert_detect_card(sc_pkcs15_card_t *p15card) +{ + int r; + u8 buf[128]; + sc_path_t path; + sc_card_t *card = p15card->card; + + /* check if we have the correct card OS */ + if (strcmp(card->name, "STARCOS SPK 2.3")) + return SC_ERROR_WRONG_CARD; + /* read EF_Info file */ + sc_format_path("3F00FE13", &path); + card->ctx->suppress_errors++; + r = sc_select_file(card, &path, NULL); + card->ctx->suppress_errors--; + if (r != SC_SUCCESS) + return SC_ERROR_WRONG_CARD; + r = sc_read_binary(card, 0, buf, 64, 0); + if (r != 64) + return SC_ERROR_WRONG_CARD; + if (memcmp(buf + 24, STARCERT, strlen(STARCERT))) + return SC_ERROR_WRONG_CARD; + + return SC_SUCCESS; +} + int sc_pkcs15emu_starcert_init(sc_pkcs15_card_t *p15card) { int r, i; @@ -126,21 +152,6 @@ int sc_pkcs15emu_starcert_init(sc_pkcs15_card_t *p15card) struct sc_card *card = p15card->card; struct sc_serial_number serial; - /* check if we have the correct card OS */ - if (strcmp(card->name, "STARCOS SPK 2.3")) - return SC_ERROR_WRONG_CARD; - /* read EF_Info file */ - sc_format_path("3F00FE13", &path); - card->ctx->suppress_errors++; - r = sc_select_file(card, &path, &file); - card->ctx->suppress_errors--; - if (r != SC_SUCCESS) - return SC_ERROR_WRONG_CARD; - r = sc_read_binary(card, 0, buf, 64, 0); - if (r != 64) - return SC_ERROR_WRONG_CARD; - if (memcmp(buf + 24, STARCERT, strlen(STARCERT))) - return SC_ERROR_WRONG_CARD; /* get serial number */ r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial); r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0); @@ -217,3 +228,17 @@ int sc_pkcs15emu_starcert_init(sc_pkcs15_card_t *p15card) return SC_SUCCESS; } + +int sc_pkcs15emu_starcert_init_ex(sc_pkcs15_card_t *p15card, + sc_pkcs15emu_opt_t *opts) +{ + + if (opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK) + return sc_pkcs15emu_starcert_init(p15card); + else { + int r = starcert_detect_card(p15card); + if (r) + return SC_ERROR_WRONG_CARD; + return sc_pkcs15emu_starcert_init(p15card); + } +} diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c index 35cf84cc..79743d6d 100644 --- a/src/libopensc/pkcs15-syn.c +++ b/src/libopensc/pkcs15-syn.c @@ -2,6 +2,7 @@ * pkcs15-syn.c: PKCS #15 emulation of non-pkcs15 cards * * Copyright (C) 2003 Olaf Kirch + * 2004 Nils Larsch * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,39 +27,47 @@ #include #include -static int sc_pkcs15_bind_emulation(sc_pkcs15_card_t *, const char *, - scconf_block *, int); - -extern int sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *); -extern int sc_pkcs15emu_infocamere_init(sc_pkcs15_card_t *); -extern int sc_pkcs15emu_starcert_init(sc_pkcs15_card_t *); -extern int sc_pkcs15emu_netkey_init(sc_pkcs15_card_t *); -extern int sc_pkcs15emu_esteid_init(sc_pkcs15_card_t *); +extern int sc_pkcs15emu_openpgp_init_ex(sc_pkcs15_card_t *, + sc_pkcs15emu_opt_t *); +extern int sc_pkcs15emu_infocamere_init_ex(sc_pkcs15_card_t *, + sc_pkcs15emu_opt_t *); +extern int sc_pkcs15emu_starcert_init_ex(sc_pkcs15_card_t *, + sc_pkcs15emu_opt_t *); +extern int sc_pkcs15emu_netkey_init_ex(sc_pkcs15_card_t *, + sc_pkcs15emu_opt_t *); +extern int sc_pkcs15emu_esteid_init_ex(sc_pkcs15_card_t *, + sc_pkcs15emu_opt_t *); static struct { const char * name; - int (*handler)(sc_pkcs15_card_t *); + int (*handler)(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *); } builtin_emulators[] = { - { "openpgp", sc_pkcs15emu_openpgp_init }, - { "infocamere", sc_pkcs15emu_infocamere_init }, - { "starcert", sc_pkcs15emu_starcert_init }, - { "netkey", sc_pkcs15emu_netkey_init }, - { "esteid", sc_pkcs15emu_esteid_init }, + { "openpgp", sc_pkcs15emu_openpgp_init_ex }, + { "infocamere", sc_pkcs15emu_infocamere_init_ex }, + { "starcert", sc_pkcs15emu_starcert_init_ex }, + { "netkey", sc_pkcs15emu_netkey_init_ex }, + { "esteid", sc_pkcs15emu_esteid_init_ex }, { NULL } }; +static int parse_emu_block(sc_pkcs15_card_t *, scconf_block *); + +static const char *builtin_name = "builtin"; +static const char *func_name = "sc_pkcs15_init_func"; +static const char *exfunc_name = "sc_pkcs15_init_func_ex"; + int -sc_pkcs15_bind_synthetic(sc_pkcs15_card_t *p15card, int check_atr) +sc_pkcs15_bind_synthetic(sc_pkcs15_card_t *p15card) { sc_context_t *ctx = p15card->card->ctx; - const scconf_list *clist, *tmp; scconf_block *conf_block, **blocks, *blk; - int i, r; + sc_pkcs15emu_opt_t opts; + int i, r = SC_ERROR_WRONG_CARD; SC_FUNC_CALLED(ctx, 1); - assert(p15card); + memset(&opts, 0, sizeof(opts)); conf_block = NULL; for (i = 0; ctx->conf_blocks[i] != NULL; i++) { @@ -68,43 +77,60 @@ sc_pkcs15_bind_synthetic(sc_pkcs15_card_t *p15card, int check_atr) conf_block = blocks[0]; free(blocks); } - if (!conf_block) - return SC_ERROR_WRONG_CARD; - /* Old-style: get the pkcs15_syn libs from the conf file */ - clist = scconf_find_list(conf_block, "pkcs15_syn"); - for (tmp = clist; tmp != NULL; tmp = tmp->next) { - const char *module = tmp->data; - - if (module == NULL) - continue; - r = sc_pkcs15_bind_emulation(p15card, module, NULL, check_atr); - if (r != SC_ERROR_WRONG_CARD) - goto out; - } - - /* New-style: get lib name, function name, ATR list */ - blocks = scconf_find_blocks(ctx->conf, conf_block, "emulate", NULL); - for (i = 0; (blk = blocks[i]) != NULL; i++) { - const char *module; - - module = scconf_get_str(blk, "module", NULL); - if (!module) - continue; - - r = sc_pkcs15_bind_emulation(p15card, module, blk, check_atr); - if (r != SC_ERROR_WRONG_CARD) { - free(blocks); - goto out; + if (!conf_block) { + /* no conf file found => try the internal drivers */ + sc_debug(ctx, "no conf file, trying builtin emulators\n"); + for (i = 0; builtin_emulators[i].name; i++) { + sc_debug(ctx, "trying %s\n", builtin_emulators[i].name); + r = builtin_emulators[i].handler(p15card, &opts); + if (r == SC_SUCCESS) + /* we got a hit */ + goto out; } - } - free(blocks); + } else { + /* we have a conf file => let's use it */ + const scconf_list *list, *item; + /* find out if the internal drivers should be used */ + i = scconf_get_bool(conf_block, "enable_builtin_emulation", 1); + if (i) { + /* get the list of the internal drivers */ + sc_debug(ctx, "use builtin drivers\n"); + list = scconf_find_list(conf_block, "builtin_emulators"); + for (item = list; item; item = item->next) { + /* get through the list of builtin drivers */ + const char *name = item->data; + sc_debug(ctx, "trying %s\n", name); + for (i = 0; builtin_emulators[i].name; i++) + if (!strcmp(builtin_emulators[i].name, name)) { + r = builtin_emulators[i].handler(p15card, &opts); + if (r == SC_SUCCESS) + goto out; + } + } + } + /* search for 'emulate foo { ... }' entries in the conf file */ + sc_debug(ctx, "searching for 'emulate foo { ... }' blocks\n"); + blocks = scconf_find_blocks(ctx->conf, conf_block, "emulate", NULL); + + for (i = 0; (blk = blocks[i]) != NULL; i++) { + const char *name = blk->name->data; + sc_debug(ctx, "trying %s\n", name); + r = parse_emu_block(p15card, blk); + if (r == SC_SUCCESS) { + free(blocks); + goto out; + } + } + if (blocks) + free(blocks); + } + /* Total failure */ return SC_ERROR_WRONG_CARD; out: if (r == SC_SUCCESS) { - /* p15card->flags |= SC_PKCS15_CARD_FLAG_READONLY; */ p15card->magic = 0x10203040; } else if (r != SC_ERROR_WRONG_CARD) { sc_error(ctx, "Failed to load card emulator: %s\n", @@ -114,94 +140,119 @@ out: if (r == SC_SUCCESS) { return r; } -int -sc_pkcs15_bind_emulation(sc_pkcs15_card_t *p15card, - const char *module_name, - scconf_block *conf, - int check_atr) +static int emu_detect_card(const sc_card_t *card, const scconf_block *blk) +{ + int r = 1, match = 0; + const scconf_list *list, *item; + /* currently only ATR matching is supported (more to follow) */ + + /* check the ATR */ + list = scconf_find_list(blk, "atr"); + if (list) { + for (item = list; item; item = item->next) { + u8 atr[SC_MAX_ATR_SIZE]; + size_t len = sizeof(atr); + + if (!item->data) + /* skip empty data */ + continue; + if (sc_hex_to_bin(item->data, atr, &len) != SC_SUCCESS) + /* ignore errors, try next atr */ + continue; + if (len == card->atr_len && !memcmp(card->atr, atr, len)){ + match = 1; + break; + } + } + if (match) + r = 1; + else + r = 0; + } + + return r; +} + +static int parse_emu_block(sc_pkcs15_card_t *p15card, scconf_block *conf) { sc_card_t *card = p15card->card; sc_context_t *ctx = card->ctx; - const scconf_list *list, *item; + sc_pkcs15emu_opt_t opts; void *dll = NULL; int (*init_func)(sc_pkcs15_card_t *); + int (*init_func_ex)(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *); int r; + const char *module_name; - if (conf && (list = scconf_find_list(conf, "atr"))) { - int match = 0; - - if (!check_atr) - return SC_ERROR_WRONG_CARD; - for (item = list; item; item = item->next) { - u8 atr[SC_MAX_ATR_SIZE]; - size_t len = sizeof(atr); - - if (!item->data) - continue; - if (sc_hex_to_bin(item->data, atr, &len)) - continue; - if (len > card->atr_len - || memcmp(card->atr, atr, len)) - continue; - match = 1; - break; - } - if (!match) - return SC_ERROR_WRONG_CARD; - } else if (!check_atr) { - /* ATR checking required, but no ATR list to match against */ + r = emu_detect_card(card, conf); + if (!r) return SC_ERROR_WRONG_CARD; - } - init_func = NULL; + init_func = NULL; + init_func_ex = NULL; + opts.blk = conf; + opts.flags = SC_PKCS15EMU_FLAGS_NO_CHECK; + + module_name = scconf_get_str(conf, "module", builtin_name); + if (!strcmp(module_name, "builtin")) { int i; /* This function is built into libopensc itself. * Look it up in the table of emulators */ - if (conf == NULL || !conf->name) + if (!conf->name) return SC_ERROR_INTERNAL; module_name = conf->name->data; for (i = 0; builtin_emulators[i].name; i++) { if (!strcmp(builtin_emulators[i].name, module_name)) { - init_func = builtin_emulators[i].handler; + init_func_ex = builtin_emulators[i].handler; break; } } - if (!init_func) - return SC_ERROR_WRONG_CARD; } else { - const char *function_name = NULL; + const char *(*get_version)(void); + const char *name = NULL; void *address; - if (ctx->debug >= 4) - sc_debug(ctx, "Loading %s\n", module_name); - + sc_debug(ctx, "Loading %s\n", module_name); + /* try to open dynamic library */ r = sc_module_open(ctx, &dll, module_name); if (r != SC_SUCCESS) return r; + /* try to get version of the driver/api */ + r = sc_module_get_address(ctx, dll, &address, "sc_driver_version"); + if (r < 0) + get_version = NULL; + else + get_version = (const char *(*)())address; + if (!get_version || strcmp(get_version(), "0.9.3") < 0) { + /* no sc_driver_version function => assume old style + * init function (note: this should later give an error + */ + /* get the init function name */ + name = scconf_get_str(conf, "function", func_name); - /* get a handle to the pkcs15 init function - * XXX the init_func should not modify the contents of - * sc_pkcs15_card_t unless the card is really the one - * the driver is intended for -- Nils - */ - if (conf) - function_name = scconf_get_str(conf, "function", NULL); - if (function_name == NULL) - function_name = "sc_pkcs15_init_func"; + r = sc_module_get_address(ctx, dll, &address, name); + if (r == SC_SUCCESS) + init_func = (int (*)(sc_pkcs15_card_t *)) address; + } else { + name = scconf_get_str(conf, "function", exfunc_name); - r = sc_module_get_address(ctx, dll, &address, function_name); - if (r != SC_SUCCESS) - return r; - - /* try to initialize synthetic pkcs15 structures */ - init_func = (int (*)(sc_pkcs15_card_t *)) address; + r = sc_module_get_address(ctx, dll, &address, name); + if (r == SC_SUCCESS) + init_func_ex = (int (*)(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *)) address; + } } + /* try to initialize the pkcs15 structures */ + if (init_func_ex) + r = init_func_ex(p15card, &opts); + else if (init_func) + r = init_func(p15card); + else + r = SC_ERROR_WRONG_CARD; - r = init_func(p15card); if (r >= 0) { sc_debug(card->ctx, "%s succeeded, card bound\n", module_name); @@ -209,6 +260,8 @@ sc_pkcs15_bind_emulation(sc_pkcs15_card_t *p15card, } else if (ctx->debug >= 4) { sc_debug(card->ctx, "%s failed: %s\n", module_name, sc_strerror(r)); + /* clear pkcs15 card */ + sc_pkcs15_card_clear(p15card); if (dll) sc_module_close(ctx, dll); } diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index cb9121a9..3940e7af 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -222,9 +222,9 @@ static int encode_ddo(struct sc_pkcs15_card *p15card, u8 **buf, size_t *buflen) } #endif +#if 0 int sc_pkcs15_create_dir(struct sc_pkcs15_card *p15card, struct sc_card *card) { -#if 0 struct sc_path path; struct sc_file file; u8 *buf; @@ -266,9 +266,9 @@ int sc_pkcs15_create_dir(struct sc_pkcs15_card *p15card, struct sc_card *card) r = sc_update_binary(card, 0, buf, bufsize, 0); free(buf); SC_TEST_RET(card->ctx, r, "Error updating EF(DIR)"); -#endif return 0; } +#endif static const struct sc_asn1_entry c_asn1_odf[] = { { "privateKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, NULL }, @@ -420,70 +420,70 @@ void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card) free(p15card); } -int sc_pkcs15_bind(struct sc_card *card, - struct sc_pkcs15_card **p15card_out) +void sc_pkcs15_card_clear(sc_pkcs15_card_t *p15card) +{ + p15card->version = 0; + p15card->flags = 0; + while (p15card->obj_list) + sc_pkcs15_remove_object(p15card, p15card->obj_list); + p15card->obj_list = NULL; + while (p15card->df_list) + sc_pkcs15_remove_df(p15card, p15card->df_list); + p15card->df_list = NULL; + if (p15card->file_app) { + sc_file_free(p15card->file_app); + p15card->file_app = NULL; + } + if (p15card->file_tokeninfo) { + sc_file_free(p15card->file_tokeninfo); + p15card->file_tokeninfo = NULL; + } + if (p15card->file_odf) { + sc_file_free(p15card->file_odf); + p15card->file_odf = NULL; + } + if (p15card->label) { + free(p15card->label); + p15card->label = NULL; + } + if (p15card->serial_number) { + free(p15card->serial_number); + p15card->serial_number = NULL; + } + if (p15card->manufacturer_id) { + free(p15card->manufacturer_id); + p15card->manufacturer_id = NULL; + } + if (p15card->preferred_language) { + free(p15card->preferred_language); + p15card->preferred_language = NULL; + } +} + +static int sc_pkcs15_bind_internal(sc_pkcs15_card_t *p15card) { unsigned char buf[SC_MAX_APDU_BUFFER_SIZE]; - int err; + int err, ok = 0; size_t len; - struct sc_pkcs15_card *p15card = NULL; struct sc_path tmppath; - struct sc_context *ctx; - scconf_block *conf_block = NULL, **blocks; - int i; + struct sc_card *card = p15card->card; + struct sc_context *ctx = card->ctx; - assert(sc_card_valid(card) && p15card_out != NULL); - ctx = card->ctx; - SC_FUNC_CALLED(ctx, 1); - p15card = sc_pkcs15_card_new(); - if (p15card == NULL) - return SC_ERROR_OUT_OF_MEMORY; - p15card->card = card; - - for (i = 0; ctx->conf_blocks[i] != NULL; i++) { - blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], - "framework", "pkcs15"); - if (blocks[0] != NULL) - conf_block = blocks[0]; - free(blocks); - } - if (conf_block) - p15card->opts.use_cache = scconf_get_bool(conf_block, "use_caching", 0); - - err = sc_lock(card); - if (err) { - sc_error(ctx, "sc_lock() failed: %s\n", sc_strerror(err)); - sc_pkcs15_card_free(p15card); - SC_FUNC_RETURN(ctx, 1, err); - } - - /* Check for non-pkcs15 cards that we emulate. We do this - * twice - first, we check all emulators that list the ATRs - * they match - the OpenPGP emulator is one of them. - * - * If we find no emulator at this stage, we do the normal - * pkcs15 stuff - looking for EF(DIR), trying to locate the - * application DF, parsing EF(TokenInfo) etc etc. - * - * If that fails, too, we check all other emulators as a last - * resort. - */ - err = sc_pkcs15_bind_synthetic(p15card, 1); - if (err >= 0) - goto done; + if (ctx->debug > 4) + sc_debug(ctx, "trying normal pkcs15 processing\n"); /* Enumerate apps now */ if (card->app_count < 0) { err = sc_enum_apps(card); if (err < 0 && err != SC_ERROR_FILE_NOT_FOUND) { sc_error(ctx, "unable to enumerate apps: %s\n", sc_strerror(err)); - goto error; + goto end; } } p15card->file_app = sc_file_new(); if (p15card->file_app == NULL) { err = SC_ERROR_OUT_OF_MEMORY; - goto error; + goto end; } sc_format_path("3F005015", &p15card->file_app->path); if (card->app_count > 0) { @@ -502,12 +502,8 @@ int sc_pkcs15_bind(struct sc_card *card, card->ctx->suppress_errors++; err = sc_select_file(card, &p15card->file_app->path, NULL); card->ctx->suppress_errors--; - if (err < 0) { - err = sc_pkcs15_bind_synthetic(p15card, 0); - if (err < 0) - goto error; - goto done; - } + if (err < 0) + goto end; if (p15card->file_odf == NULL) { tmppath = p15card->file_app->path; @@ -519,7 +515,7 @@ int sc_pkcs15_bind(struct sc_card *card, } err = sc_select_file(card, &tmppath, &p15card->file_odf); if (err) /* FIXME: finish writing error reporting stuff */ - goto error; + goto end; /* XXX: fix buffer overflow. Silently truncate ODF if it * is too large. --okir */ @@ -527,16 +523,16 @@ int sc_pkcs15_bind(struct sc_card *card, len = sizeof(buf); err = sc_read_binary(card, 0, buf, len, 0); if (err < 0) - goto error; + goto end; if (err < 2) { err = SC_ERROR_PKCS15_APP_NOT_FOUND; - goto error; + goto end; } len = err; if (parse_odf(buf, len, p15card)) { err = SC_ERROR_PKCS15_APP_NOT_FOUND; sc_error(card->ctx, "Unable to parse ODF\n"); - goto error; + goto end; } if (card->ctx->debug) { @@ -561,19 +557,85 @@ int sc_pkcs15_bind(struct sc_card *card, } err = sc_select_file(card, &tmppath, &p15card->file_tokeninfo); if (err) - goto error; + goto end; if ((len = p15card->file_tokeninfo->size) > sizeof(buf)) len = sizeof(buf); err = sc_read_binary(card, 0, buf, len, 0); if (err < 0) - goto error; + goto end; if (err <= 2) { err = SC_ERROR_PKCS15_APP_NOT_FOUND; - goto error; + goto end; } parse_tokeninfo(p15card, buf, err); + ok = 1; +end: + if (!ok) { + sc_pkcs15_card_clear(p15card); + return err; + } + + return SC_SUCCESS; +} + +int sc_pkcs15_bind(struct sc_card *card, + struct sc_pkcs15_card **p15card_out) +{ + struct sc_pkcs15_card *p15card = NULL; + struct sc_context *ctx; + scconf_block *conf_block = NULL, **blocks; + int i, r, emu_first, enable_emu; + + assert(sc_card_valid(card) && p15card_out != NULL); + ctx = card->ctx; + SC_FUNC_CALLED(ctx, 1); + p15card = sc_pkcs15_card_new(); + if (p15card == NULL) + return SC_ERROR_OUT_OF_MEMORY; + p15card->card = card; + + for (i = 0; ctx->conf_blocks[i] != NULL; i++) { + blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], + "framework", "pkcs15"); + if (blocks[0] != NULL) + conf_block = blocks[0]; + free(blocks); + } + if (conf_block) + p15card->opts.use_cache = scconf_get_bool(conf_block, "use_caching", 0); + + r = sc_lock(card); + if (r) { + sc_error(ctx, "sc_lock() failed: %s\n", sc_strerror(r)); + sc_pkcs15_card_free(p15card); + SC_FUNC_RETURN(ctx, 1, r); + } + + enable_emu = scconf_get_bool(conf_block, "enable_pkcs15_emulation", 1); + if (enable_emu) { + emu_first = scconf_get_bool(conf_block, "try_emulation_first", 0); + if (emu_first) { + r = sc_pkcs15_bind_synthetic(p15card); + if (r == SC_SUCCESS) + goto done; + r = sc_pkcs15_bind_internal(p15card); + if (r < 0) + goto error; + } else { + r = sc_pkcs15_bind_internal(p15card); + if (r == SC_SUCCESS) + goto done; + r = sc_pkcs15_bind_synthetic(p15card); + if (r < 0) + goto error; + } + } else { + r = sc_pkcs15_bind_internal(p15card); + if (r < 0) + goto error; + } done: *p15card_out = p15card; sc_unlock(card); @@ -581,7 +643,7 @@ done: error: sc_unlock(card); sc_pkcs15_card_free(p15card); - SC_FUNC_RETURN(ctx, 1, err); + SC_FUNC_RETURN(ctx, 1, r); } int sc_pkcs15_detect(struct sc_card *card) diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index 0393ff94..7e70dea3 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -383,6 +383,7 @@ int sc_pkcs15_find_object_by_id(sc_pkcs15_card_t *, int, struct sc_pkcs15_card * sc_pkcs15_card_new(void); void sc_pkcs15_card_free(struct sc_pkcs15_card *p15card); +void sc_pkcs15_card_clear(sc_pkcs15_card_t *p15card); int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *prkey_obj, @@ -601,7 +602,15 @@ typedef struct sc_pkcs15_search_key { int sc_pkcs15_search_objects(sc_pkcs15_card_t *, sc_pkcs15_search_key_t *, sc_pkcs15_object_t **, size_t); -extern int sc_pkcs15_bind_synthetic(sc_pkcs15_card_t *, int); +/* This structure is passed to the new sc_pkcs15emu_*_init functions */ +typedef struct sc_pkcs15emu_opt { + scconf_block *blk; + unsigned int flags; +} sc_pkcs15emu_opt_t; + +#define SC_PKCS15EMU_FLAGS_NO_CHECK 0x00000001 + +extern int sc_pkcs15_bind_synthetic(sc_pkcs15_card_t *); sc_pkcs15_df_t *sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card, int type);