/* create slots associated with a reader, called whenever a reader is seen. */ CK_RV initialize_reader(sc_reader_t *reader) { unsigned int i; CK_RV rv; scconf_block *conf_block = NULL; const scconf_list *list = NULL; conf_block = sc_get_conf_block(context, "pkcs11", NULL, 1); if (conf_block != NULL) { list = scconf_find_list(conf_block, "ignored_readers"); while (list != NULL) { if (strstr(reader->name, list->data) != NULL) { sc_debug(context, SC_LOG_DEBUG_NORMAL, "Ignoring reader \'%s\' because of \'%s\'\n", reader->name, list->data); return CKR_OK; } list = list->next; } } for (i = 0; i < sc_pkcs11_conf.slots_per_card; i++) { rv = create_slot(reader); if (rv != CKR_OK) return rv; } if (sc_detect_card_presence(reader)) { card_detect(reader); } return CKR_OK; }
static int list_readers(sc_context_t *ctx) { char card_atr[0x3e]; sc_card_t *card; sc_reader_t *reader; size_t i, rcount = sc_ctx_get_reader_count(ctx); if (rcount == 0) { printf("No smart card readers found.\n"); return 0; } printf("%-4s %-7s %s\n", "Nr.", "Driver", "Smart Card Reader"); for (i = 0; i < rcount; i++) { reader = sc_ctx_get_reader(ctx, i); memset(card_atr, '\0', sizeof card_atr); if (sc_detect_card_presence(reader) & SC_READER_CARD_PRESENT) { if (sc_connect_card(reader, &card) == SC_SUCCESS) { sc_bin_to_hex(card->atr.value, card->atr.len, card_atr, sizeof card_atr, ':'); } sc_disconnect_card(card); } else { strncpy(card_atr, "[no card present]", sizeof card_atr); } printf("%-4d %-7s %s\n", i, reader->driver->short_name, reader->name); printf(" ATR: %s\n", card_atr); } return 0; }
int initialize(int reader_id, int verbose, sc_context_t **ctx, sc_reader_t **reader) { unsigned int i, reader_count; if (!ctx || !reader) return SC_ERROR_INVALID_ARGUMENTS; int r = sc_establish_context(ctx, ""); if (r < 0 || !*ctx) { fprintf(stderr, "Failed to create initial context: %s", sc_strerror(r)); return r; } (*ctx)->debug = verbose; (*ctx)->enable_default_driver = 1; reader_count = sc_ctx_get_reader_count(*ctx); if (reader_count == 0) { sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "No reader not found.\n"); return SC_ERROR_NO_READERS_FOUND; } if (reader_id < 0) { /* Automatically try to skip to a reader with a card if reader not specified */ for (i = 0; i < reader_count; i++) { *reader = sc_ctx_get_reader(*ctx, i); if (sc_detect_card_presence(*reader) & SC_READER_CARD_PRESENT) { reader_id = i; sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "Using the first reader" " with a card: %s", (*reader)->name); break; } } if (reader_id >= reader_count) { sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "No card found, using the first reader."); reader_id = 0; } } if (reader_id >= reader_count) { sc_debug(*ctx, SC_LOG_DEBUG_NORMAL, "Invalid reader number " "(%d), only %d available.\n", reader_id, reader_count); return SC_ERROR_NO_READERS_FOUND; } *reader = sc_ctx_get_reader(*ctx, reader_id); return SC_SUCCESS; }
/* create slots associated with a reader, called whenever a reader is seen. */ CK_RV initialize_reader(sc_reader_t *reader) { unsigned int i; CK_RV rv; for (i = 0; i < sc_pkcs11_conf.slots_per_card; i++) { rv = create_slot(reader); if (rv != CKR_OK) return rv; } sc_log(context, "Initialize reader '%s': detect SC card presence", reader->name); if (sc_detect_card_presence(reader)) { sc_log(context, "Initialize reader '%s': detect PKCS11 card presence", reader->name); card_detect(reader); } sc_log(context, "Reader '%s' initialized", reader->name); return CKR_OK; }
int sc_test_init(int *argc, char *argv[]) { char *opt_driver = NULL, *app_name; int opt_debug = 0, opt_reader = -1; int i, c, rc; sc_context_param_t ctx_param; if ((app_name = strrchr(argv[0], '/')) != NULL) app_name++; else app_name = argv[0]; while ((c = getopt_long(*argc, argv, "r:c:d", options, NULL)) != -1) { switch (c) { case 'r': opt_reader = atoi(optarg); break; case 'c': opt_driver = optarg; break; case 'd': opt_debug++; break; default: fprintf(stderr, "usage: %s [-r reader] [-c driver] [-d]\n", app_name); exit(1); } } *argc = optind; printf("Using libopensc version %s.\n", sc_get_version()); memset(&ctx_param, 0, sizeof(ctx_param)); ctx_param.ver = 0; ctx_param.app_name = app_name; i = sc_context_create(&ctx, &ctx_param); if (i != SC_SUCCESS) { printf("Failed to establish context: %s\n", sc_strerror(i)); return i; } ctx->debug = opt_debug; if (opt_reader >= sc_ctx_get_reader_count(ctx)) { fprintf(stderr, "Illegal reader number.\n" "Only %d reader(s) configured.\n", sc_ctx_get_reader_count(ctx)); exit(1); } while (1) { if (opt_reader >= 0) { rc = sc_detect_card_presence(sc_ctx_get_reader(ctx, opt_reader)); printf("Card %s.\n", rc == 1 ? "present" : "absent"); if (rc < 0) return rc; } else { for (i = rc = 0; rc != 1 && i < sc_ctx_get_reader_count(ctx); i++) rc = sc_detect_card_presence(sc_ctx_get_reader(ctx, opt_reader)); if (rc == 1) opt_reader = i - 1; } if (rc > 0) { printf("Card detected in reader '%s'\n",sc_ctx_get_reader(ctx, opt_reader)->name); break; } if (rc < 0) return rc; printf("Please insert a smart card. Press return to continue"); fflush(stdout); while (getc(stdin) != '\n') ; } printf("Connecting... "); fflush(stdout); i = sc_connect_card(sc_ctx_get_reader(ctx, opt_reader), &card); if (i != SC_SUCCESS) { printf("Connecting to card failed: %s\n", sc_strerror(i)); return i; } printf("connected.\n"); { char tmp[SC_MAX_ATR_SIZE*3]; sc_bin_to_hex(card->atr, card->atr_len, tmp, sizeof(tmp) - 1, ':'); printf("ATR = %s\n",tmp); } if (opt_driver != NULL) { rc = sc_set_card_driver(ctx, opt_driver); if (rc != 0) { fprintf(stderr, "Driver '%s' not found!\n", opt_driver); return rc; } } return 0; }
int util_connect_card(sc_context_t *ctx, sc_card_t **cardp, int reader_id, int slot_id, int wait, int verbose) { sc_reader_t *reader; sc_card_t *card; int r; if (wait) { sc_reader_t *readers[16]; int slots[16]; unsigned int i; int j, k, found; unsigned int event; for (i = k = 0; i < sc_ctx_get_reader_count(ctx); i++) { if (reader_id >= 0 && (unsigned int)reader_id != i) continue; reader = sc_ctx_get_reader(ctx, i); for (j = 0; j < reader->slot_count; j++, k++) { readers[k] = reader; slots[k] = j; } } //printf("Waiting for card to be inserted...\n"); r = sc_wait_for_event(readers, slots, k, SC_EVENT_CARD_INSERTED, &found, &event, -1); if (r < 0) { syslog(LOG_ERR, "Error while waiting for card: %s\n", sc_strerror(r)); return 3; } reader = readers[found]; slot_id = slots[found]; } else { if (sc_ctx_get_reader_count(ctx) == 0) { syslog(LOG_ERR, "No smart card readers found.\n"); return 1; } if (reader_id < 0) { unsigned int i; /* Automatically try to skip to a reader with a card if reader not specified */ for (i = 0; i < sc_ctx_get_reader_count(ctx); i++) { reader = sc_ctx_get_reader(ctx, i); if (sc_detect_card_presence(reader, 0) & SC_SLOT_CARD_PRESENT) { reader_id = i; syslog(LOG_NOTICE, "Using reader with a card: %s\n", reader->name); goto autofound; } } reader_id = 0; } autofound: if ((unsigned int)reader_id >= sc_ctx_get_reader_count(ctx)) { syslog(LOG_ERR, "Illegal reader number. " "Only %d reader(s) configured.\n", sc_ctx_get_reader_count(ctx)); return 1; } reader = sc_ctx_get_reader(ctx, reader_id); slot_id = 0; if (sc_detect_card_presence(reader, 0) <= 0) { syslog(LOG_ERR, "Card not present.\n"); return 3; } } if (verbose) printf("Connecting to card in reader %s...\n", reader->name); if ((r = sc_connect_card(reader, slot_id, &card)) < 0) { syslog(LOG_ERR, "Failed to connect to card: %s\n", sc_strerror(r)); return 1; } if (verbose) printf("Using card driver %s.\n", card->driver->name); if ((r = sc_lock(card)) < 0) { syslog(LOG_ERR, "Failed to lock card: %s\n", sc_strerror(r)); sc_disconnect_card(card, 0); return 1; } *cardp = card; return 0; }
CK_RV card_detect(sc_reader_t *reader) { struct sc_pkcs11_card *p11card = NULL; int free_p11card = 0; int rc; CK_RV rv; unsigned int i; int j; sc_log(context, "%s: Detecting smart card", reader->name); /* Check if someone inserted a card */ again: rc = sc_detect_card_presence(reader); if (rc < 0) { sc_log(context, "%s: failed, %s", reader->name, sc_strerror(rc)); return sc_to_cryptoki_error(rc, NULL); } if (rc == 0) { sc_log(context, "%s: card absent", reader->name); card_removed(reader); /* Release all resources */ return CKR_TOKEN_NOT_PRESENT; } /* If the card was changed, disconnect the current one */ if (rc & SC_READER_CARD_CHANGED) { sc_log(context, "%s: Card changed", reader->name); /* The following should never happen - but if it * does we'll be stuck in an endless loop. * So better be fussy. if (!retry--) return CKR_TOKEN_NOT_PRESENT; */ card_removed(reader); goto again; } /* Locate a slot related to the reader */ for (i=0; i<list_size(&virtual_slots); i++) { sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); if (slot->reader == reader) { p11card = slot->p11card; break; } } /* Detect the card if it's not known already */ if (p11card == NULL) { sc_log(context, "%s: First seen the card ", reader->name); p11card = (struct sc_pkcs11_card *)calloc(1, sizeof(struct sc_pkcs11_card)); if (!p11card) return CKR_HOST_MEMORY; free_p11card = 1; p11card->reader = reader; } if (p11card->card == NULL) { sc_log(context, "%s: Connecting ... ", reader->name); rc = sc_connect_card(reader, &p11card->card); if (rc != SC_SUCCESS) { sc_log(context, "%s: SC connect card error %i", reader->name, rc); rv = sc_to_cryptoki_error(rc, NULL); goto fail; } /* escape commands are only guaranteed to be working with a card * inserted. That's why by now, after sc_connect_card() the reader's * metadata may have changed. We re-initialize the metadata for every * slot of this reader here. */ if (reader->flags & SC_READER_ENABLE_ESCAPE) { for (i = 0; i<list_size(&virtual_slots); i++) { sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); if (slot->reader == reader) init_slot_info(&slot->slot_info, reader); } } sc_log(context, "%s: Connected SC card %p", reader->name, p11card->card); } /* Detect the framework */ if (p11card->framework == NULL) { struct sc_app_info *app_generic = sc_pkcs15_get_application_by_type(p11card->card, "generic"); sc_log(context, "%s: Detecting Framework. %i on-card applications", reader->name, p11card->card->app_count); sc_log(context, "%s: generic application %s", reader->name, app_generic ? app_generic->label : "<none>"); for (i = 0; frameworks[i]; i++) if (frameworks[i]->bind != NULL) break; /*TODO: only first framework is used: pkcs15init framework is not reachable here */ if (frameworks[i] == NULL) { rv = CKR_GENERAL_ERROR; goto fail; } p11card->framework = frameworks[i]; /* Initialize framework */ sc_log(context, "%s: Detected framework %d. Creating tokens.", reader->name, i); /* Bind 'generic' application or (emulated?) card without applications */ if (app_generic || !p11card->card->app_count) { scconf_block *conf_block = NULL; int enable_InitToken = 0; conf_block = sc_match_atr_block(p11card->card->ctx, NULL, &p11card->reader->atr); if (!conf_block) /* check default block */ conf_block = sc_get_conf_block(context, "framework", "pkcs15", 1); enable_InitToken = scconf_get_bool(conf_block, "pkcs11_enable_InitToken", 0); sc_log(context, "%s: Try to bind 'generic' token.", reader->name); rv = frameworks[i]->bind(p11card, app_generic); if (rv == CKR_TOKEN_NOT_RECOGNIZED && enable_InitToken) { sc_log(context, "%s: 'InitToken' enabled -- accept non-binded card", reader->name); rv = CKR_OK; } if (rv != CKR_OK) { sc_log(context, "%s: cannot bind 'generic' token: rv 0x%lX", reader->name, rv); goto fail; } sc_log(context, "%s: Creating 'generic' token.", reader->name); rv = frameworks[i]->create_tokens(p11card, app_generic); if (rv != CKR_OK) { sc_log(context, "%s: create 'generic' token error 0x%lX", reader->name, rv); goto fail; } } /* Now bind the rest of applications that are not 'generic' */ for (j = 0; j < p11card->card->app_count; j++) { struct sc_app_info *app_info = p11card->card->app[j]; char *app_name = app_info ? app_info->label : "<anonymous>"; if (app_generic && app_generic == p11card->card->app[j]) continue; sc_log(context, "%s: Binding %s token.", reader->name, app_name); rv = frameworks[i]->bind(p11card, app_info); if (rv != CKR_OK) { sc_log(context, "%s: bind %s token error Ox%lX", reader->name, app_name, rv); continue; } sc_log(context, "%s: Creating %s token.", reader->name, app_name); rv = frameworks[i]->create_tokens(p11card, app_info); if (rv != CKR_OK) { sc_log(context, "%s: create %s token error 0x%lX", reader->name, app_name, rv); goto fail; } } } sc_log(context, "%s: Detection ended", reader->name); return CKR_OK; fail: if (free_p11card) { if (p11card->framework) p11card->framework->unbind(p11card); if (p11card->card != NULL) sc_disconnect_card(p11card->card); free(p11card); } return rv; }
CK_RV card_detect(sc_reader_t *reader) { struct sc_pkcs11_card *p11card = NULL; int rc, rv; unsigned int i; rv = CKR_OK; sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: Detecting smart card\n", reader->name); /* Check if someone inserted a card */ again:rc = sc_detect_card_presence(reader); if (rc < 0) { sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: failed, %s\n", reader->name, sc_strerror(rc)); return sc_to_cryptoki_error(rc, NULL); } if (rc == 0) { sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: card absent\n", reader->name); card_removed(reader); /* Release all resources */ return CKR_TOKEN_NOT_PRESENT; } /* If the card was changed, disconnect the current one */ if (rc & SC_READER_CARD_CHANGED) { sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: Card changed\n", reader->name); /* The following should never happen - but if it * does we'll be stuck in an endless loop. * So better be fussy. if (!retry--) return CKR_TOKEN_NOT_PRESENT; */ card_removed(reader); goto again; } /* Locate a slot related to the reader */ for (i=0; i<list_size(&virtual_slots); i++) { sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); if (slot->reader == reader) { p11card = slot->card; break; } } /* Detect the card if it's not known already */ if (p11card == NULL) { sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: First seen the card ", reader->name); p11card = (struct sc_pkcs11_card *)calloc(1, sizeof(struct sc_pkcs11_card)); if (!p11card) return CKR_HOST_MEMORY; p11card->reader = reader; } if (p11card->card == NULL) { sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: Connecting ... ", reader->name); rc = sc_connect_card(reader, &p11card->card); if (rc != SC_SUCCESS) return sc_to_cryptoki_error(rc, NULL); } /* Detect the framework */ if (p11card->framework == NULL) { sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: Detecting Framework\n", reader->name); for (i = 0; frameworks[i]; i++) { if (frameworks[i]->bind == NULL) continue; rv = frameworks[i]->bind(p11card); if (rv == CKR_OK) break; } if (frameworks[i] == NULL) return CKR_TOKEN_NOT_RECOGNIZED; /* Initialize framework */ sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: Detected framework %d. Creating tokens.\n", reader->name, i); rv = frameworks[i]->create_tokens(p11card); if (rv != CKR_OK) return rv; p11card->framework = frameworks[i]; } sc_debug(context, SC_LOG_DEBUG_NORMAL, "%s: Detection ended\n", reader->name); return CKR_OK; }
/* Create a new context for the card and figures out some basic information of the card. Detects whether a PKCS_15 application is stored. Common errors: GPG_ERR_CARD_NOT_PRESENT */ int card_open (CARD *rcard) { #ifdef HAVE_OPENSC CARD card; int rc; if (opt.disable_opensc) return gpg_error (GPG_ERR_NOT_SUPPORTED); card = xtrycalloc (1, sizeof *card); if (!card) return gpg_error (gpg_err_code_from_errno (errno)); card->reader = 0; rc = sc_establish_context (&card->ctx, "scdaemon"); if (rc) { log_error ("failed to establish SC context: %s\n", sc_strerror (rc)); rc = map_sc_err (rc); goto leave; } if (card->reader >= card->ctx->reader_count) { log_error ("no card reader available\n"); rc = gpg_error (GPG_ERR_CARD); goto leave; } card->ctx->error_file = log_get_stream (); card->ctx->debug = opt.debug_sc; card->ctx->debug_file = log_get_stream (); if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1) { rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT); goto leave; } rc = sc_connect_card (card->ctx->reader[card->reader], 0, &card->scard); if (rc) { log_error ("failed to connect card in reader %d: %s\n", card->reader, sc_strerror (rc)); rc = map_sc_err (rc); goto leave; } if (opt.verbose) log_info ("connected to card in reader %d using driver '%s'\n", card->reader, card->scard->driver->name); rc = sc_lock (card->scard); if (rc) { log_error ("can't lock card in reader %d: %s\n", card->reader, sc_strerror (rc)); rc = map_sc_err (rc); goto leave; } leave: if (rc) card_close (card); else *rcard = card; return rc; #else return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif }