/* * Deal with uninitialized cards */ static CK_RV pkcs15init_bind(struct sc_pkcs11_card *p11card, struct sc_app_info *app_info) { struct sc_card *card = p11card->card; struct sc_profile *profile; int rc; rc = sc_pkcs15init_bind(card, "pkcs15", NULL, NULL, &profile); if (rc == 0) p11card->fws_data[0] = profile; return sc_to_cryptoki_error(rc, NULL); }
static CK_RV pkcs15init_initialize(struct sc_pkcs11_card *p11card, void *ptr, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) { struct sc_profile *profile = (struct sc_profile *) p11card->fws_data[0]; struct sc_pkcs15init_initargs args; struct sc_pkcs11_slot *slot; int rc, rv, id; memset(&args, 0, sizeof(args)); args.so_pin = pPin; args.so_pin_len = ulPinLen; args.so_puk = pPin; args.so_puk_len = ulPinLen; args.label = (const char *) pLabel; rc = sc_pkcs15init_add_app(p11card->card, profile, &args); if (rc < 0) return sc_to_cryptoki_error(rc, NULL); /* Change the binding from the pkcs15init framework * to the pkcs15 framework on the fly. * First, try to bind pkcs15 framework */ if ((rv = framework_pkcs15.bind(p11card, NULL)) != CKR_OK) { /* whoops, bad */ p11card->fws_data[0] = profile; return rv; } /* Change the function vector to the standard pkcs15 ops */ p11card->framework = &framework_pkcs15; /* Loop over all slots belonging to this card, and fix up * the flags. */ for (id = 0; slot_get_slot(id, &slot) == CKR_OK; id++) { if (slot->card == p11card) slot->token_info.flags |= CKF_TOKEN_INITIALIZED; if (slot->card->card->caps & SC_CARD_CAP_RNG) slot->token_info.flags |= CKF_RNG; } sc_pkcs15init_unbind(profile); return CKR_OK; }
CK_RV C_WaitForSlotEvent(CK_FLAGS flags, /* blocking/nonblocking flag */ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */ CK_VOID_PTR pReserved) /* reserved. Should be NULL_PTR */ { sc_reader_t *found; unsigned int mask, events; void *reader_states = NULL; CK_SLOT_ID slot_id; CK_RV rv; int r; if (pReserved != NULL_PTR) return CKR_ARGUMENTS_BAD; sc_log(context, "C_WaitForSlotEvent(block=%d)", !(flags & CKF_DONT_BLOCK)); /* Not all pcsc-lite versions implement consistently used functions as they are */ /* FIXME: add proper checking into build to check correct pcsc-lite version for SCardStatusChange/SCardCancel */ if (!(flags & CKF_DONT_BLOCK)) return CKR_FUNCTION_NOT_SUPPORTED; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; mask = SC_EVENT_CARD_EVENTS; /* Detect and add new slots for added readers v2.20 */ if (sc_pkcs11_conf.plug_and_play) { mask |= SC_EVENT_READER_EVENTS; } rv = slot_find_changed(&slot_id, mask); if ((rv == CKR_OK) || (flags & CKF_DONT_BLOCK)) goto out; again: sc_log(context, "C_WaitForSlotEvent() reader_states:%p", reader_states); sc_pkcs11_unlock(); r = sc_wait_for_event(context, mask, &found, &events, -1, &reader_states); if (sc_pkcs11_conf.plug_and_play && events & SC_EVENT_READER_ATTACHED) { /* NSS/Firefox Triggers a C_GetSlotList(NULL) only if a slot ID is returned that it does not know yet Change the first hotplug slot id on every call to make this happen. */ sc_pkcs11_slot_t *hotplug_slot = list_get_at(&virtual_slots, 0); *pSlot= hotplug_slot->id -1; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; goto out; } /* Was C_Finalize called ? */ if (in_finalize == 1) return CKR_CRYPTOKI_NOT_INITIALIZED; if ((rv = sc_pkcs11_lock()) != CKR_OK) return rv; if (r != SC_SUCCESS) { sc_log(context, "sc_wait_for_event() returned %d\n", r); rv = sc_to_cryptoki_error(r, "C_WaitForSlotEvent"); goto out; } /* If no changed slot was found (maybe an unsupported card * was inserted/removed) then go waiting again */ rv = slot_find_changed(&slot_id, mask); if (rv != CKR_OK) goto again; out: if (pSlot) *pSlot = slot_id; /* Free allocated readers states holder */ if (reader_states) { sc_log(context, "free reader states"); sc_wait_for_event(context, 0, NULL, NULL, -1, &reader_states); } sc_log(context, "C_WaitForSlotEvent() = %s", lookup_enum (RV_T, rv)); sc_pkcs11_unlock(); return rv; }
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; }
CK_RV C_WaitForSlotEvent(CK_FLAGS flags, /* blocking/nonblocking flag */ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */ CK_VOID_PTR pReserved) /* reserved. Should be NULL_PTR */ { sc_reader_t *found; unsigned int mask, events; void *reader_states = NULL; CK_SLOT_ID slot_id; CK_RV rv; int r; if (pReserved != NULL_PTR) return CKR_ARGUMENTS_BAD; sc_log(context, "C_WaitForSlotEvent(block=%d)", !(flags & CKF_DONT_BLOCK)); #ifndef PCSCLITE_GOOD /* Not all pcsc-lite versions implement consistently used functions as they are */ if (!(flags & CKF_DONT_BLOCK)) return CKR_FUNCTION_NOT_SUPPORTED; #endif /* PCSCLITE_GOOD */ rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; mask = SC_EVENT_CARD_EVENTS | SC_EVENT_READER_EVENTS; /* Detect and add new slots for added readers v2.20 */ rv = slot_find_changed(&slot_id, mask); if ((rv == CKR_OK) || (flags & CKF_DONT_BLOCK)) goto out; again: sc_log(context, "C_WaitForSlotEvent() reader_states:%p", reader_states); sc_pkcs11_unlock(); r = sc_wait_for_event(context, mask, &found, &events, -1, &reader_states); if (events & SC_EVENT_READER_ATTACHED) { rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; goto out; } /* Was C_Finalize called ? */ if (in_finalize == 1) return CKR_CRYPTOKI_NOT_INITIALIZED; if ((rv = sc_pkcs11_lock()) != CKR_OK) return rv; if (r != SC_SUCCESS) { sc_log(context, "sc_wait_for_event() returned %d\n", r); rv = sc_to_cryptoki_error(r, "C_WaitForSlotEvent"); goto out; } /* If no changed slot was found (maybe an unsupported card * was inserted/removed) then go waiting again */ rv = slot_find_changed(&slot_id, mask); if (rv != CKR_OK) goto again; out: if (pSlot) *pSlot = slot_id; /* Free allocated readers states holder */ if (reader_states) { sc_log(context, "free reader states"); sc_wait_for_event(context, 0, NULL, NULL, -1, &reader_states); } sc_log(context, "C_WaitForSlotEvent() = %s", lookup_enum (RV_T, rv)); sc_pkcs11_unlock(); return rv; }