- slots, sessions and objects are kept as lists.
  - change the way slots, cards and readers are managed.
  - re-implement C_WaitForSlotEvent(/C_Finalize) as written in PCKS#11 v2.20, canceling pending blocking calls.
  - implement a "virtual hotplug slot" with a floating slot id to keep NSS working with C_WaitForSlotEvent with a new reader.
    NSS does not call C_GetSlotList(NULL) to re-fetch the list of available slots if C_WaitForSlotEvent returns an event in an already known slot ID.
    By changing the ID of a slot whenever a reader attached  NSS/Firefox can be tricked into recognizing new readers when waiting for events with C_WaitForSlotEvent.
  - change (possibly break something) sc_to_cryptoki_error() to not have side-effects
  - Implement CKU_CONTEXT_SPECIFIC in C_Login to implement CKA_ALWAYS_AUTHENTICATE (keys with user consent) 
 


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3935 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
martin 2010-01-24 20:45:02 +00:00
parent 0595eb7d1e
commit 0244baa494
10 changed files with 999 additions and 1046 deletions

View File

@ -11,16 +11,18 @@ lib_LTLIBRARIES = opensc-pkcs11.la pkcs11-spy.la onepin-opensc-pkcs11.la
noinst_LTLIBRARIES = libpkcs11.la
AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(LTLIB_CFLAGS) $(PTHREAD_CFLAGS)
INCLUDES = -I$(top_srcdir)/src/pkcs15init -I$(top_builddir)/src/include
INCLUDES = -I$(top_srcdir)/src/pkcs15init -I$(top_builddir)/src/include -I$(top_builddir)/src/common
OPENSC_PKCS11_INC = sc-pkcs11.h
OPENSC_PKCS11_SRC = pkcs11-global.c pkcs11-session.c pkcs11-object.c misc.c slot.c \
mechanism.c openssl.c secretkey.c framework-pkcs15.c \
framework-pkcs15init.c debug.c opensc-pkcs11.exports
framework-pkcs15init.c debug.c opensc-pkcs11.exports \
pkcs11-display.c pkcs11-display.h
OPENSC_PKCS11_LIBS = $(OPTIONAL_OPENSSL_LIBS) $(PTHREAD_LIBS) \
$(top_builddir)/src/pkcs15init/libpkcs15init.la \
$(top_builddir)/src/libopensc/libopensc.la \
$(top_builddir)/src/scconf/libscconf.la
$(top_builddir)/src/scconf/libscconf.la \
$(top_builddir)/src/common/libcompat.la
libpkcs11_la_SOURCES = libpkcs11.c

View File

@ -163,7 +163,7 @@ static CK_RV pkcs15_bind(struct sc_pkcs11_card *p11card)
rc = sc_pkcs15_bind(p11card->card, &fw_data->p15_card);
sc_debug(context, "Binding to PKCS#15, rc=%d\n", rc);
if (rc < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
return register_mechanisms(p11card);
}
@ -187,7 +187,7 @@ static CK_RV pkcs15_unbind(struct sc_pkcs11_card *p11card)
rc = sc_pkcs15_unbind(fw_data->p15_card);
free(fw_data);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
static void pkcs15_init_token_info(struct sc_pkcs15_card *card, CK_TOKEN_INFO_PTR pToken)
@ -634,19 +634,6 @@ check_cert_data_read(struct pkcs15_fw_data *fw_data,
return 0;
}
static int
pool_is_present(struct sc_pkcs11_pool *pool, struct pkcs15_any_object *obj)
{
struct sc_pkcs11_pool_item *item;
for (item = pool->head; item != NULL; item = item->next) {
if (obj == (struct pkcs15_any_object *) item->item)
return 1;
}
return 0;
}
static void
pkcs15_add_object(struct sc_pkcs11_slot *slot,
struct pkcs15_any_object *obj,
@ -659,10 +646,13 @@ pkcs15_add_object(struct sc_pkcs11_slot *slot,
|| (obj->base.flags & (SC_PKCS11_OBJECT_HIDDEN | SC_PKCS11_OBJECT_RECURS)))
return;
if (pool_is_present(&slot->object_pool, obj))
if (list_contains(&slot->objects, obj))
return;
pool_insert(&slot->object_pool, obj, pHandle);
list_append(&slot->objects, obj); // FIXME: pHandle too!
sc_debug(context, "Setting object handle of 0x%lx to 0x%lx", obj->base.handle, (CK_OBJECT_HANDLE)obj);
obj->base.handle = (CK_OBJECT_HANDLE)obj; // cast pointer to long
obj->base.flags |= SC_PKCS11_OBJECT_SEEN;
obj->refcount++;
@ -713,7 +703,7 @@ static void pkcs15_init_slot(struct sc_pkcs15_card *card,
slot->token_info.flags |= CKF_TOKEN_INITIALIZED;
if (auth != NULL)
slot->token_info.flags |= CKF_USER_PIN_INITIALIZED;
if (card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) {
if (card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
slot->token_info.flags |= CKF_PROTECTED_AUTHENTICATION_PATH;
}
if (card->card->caps & SC_CARD_CAP_RNG)
@ -731,6 +721,7 @@ static void pkcs15_init_slot(struct sc_pkcs15_card *card,
snprintf(tmp, sizeof(tmp), "%s", card->label);
}
slot->token_info.flags |= CKF_LOGIN_REQUIRED;
/* FIXME: update this information during runtime */
if (pin_info->tries_left >= 0) {
if (pin_info->tries_left == 1)
slot->token_info.flags |= CKF_USER_PIN_FINAL_TRY;
@ -754,7 +745,7 @@ static void pkcs15_init_slot(struct sc_pkcs15_card *card,
if (card->flags & SC_PKCS15_CARD_FLAG_EMULATED)
slot->token_info.flags |= CKF_WRITE_PROTECTED;
sc_debug(context, "Initialized token '%s'\n", tmp);
sc_debug(context, "Initialized token '%s' in slot 0x%lx", tmp, slot->id);
}
static CK_RV pkcs15_create_slot(struct sc_pkcs11_card *p11card,
@ -784,7 +775,7 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card)
struct pkcs15_fw_data *fw_data = (struct pkcs15_fw_data *) p11card->fw_data;
struct sc_pkcs15_object *auths[MAX_OBJECTS];
struct sc_pkcs11_slot *slot = NULL;
int i, rv, reader = p11card->reader;
int i, rv;
int auth_count;
int found_auth_count = 0;
unsigned int j;
@ -794,7 +785,7 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card)
auths,
SC_PKCS15_MAX_PINS);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
sc_debug(context, "Found %d authentication objects\n", rv);
auth_count = rv;
@ -803,42 +794,42 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card)
"private key",
__pkcs15_create_prkey_object);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PUBKEY_RSA,
"public key",
__pkcs15_create_pubkey_object);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PRKEY_GOSTR3410,
"private key",
__pkcs15_create_prkey_object);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PUBKEY_GOSTR3410,
"public key",
__pkcs15_create_pubkey_object);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_CERT_X509,
"certificate",
__pkcs15_create_cert_object);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_DATA_OBJECT,
"data object",
__pkcs15_create_data_object);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
/* Match up related keys and certificates */
pkcs15_bind_related_objects(fw_data);
@ -921,7 +912,7 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card)
}
}
/* Create read/write slots */
/* FIXME Create read/write slots
while (slot_allocate(&slot, p11card) == CKR_OK) {
if (!sc_pkcs11_conf.hide_empty_tokens && !(fw_data->p15_card->flags & SC_PKCS15_CARD_FLAG_EMULATED)) {
slot->slot_info.flags |= CKF_TOKEN_PRESENT;
@ -930,7 +921,7 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card)
slot->token_info.flags |= CKF_TOKEN_INITIALIZED;
}
}
*/
sc_debug(context, "All tokens created\n");
return CKR_OK;
}
@ -980,10 +971,10 @@ static CK_RV pkcs15_login(struct sc_pkcs11_card *p11card,
}
sc_debug(context, "No SOPIN found; returns %d\n", rc);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
else if (rc < 0) {
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
break;
@ -1003,13 +994,13 @@ static CK_RV pkcs15_login(struct sc_pkcs11_card *p11card,
}
#endif
sc_debug(context, "context specific login returns %d\n", rc);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
default:
return CKR_USER_TYPE_INVALID;
}
pin = (struct sc_pkcs15_pin_info *) auth_object->data;
if (p11card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) {
if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
/* pPin should be NULL in case of a pin pad reader, but
* some apps (e.g. older Netscapes) don't know about it.
* So we don't require that pPin == NULL, but set it to
@ -1038,11 +1029,11 @@ static CK_RV pkcs15_login(struct sc_pkcs11_card *p11card,
* Otherwise an attacker could perform some crypto operation
* after we've authenticated with the card */
if (sc_pkcs11_conf.lock_login && (rc = lock_card(fw_data)) < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
rc = sc_pkcs15_verify_pin(card, pin, pPin, ulPinLen);
sc_debug(context, "PKCS15 verify PIN returned %d\n", rc);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
static CK_RV pkcs15_logout(struct sc_pkcs11_card *p11card, void *fw_token)
@ -1058,7 +1049,7 @@ static CK_RV pkcs15_logout(struct sc_pkcs11_card *p11card, void *fw_token)
if (sc_pkcs11_conf.lock_login)
rc = unlock_card(fw_data);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
static CK_RV pkcs15_change_pin(struct sc_pkcs11_card *p11card,
@ -1073,7 +1064,7 @@ static CK_RV pkcs15_change_pin(struct sc_pkcs11_card *p11card,
if (!(pin = slot_data_pin_info(fw_token)))
return CKR_USER_PIN_NOT_INITIALIZED;
if (p11card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) {
if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
/* pPin should be NULL in case of a pin pad reader, but
* some apps (e.g. older Netscapes) don't know about it.
* So we don't require that pPin == NULL, but set it to
@ -1110,7 +1101,7 @@ static CK_RV pkcs15_change_pin(struct sc_pkcs11_card *p11card,
}
sc_debug(context, "PIN change returns %d\n", rc);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
#ifdef USE_PKCS15_INIT
@ -1139,21 +1130,21 @@ static CK_RV pkcs15_init_pin(struct sc_pkcs11_card *p11card,
* of ISO 'RESET RETRY COUNTER' command. */
rc = sc_pkcs15_unblock_pin(fw_data->p15_card, pin_info, NULL, 0, pPin, ulPinLen);
#else
return sc_to_cryptoki_error(SC_ERROR_NOT_SUPPORTED, p11card->reader);
return sc_to_cryptoki_error(SC_ERROR_NOT_SUPPORTED);
#endif
}
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
rc = sc_lock(p11card->card);
if (rc < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
rc = sc_pkcs15init_bind(p11card->card, "pkcs15", NULL, &profile);
if (rc < 0) {
sc_unlock(p11card->card);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
memset(&args, 0, sizeof(args));
@ -1165,11 +1156,11 @@ static CK_RV pkcs15_init_pin(struct sc_pkcs11_card *p11card,
sc_pkcs15init_unbind(profile);
sc_unlock(p11card->card);
if (rc < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
rc = sc_pkcs15_find_pin_by_auth_id(fw_data->p15_card, &args.auth_id, &auth_obj);
if (rc < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
/* Re-initialize the slot */
free(slot->fw_data);
@ -1262,7 +1253,7 @@ static CK_RV pkcs15_create_private_key(struct sc_pkcs11_card *p11card,
rc = sc_pkcs15init_store_private_key(fw_data->p15_card, profile, &args, &key_obj);
if (rc < 0) {
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
goto out;
}
@ -1351,7 +1342,7 @@ static CK_RV pkcs15_create_public_key(struct sc_pkcs11_card *p11card,
rc = sc_pkcs15init_store_public_key(fw_data->p15_card, profile, &args, &key_obj);
if (rc < 0) {
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
goto out;
}
@ -1429,7 +1420,7 @@ static CK_RV pkcs15_create_certificate(struct sc_pkcs11_card *p11card,
rc = sc_pkcs15init_store_certificate(fw_data->p15_card, profile, &args, &cert_obj);
if (rc < 0) {
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
goto out;
}
/* Create a new pkcs11 object for it */
@ -1511,7 +1502,7 @@ static CK_RV pkcs15_create_data(struct sc_pkcs11_card *p11card,
rc = sc_pkcs15init_store_data_object(fw_data->p15_card, profile, &args, &data_obj);
if (rc < 0) {
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
goto out;
}
/* Create a new pkcs11 object for it */
@ -1538,13 +1529,13 @@ static CK_RV pkcs15_create_object(struct sc_pkcs11_card *p11card,
rc = sc_lock(p11card->card);
if (rc < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
/* Bind the profile */
rc = sc_pkcs15init_bind(p11card->card, "pkcs15", NULL, &profile);
if (rc < 0) {
sc_unlock(p11card->card);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
/* Add the PINs the user presented so far to the keycache. */
@ -1694,12 +1685,12 @@ static CK_RV pkcs15_gen_keypair(struct sc_pkcs11_card *p11card,
rc = sc_lock(p11card->card);
if (rc < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
rc = sc_pkcs15init_bind(p11card->card, "pkcs15", NULL, &profile);
if (rc < 0) {
sc_unlock(p11card->card);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
memset(&keygen_args, 0, sizeof(keygen_args));
@ -1791,13 +1782,13 @@ static CK_RV pkcs15_gen_keypair(struct sc_pkcs11_card *p11card,
rc = sc_pkcs15_find_pubkey_by_id(fw_data->p15_card, &id, &pub_key_obj);
if (rc != 0) {
sc_debug(context, "sc_pkcs15_find_pubkey_by_id returned %d\n", rc);
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
goto kpgen_done;
}
}
else if (rc != SC_ERROR_NOT_SUPPORTED) {
sc_debug(context, "sc_pkcs15init_generate_key returned %d\n", rc);
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
goto kpgen_done;
}
else {
@ -1836,7 +1827,7 @@ static CK_RV pkcs15_gen_keypair(struct sc_pkcs11_card *p11card,
}
if (rc < 0) {
sc_debug(context, "private/public keys not stored: %d\n", rc);
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
goto kpgen_done;
}
}
@ -1848,7 +1839,7 @@ static CK_RV pkcs15_gen_keypair(struct sc_pkcs11_card *p11card,
rc = __pkcs15_create_pubkey_object(fw_data, pub_key_obj, &pub_any_obj);
if (rc != 0) {
sc_debug(context, "__pkcs15_create_pr/pubkey_object returned %d\n", rc);
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
goto kpgen_done;
}
pkcs15_add_object(slot, priv_any_obj, phPrivKey);
@ -1872,7 +1863,7 @@ static CK_RV pkcs15_get_random(struct sc_pkcs11_card *p11card,
struct sc_card *card = fw_data->p15_card->card;
rc = sc_get_challenge(card, p, (size_t)len);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
struct sc_pkcs11_framework_ops framework_pkcs15 = {
@ -1913,12 +1904,12 @@ static CK_RV pkcs15_set_attrib(struct sc_pkcs11_session *session,
rc = sc_lock(p11card->card);
if (rc < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
rc = sc_pkcs15init_bind(p11card->card, "pkcs15", NULL, &profile);
if (rc < 0) {
sc_unlock(p11card->card);
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
/* Add the PINs the user presented so far to the keycache. */
@ -1947,7 +1938,7 @@ static CK_RV pkcs15_set_attrib(struct sc_pkcs11_session *session,
goto set_attr_done;
}
rv = sc_to_cryptoki_error(rc, p11card->reader);
rv = sc_to_cryptoki_error(rc);
set_attr_done:
sc_pkcs15init_unbind(profile);
@ -2340,13 +2331,13 @@ static CK_RV pkcs15_prkey_sign(struct sc_pkcs11_session *ses, void *obj,
rv = sc_lock(ses->slot->card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, ses->slot->card->reader);
return sc_to_cryptoki_error(rv);
if (!sc_pkcs11_conf.lock_login) {
rv = reselect_app_df(fw_data->p15_card);
if (rv < 0) {
sc_unlock(ses->slot->card->card);
return sc_to_cryptoki_error(rv, ses->slot->card->reader);
return sc_to_cryptoki_error(rv);
}
}
@ -2368,7 +2359,7 @@ static CK_RV pkcs15_prkey_sign(struct sc_pkcs11_session *ses, void *obj,
return CKR_OK;
}
return sc_to_cryptoki_error(rv, ses->slot->card->reader);
return sc_to_cryptoki_error(rv);
}
static CK_RV
@ -2408,13 +2399,13 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_session *ses, void *obj,
rv = sc_lock(ses->slot->card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, ses->slot->card->reader);
return sc_to_cryptoki_error(rv);
if (!sc_pkcs11_conf.lock_login) {
rv = reselect_app_df(fw_data->p15_card);
if (rv < 0) {
sc_unlock(ses->slot->card->card);
return sc_to_cryptoki_error(rv, ses->slot->card->reader);
return sc_to_cryptoki_error(rv);
}
}
@ -2427,7 +2418,7 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_session *ses, void *obj,
sc_debug(context, "Key unwrap/decryption complete. Result %d.\n", rv);
if (rv < 0)
return sc_to_cryptoki_error(rv, ses->slot->card->reader);
return sc_to_cryptoki_error(rv);
buff_too_small = (*pulDataLen < (CK_ULONG)rv);
*pulDataLen = rv;
@ -2455,7 +2446,7 @@ pkcs15_prkey_unwrap(struct sc_pkcs11_session *ses, void *obj,
unwrapped_key, &key_len);
if (r < 0)
return sc_to_cryptoki_error(r, ses->slot->card->reader);
return sc_to_cryptoki_error(r);
return sc_pkcs11_create_secret_key(ses,
unwrapped_key, key_len,
pTemplate, ulAttributeCount,
@ -2665,20 +2656,19 @@ static int pkcs15_dobj_get_value(struct sc_pkcs11_session *session,
struct pkcs15_fw_data *fw_data =
(struct pkcs15_fw_data *) session->slot->card->fw_data;
sc_card_t *card = session->slot->card->card;
int reader = session->slot->card->reader;
if (!out_data)
return SC_ERROR_INVALID_ARGUMENTS;
rv = sc_lock(card);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
rv = sc_pkcs15_read_data_object(fw_data->p15_card, dobj->info, out_data);
sc_unlock(card);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
return rv;
}
@ -2775,18 +2765,17 @@ static CK_RV pkcs15_dobj_destroy(struct sc_pkcs11_session *session, void *object
struct sc_pkcs11_card *card = session->slot->card;
struct pkcs15_fw_data *fw_data = (struct pkcs15_fw_data *) card->fw_data;
struct sc_profile *profile = NULL;
int reader = session->slot->card->reader;
int rv;
rv = sc_lock(card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, card->reader);
return sc_to_cryptoki_error(rv);
/* Bind the profile */
rv = sc_pkcs15init_bind(card->card, "pkcs15", NULL, &profile);
if (rv < 0) {
sc_unlock(card->card);
return sc_to_cryptoki_error(rv, card->reader);
return sc_to_cryptoki_error(rv);
}
/* Add the PINs the user presented so far to the keycache */
@ -2794,7 +2783,6 @@ static CK_RV pkcs15_dobj_destroy(struct sc_pkcs11_session *session, void *object
/* Delete object in smartcard */
rv = sc_pkcs15init_delete_object(fw_data->p15_card, profile, obj->base.p15_object);
/* FIXME: PIN revalidation missing, following belongs libopensc */
if (rv >= 0) {
/* pool_find_and_delete is called, therefore correct refcont
* Oppose to pkcs15_add_object */
@ -2807,7 +2795,7 @@ static CK_RV pkcs15_dobj_destroy(struct sc_pkcs11_session *session, void *object
sc_unlock(card->card);
if (rv < 0)
return sc_to_cryptoki_error(rv, reader);
return sc_to_cryptoki_error(rv);
return CKR_OK;
}

View File

@ -36,7 +36,7 @@ static CK_RV pkcs15init_bind(struct sc_pkcs11_card *p11card)
rc = sc_pkcs15init_bind(card, "pkcs15", NULL, &profile);
if (rc == 0)
p11card->fw_data = profile;
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
}
static CK_RV pkcs15init_unbind(struct sc_pkcs11_card *p11card)
@ -134,7 +134,7 @@ pkcs15init_initialize(struct sc_pkcs11_card *p11card, void *ptr,
args.label = (const char *) pLabel;
rc = sc_pkcs15init_add_app(p11card->card, profile, &args);
if (rc < 0)
return sc_to_cryptoki_error(rc, p11card->reader);
return sc_to_cryptoki_error(rc);
/* Change the binding from the pkcs15init framework
* to the pkcs15 framework on the fly.

View File

@ -52,7 +52,7 @@ sc_pkcs11_register_mechanism(struct sc_pkcs11_card *p11card,
* Look up a mechanism
*/
sc_pkcs11_mechanism_type_t *
sc_pkcs11_find_mechanism(struct sc_pkcs11_card *p11card, CK_MECHANISM_TYPE mech, int flags)
sc_pkcs11_find_mechanism(struct sc_pkcs11_card *p11card, CK_MECHANISM_TYPE mech, unsigned int flags)
{
sc_pkcs11_mechanism_type_t *mt;
unsigned int n;
@ -199,7 +199,7 @@ sc_pkcs11_md_final(struct sc_pkcs11_session *session,
CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
{
sc_pkcs11_operation_t *op;
int rv;
CK_RV rv;
rv = session_get_operation(session, SC_PKCS11_OPERATION_DIGEST, &op);
if (rv != CKR_OK)
@ -793,7 +793,7 @@ sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech,
#endif
}
if (pInfo->flags & CKF_UNWRAP) {
/* ... */
/* TODO */
}
if (pInfo->flags & CKF_DECRYPT) {
mt->decrypt_init = sc_pkcs11_decrypt_init;

View File

@ -24,22 +24,23 @@
#define DUMP_TEMPLATE_MAX 32
void strcpy_bp(u8 *dst, const char *src, size_t dstsize)
void strcpy_bp(u8 * dst, const char *src, size_t dstsize)
{
size_t c;
if (!dst || !src || !dstsize)
return;
memset((char *) dst, ' ', dstsize);
memset((char *)dst, ' ', dstsize);
c = strlen(src) > dstsize ? dstsize : strlen(src);
memcpy((char *) dst, src, c);
memcpy((char *)dst, src, c);
}
CK_RV sc_to_cryptoki_error(int rc, int reader)
CK_RV sc_to_cryptoki_error(int rc)
{
sc_debug(context, "opensc error: %s (%d)\n", sc_strerror(rc), rc);
switch (rc) {
case SC_SUCCESS:
return CKR_OK;
@ -54,7 +55,6 @@ CK_RV sc_to_cryptoki_error(int rc, int reader)
case SC_ERROR_BUFFER_TOO_SMALL:
return CKR_BUFFER_TOO_SMALL;
case SC_ERROR_CARD_NOT_PRESENT:
card_removed(reader);
return CKR_TOKEN_NOT_PRESENT;
case SC_ERROR_INVALID_CARD:
return CKR_TOKEN_NOT_RECOGNIZED;
@ -77,105 +77,29 @@ CK_RV sc_to_cryptoki_error(int rc, int reader)
case SC_ERROR_INCORRECT_PARAMETERS:
return CKR_DATA_INVALID;
case SC_ERROR_CARD_UNRESPONSIVE:
case SC_ERROR_READER_LOCKED:
return CKR_DEVICE_ERROR;
case SC_ERROR_READER_DETACHED:
return CKR_TOKEN_NOT_PRESENT; /* Maybe CKR_DEVICE_REMOVED ? */
case SC_ERROR_NOT_ENOUGH_MEMORY:
return CKR_DEVICE_MEMORY;
case SC_ERROR_MEMORY_FAILURE: /* EEPROM has failed */
case SC_ERROR_MEMORY_FAILURE: /* EEPROM has failed */
return CKR_DEVICE_ERROR;
}
sc_debug(context, "opensc error: %s (%d)\n", sc_strerror(rc), rc);
return CKR_GENERAL_ERROR;
}
/* Pool */
CK_RV pool_initialize(struct sc_pkcs11_pool *pool, int type)
{
pool->type = type;
pool->next_free_handle = 1;
pool->num_items = 0;
pool->head = pool->tail = NULL;
return CKR_OK;
}
CK_RV pool_insert(struct sc_pkcs11_pool *pool, void *item_ptr, CK_ULONG_PTR pHandle)
{
struct sc_pkcs11_pool_item *item;
int handle = pool->next_free_handle++;
item = (struct sc_pkcs11_pool_item*) malloc(sizeof(struct sc_pkcs11_pool_item));
if (pHandle != NULL)
*pHandle = handle;
item->handle = handle;
item->item = item_ptr;
item->next = NULL;
item->prev = pool->tail;
if (pool->head != NULL && pool->tail != NULL) {
pool->tail->next = item;
pool->tail = item;
} else
pool->head = pool->tail = item;
return CKR_OK;
}
CK_RV pool_find(struct sc_pkcs11_pool *pool, CK_ULONG handle, void **item_ptr)
{
struct sc_pkcs11_pool_item *item;
if (context == NULL)
return CKR_CRYPTOKI_NOT_INITIALIZED;
for (item = pool->head; item != NULL; item = item->next) {
if (item->handle == handle) {
*item_ptr = item->item;
return CKR_OK;
}
}
return (pool->type == POOL_TYPE_OBJECT)? CKR_OBJECT_HANDLE_INVALID
: CKR_SESSION_HANDLE_INVALID;
}
CK_RV pool_find_and_delete(struct sc_pkcs11_pool *pool, CK_ULONG handle, void **item_ptr)
{
struct sc_pkcs11_pool_item *item;
if (context == NULL)
return CKR_CRYPTOKI_NOT_INITIALIZED;
for (item = pool->head; item != NULL; item = item->next) {
if (handle == 0 || item->handle == handle) {
if (item->prev) item->prev->next = item->next;
if (item->next) item->next->prev = item->prev;
if (pool->head == item) pool->head = item->next;
if (pool->tail == item) pool->tail = item->prev;
*item_ptr = item->item;
free(item);
return CKR_OK;
}
}
return (pool->type == POOL_TYPE_OBJECT)? CKR_OBJECT_HANDLE_INVALID
: CKR_SESSION_HANDLE_INVALID;
}
/* Session manipulation */
CK_RV session_start_operation(struct sc_pkcs11_session *session,
int type,
sc_pkcs11_mechanism_type_t *mech,
struct sc_pkcs11_operation **operation)
CK_RV session_start_operation(struct sc_pkcs11_session * session,
int type, sc_pkcs11_mechanism_type_t * mech, struct sc_pkcs11_operation ** operation)
{
sc_pkcs11_operation_t *op;
if (context == NULL)
return CKR_CRYPTOKI_NOT_INITIALIZED;
SC_FUNC_CALLED(context, 3);
sc_debug(context, "Session 0x%lx, type %d", session->handle, type);
if (type < 0 || type >= SC_PKCS11_OPERATION_MAX)
return CKR_ARGUMENTS_BAD;
@ -192,11 +116,12 @@ CK_RV session_start_operation(struct sc_pkcs11_session *session,
return CKR_OK;
}
CK_RV session_get_operation(struct sc_pkcs11_session *session, int type,
sc_pkcs11_operation_t **operation)
CK_RV session_get_operation(struct sc_pkcs11_session * session, int type, sc_pkcs11_operation_t ** operation)
{
sc_pkcs11_operation_t *op;
SC_FUNC_CALLED(context, 3);
if (type < 0 || type >= SC_PKCS11_OPERATION_MAX)
return CKR_ARGUMENTS_BAD;
@ -209,7 +134,7 @@ CK_RV session_get_operation(struct sc_pkcs11_session *session, int type,
return CKR_OK;
}
CK_RV session_stop_operation(struct sc_pkcs11_session *session, int type)
CK_RV session_stop_operation(struct sc_pkcs11_session * session, int type)
{
if (type < 0 || type >= SC_PKCS11_OPERATION_MAX)
return CKR_ARGUMENTS_BAD;
@ -221,9 +146,9 @@ CK_RV session_stop_operation(struct sc_pkcs11_session *session, int type)
return CKR_OK;
}
CK_RV attr_extract(CK_ATTRIBUTE_PTR pAttr, void *ptr, size_t *sizep)
CK_RV attr_extract(CK_ATTRIBUTE_PTR pAttr, void *ptr, size_t * sizep)
{
unsigned int size;
unsigned int size;
if (sizep) {
size = *sizep;
@ -233,17 +158,23 @@ CK_RV attr_extract(CK_ATTRIBUTE_PTR pAttr, void *ptr, size_t *sizep)
} else {
switch (pAttr->type) {
case CKA_CLASS:
size = sizeof(CK_OBJECT_CLASS); break;
size = sizeof(CK_OBJECT_CLASS);
break;
case CKA_KEY_TYPE:
size = sizeof(CK_KEY_TYPE); break;
size = sizeof(CK_KEY_TYPE);
break;
case CKA_PRIVATE:
size = sizeof(CK_BBOOL); break;
size = sizeof(CK_BBOOL);
break;
case CKA_CERTIFICATE_TYPE:
size = sizeof(CK_CERTIFICATE_TYPE); break;
size = sizeof(CK_CERTIFICATE_TYPE);
break;
case CKA_MODULUS_BITS:
size = sizeof(CK_ULONG); break;
size = sizeof(CK_ULONG);
break;
case CKA_OBJECT_ID:
size = sizeof(struct sc_object_id); break;
size = sizeof(struct sc_object_id);
break;
default:
return CKR_FUNCTION_FAILED;
}
@ -254,10 +185,9 @@ CK_RV attr_extract(CK_ATTRIBUTE_PTR pAttr, void *ptr, size_t *sizep)
return CKR_OK;
}
CK_RV attr_find(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_ULONG type, void *ptr, size_t *sizep)
CK_RV attr_find(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void *ptr, size_t * sizep)
{
unsigned int n;
unsigned int n;
for (n = 0; n < ulCount; n++, pTemplate++) {
if (pTemplate->type == type)
@ -270,11 +200,10 @@ CK_RV attr_find(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
}
CK_RV attr_find2(CK_ATTRIBUTE_PTR pTemp1, CK_ULONG ulCount1,
CK_ATTRIBUTE_PTR pTemp2, CK_ULONG ulCount2,
CK_ULONG type, void *ptr, size_t *sizep)
CK_ATTRIBUTE_PTR pTemp2, CK_ULONG ulCount2, CK_ULONG type, void *ptr, size_t * sizep)
{
CK_RV rv;
rv = attr_find(pTemp1, ulCount1, type, ptr, sizep);
if (rv != CKR_OK)
rv = attr_find(pTemp2, ulCount2, type, ptr, sizep);
@ -282,10 +211,9 @@ CK_RV attr_find2(CK_ATTRIBUTE_PTR pTemp1, CK_ULONG ulCount1,
return rv;
}
CK_RV attr_find_ptr(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_ULONG type, void **ptr, size_t *sizep)
CK_RV attr_find_ptr(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void **ptr, size_t * sizep)
{
unsigned int n;
unsigned int n;
for (n = 0; n < ulCount; n++, pTemplate++) {
if (pTemplate->type == type)
@ -301,10 +229,9 @@ CK_RV attr_find_ptr(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
return CKR_OK;
}
CK_RV attr_find_var(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_ULONG type, void *ptr, size_t *sizep)
CK_RV attr_find_var(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_ULONG type, void *ptr, size_t * sizep)
{
unsigned int n;
unsigned int n;
for (n = 0; n < ulCount; n++, pTemplate++) {
if (pTemplate->type == type)
@ -317,7 +244,7 @@ CK_RV attr_find_var(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
return attr_extract(pTemplate, ptr, sizep);
}
void load_pkcs11_parameters(struct sc_pkcs11_config *conf, sc_context_t *ctx)
void load_pkcs11_parameters(struct sc_pkcs11_config *conf, sc_context_t * ctx)
{
scconf_block *conf_block = NULL;
char *unblock_style = NULL;
@ -345,7 +272,7 @@ void load_pkcs11_parameters(struct sc_pkcs11_config *conf, sc_context_t *ctx)
conf->lock_login = scconf_get_bool(conf_block, "lock_login", conf->lock_login);
conf->soft_keygen_allowed = scconf_get_bool(conf_block, "soft_keygen_allowed", conf->soft_keygen_allowed);
unblock_style = (char *) scconf_get_str(conf_block, "user_pin_unblock_style", NULL);
unblock_style = (char *)scconf_get_str(conf_block, "user_pin_unblock_style", NULL);
if (unblock_style && !strcmp(unblock_style, "set_pin_in_unlogged_session"))
conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_UNLOGGED_SETPIN;
else if (unblock_style && !strcmp(unblock_style, "set_pin_in_specific_context"))
@ -354,7 +281,7 @@ void load_pkcs11_parameters(struct sc_pkcs11_config *conf, sc_context_t *ctx)
conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_SO_LOGGED_INITPIN;
sc_debug(ctx, "PKCS#11 options: plug_and_play=%d max_virtual_slots=%d slots_per_card=%d "
"hide_empty_tokens=%d lock_login=%d pin_unblock_style=%d",
conf->plug_and_play, conf->max_virtual_slots, conf->slots_per_card,
conf->hide_empty_tokens, conf->lock_login, conf->pin_unblock_style);
"hide_empty_tokens=%d lock_login=%d pin_unblock_style=%d",
conf->plug_and_play, conf->max_virtual_slots, conf->slots_per_card,
conf->hide_empty_tokens, conf->lock_login, conf->pin_unblock_style);
}

View File

@ -30,14 +30,13 @@
#include "sc-pkcs11.h"
sc_context_t *context = NULL;
struct sc_pkcs11_pool session_pool;
struct sc_pkcs11_slot *virtual_slots = NULL;
struct sc_pkcs11_card card_table[SC_MAX_READERS];
struct sc_pkcs11_config sc_pkcs11_conf;
list_t sessions;
list_t virtual_slots;
#if !defined(_WIN32)
pid_t initialized_pid = (pid_t)-1;
#endif
static int in_finalize = 0;
extern CK_FUNCTION_LIST pkcs11_function_list;
#if defined(HAVE_PTHREAD) && defined(PKCS11_THREAD_LOCKING)
@ -170,13 +169,33 @@ static sc_thread_context_t sc_thread_ctx = {
sc_unlock_mutex, sc_destroy_mutex, NULL
};
/* simclist helpers to locate interesting objects by ID */
static int session_list_seeker(const void *el, const void *key) {
const struct sc_pkcs11_session *session = (struct sc_pkcs11_session *)el;
if ((el == NULL) || (key == NULL))
return 0;
if (session->handle == *(CK_SESSION_HANDLE*)key)
return 1;
return 0;
}
static int slot_list_seeker(const void *el, const void *key) {
const struct sc_pkcs11_slot *slot = (struct sc_pkcs11_slot *)el;
if ((el == NULL) || (key == NULL))
return 0;
if (slot->id == *(CK_SLOT_ID *)key)
return 1;
return 0;
}
CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
{
#if !defined(_WIN32)
pid_t current_pid = getpid();
#endif
int rc, rv;
unsigned int i;
int rc, rv;
sc_context_param_t ctx_opts;
/* Handle fork() exception */
@ -185,6 +204,7 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
C_Finalize(NULL_PTR);
}
initialized_pid = current_pid;
in_finalize = 0;
#endif
if (context != NULL) {
@ -211,26 +231,32 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
/* Load configuration */
load_pkcs11_parameters(&sc_pkcs11_conf, context);
first_free_slot = 0;
virtual_slots = (struct sc_pkcs11_slot *)malloc(
sizeof (*virtual_slots) * sc_pkcs11_conf.max_virtual_slots
);
if (virtual_slots == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
/* List of sessions */
list_init(&sessions);
list_attributes_seeker(&sessions, session_list_seeker);
/* List of slots */
list_init(&virtual_slots);
list_attributes_seeker(&virtual_slots, slot_list_seeker);
/* Create a slot for a future "PnP" stuff. */
if (sc_pkcs11_conf.plug_and_play) {
create_slot(NULL);
}
/* Create slots for readers found on initialization */
for (i=0; i<sc_ctx_get_reader_count(context); i++) {
initialize_reader(sc_ctx_get_reader(context, i));
}
pool_initialize(&session_pool, POOL_TYPE_SESSION);
for (i=0; i<sc_pkcs11_conf.max_virtual_slots; i++)
slot_initialize(i, &virtual_slots[i]);
for (i=0; i<SC_MAX_READERS; i++)
card_initialize(i);
/* Detect any card, but do not flag "insert" events */
__card_detect_all(0);
/* Set initial event state on slots */
for (i=0; i<list_size(&virtual_slots); i++) {
sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
slot->events = 0; /* Initially there are no events */
}
out:
if (context != NULL)
sc_debug(context, "C_Initialize: result = %d\n", rv);
sc_debug(context, "C_Initialize() = %s", lookup_enum ( RV_T, rv ));
if (rv != CKR_OK) {
if (context != NULL) {
@ -261,15 +287,19 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved)
goto out;
}
sc_debug(context, "Shutting down Cryptoki\n");
sc_debug(context, "C_Finalize()");
/* cancel pending calls */
in_finalize = 1;
sc_cancel(context);
/* remove all cards from readers */
for (i=0; i < (int)sc_ctx_get_reader_count(context); i++)
card_removed(i);
if (virtual_slots) {
free(virtual_slots);
virtual_slots = NULL;
}
card_removed(sc_ctx_get_reader(context, i));
list_destroy(&sessions);
list_destroy(&virtual_slots);
sc_release_context(context);
context = NULL;
@ -292,7 +322,7 @@ CK_RV C_GetInfo(CK_INFO_PTR pInfo)
goto out;
}
sc_debug(context, "Cryptoki info query\n");
sc_debug(context, "C_GetInfo()");
memset(pInfo, 0, sizeof(CK_INFO));
pInfo->cryptokiVersion.major = 2;
@ -301,7 +331,7 @@ CK_RV C_GetInfo(CK_INFO_PTR pInfo)
"OpenSC (www.opensc-project.org)",
sizeof(pInfo->manufacturerID));
strcpy_bp(pInfo->libraryDescription,
"smart card PKCS#11 API",
"Smart card PKCS#11 API",
sizeof(pInfo->libraryDescription));
pInfo->libraryVersion.major = 0;
pInfo->libraryVersion.minor = 0; /* FIXME: use 0.116 for 0.11.6 from autoconf */
@ -347,19 +377,23 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese
goto out;
}
sc_debug(context, "Getting slot listing\n");
sc_debug(context, "C_GetSlotList(token=%d, %s)", tokenPresent, (pSlotList==NULL_PTR && sc_pkcs11_conf.plug_and_play)? "plug-n-play":"refresh");
/* Slot list can only change in v2.20 */
if (pSlotList == NULL_PTR && sc_pkcs11_conf.plug_and_play) {
sc_ctx_detect_readers(context);
/* Trick NSS into updating the slot list by changing the hotplug slot ID */
sc_pkcs11_slot_t *hotplug_slot = list_get_at(&virtual_slots, 0);
hotplug_slot->id--;
sc_ctx_detect_readers(context);
}
card_detect_all();
numMatches = 0;
for (i=0; i<sc_pkcs11_conf.max_virtual_slots; i++) {
slot = &virtual_slots[i];
if (!tokenPresent || (slot->slot_info.flags & CKF_TOKEN_PRESENT))
found[numMatches++] = i;
for (i=0; i<list_size(&virtual_slots); i++) {
slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
if (!tokenPresent || (slot->slot_info.flags & CKF_TOKEN_PRESENT))
found[numMatches++] = slot->id;
}
if (pSlotList == NULL_PTR) {
@ -433,16 +467,20 @@ CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
goto out;
}
sc_debug(context, "Getting info about slot %d\n", slotID);
sc_debug(context, "C_GetSlotInfo(0x%lx)", slotID);
rv = slot_get_slot(slotID, &slot);
if (rv == CKR_OK){
now = get_current_time();
if (now >= card_table[slot->reader].slot_state_expires || now == 0) {
/* Update slot status */
rv = card_detect(slot->reader);
/* Don't ask again within the next second */
card_table[slot->reader].slot_state_expires = now + 1000;
if (slot->reader == NULL)
rv = CKR_TOKEN_NOT_PRESENT;
else {
now = get_current_time();
if (now >= slot->slot_state_expires || now == 0) {
/* Update slot status */
rv = card_detect(slot->reader);
/* Don't ask again within the next second */
slot->slot_state_expires = now + 1000;
}
}
}
if (rv == CKR_TOKEN_NOT_PRESENT || rv == CKR_TOKEN_NOT_RECOGNIZED)
@ -451,7 +489,8 @@ CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
if (rv == CKR_OK)
memcpy(pInfo, &slot->slot_info, sizeof(CK_SLOT_INFO));
out: sc_pkcs11_unlock();
out: sc_debug(context, "C_GetSlotInfo(0x%lx) = %s", slotID, lookup_enum ( RV_T, rv ));
sc_pkcs11_unlock();
return rv;
}
@ -469,9 +508,10 @@ CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
goto out;
}
sc_debug(context, "Getting info about token in slot %d\n", slotID);
sc_debug(context, "C_GetTokenInfo(%lx)", slotID);
rv = slot_get_token(slotID, &slot);
/* TODO: update token flags */
if (rv == CKR_OK)
memcpy(pInfo, &slot->token_info, sizeof(CK_TOKEN_INFO));
@ -526,10 +566,10 @@ CK_RV C_InitToken(CK_SLOT_ID slotID,
CK_ULONG ulPinLen,
CK_CHAR_PTR pLabel)
{
struct sc_pkcs11_pool_item *item;
struct sc_pkcs11_session *session;
struct sc_pkcs11_slot *slot;
CK_RV rv;
unsigned int i;
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
@ -538,10 +578,10 @@ CK_RV C_InitToken(CK_SLOT_ID slotID,
rv = slot_get_token(slotID, &slot);
if (rv != CKR_OK)
goto out;
/* Make sure there's no open session for this token */
for (item = session_pool.head; item; item = item->next) {
session = (struct sc_pkcs11_session*) item->item;
for (i=0; i<list_size(&sessions); i++) {
session = (struct sc_pkcs11_session*)list_get_at(&sessions, i);
if (session->slot == slot) {
rv = CKR_SESSION_EXISTS;
goto out;
@ -568,68 +608,59 @@ 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 *reader, *readers[SC_MAX_SLOTS * SC_MAX_READERS];
int slots[SC_MAX_SLOTS * SC_MAX_READERS];
int i, j, k, r, found;
sc_reader_t *found;
int r;
unsigned int mask, events;
CK_RV rv;
if (pReserved != NULL_PTR) {
return CKR_ARGUMENTS_BAD;
}
/* Firefox 1.5 (NSS 3.10) calls this function (blocking) from a seperate thread,
* which gives 2 problems:
* - on Windows/Mac: this waiting thread will log to a NULL context
* after the 'main' thread does a C_Finalize() and sets the ctx to NULL.
* - on Linux, things just hang (at least on Debian 'sid')
* So we just return CKR_FUNCTION_NOT_SUPPORTED on a blocking call,
* in which case FF just seems to default to polling in the main thread
* as earlier NSS versions.
*/
sc_debug(context, "C_WaitForSlotEvent(block=%d)", !(flags & CKF_DONT_BLOCK));
#if 0
/* pcsc-lite does not implement it in a threaded way */
if (!(flags & CKF_DONT_BLOCK))
return CKR_FUNCTION_NOT_SUPPORTED;
#endif
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
return rv;
if (pReserved != NULL_PTR) {
rv = CKR_ARGUMENTS_BAD;
goto out;
}
mask = SC_EVENT_CARD_INSERTED|SC_EVENT_CARD_REMOVED;
/* Detect and add new slots for added readers v2.20 */
if (sc_pkcs11_conf.plug_and_play) {
mask |= SC_EVENT_READER_ATTACHED;
}
if ((rv = slot_find_changed(pSlot, mask)) == CKR_OK
|| (flags & CKF_DONT_BLOCK))
goto out;
for (i = k = 0; i < (int)sc_ctx_get_reader_count(context); i++) {
reader = sc_ctx_get_reader(context, i);
if (reader == NULL) {
rv = CKR_GENERAL_ERROR;
goto out;
}
for (j = 0; j < reader->slot_count; j++, k++) {
readers[k] = reader;
slots[k] = j;
}
}
again:
/* Check if C_Finalize() has been called in another thread */
if (context == NULL)
return CKR_CRYPTOKI_NOT_INITIALIZED;
sc_pkcs11_unlock();
r = sc_wait_for_event(readers, slots, k, mask, &found, &events, -1);
r = sc_wait_for_event(context, mask, &found, &events, -1);
/* There may have been a C_Finalize while we slept */
if (context == NULL)
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 = CKR_OK;
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_debug(context, "sc_wait_for_event() returned %d\n", r);
rv = sc_to_cryptoki_error(r, -1);
rv = sc_to_cryptoki_error(r);
goto out;
}
@ -638,7 +669,8 @@ again:
if ((rv = slot_find_changed(pSlot, mask)) != CKR_OK)
goto again;
out: sc_pkcs11_unlock();
out: sc_debug(context, "C_WaitForSlotEvent() = %s, event in 0x%lx", lookup_enum (RV_T, rv), *pSlot);
sc_pkcs11_unlock();
return rv;
}

File diff suppressed because it is too large Load Diff

View File

@ -23,12 +23,20 @@
#include <string.h>
#include "sc-pkcs11.h"
CK_RV C_OpenSession(CK_SLOT_ID slotID, /* the slot's ID */
CK_FLAGS flags, /* defined in CK_SESSION_INFO */
CK_VOID_PTR pApplication, /* pointer passed to callback */
CK_NOTIFY Notify, /* notification callback function */
CK_SESSION_HANDLE_PTR phSession) /* receives new session handle */
CK_RV get_session(CK_SESSION_HANDLE hSession, struct sc_pkcs11_session **session)
{
*session = list_seek(&sessions, &hSession);
if (!*session)
return CKR_SESSION_HANDLE_INVALID;
return CKR_OK;
}
CK_RV C_OpenSession(CK_SLOT_ID slotID, /* the slot's ID */
CK_FLAGS flags, /* defined in CK_SESSION_INFO */
CK_VOID_PTR pApplication, /* pointer passed to callback */
CK_NOTIFY Notify, /* notification callback function */
CK_SESSION_HANDLE_PTR phSession)
{ /* receives new session handle */
struct sc_pkcs11_slot *slot;
struct sc_pkcs11_session *session;
int rv;
@ -37,7 +45,7 @@ CK_RV C_OpenSession(CK_SLOT_ID slotID, /* the slot's ID */
if (rv != CKR_OK)
return rv;
sc_debug(context, "Opening new session for slot %d\n", slotID);
sc_debug(context, "C_OpenSession(0x%lx)", slotID);
if (!(flags & CKF_SERIAL_SESSION)) {
rv = CKR_SESSION_PARALLEL_NOT_SUPPORTED;
@ -59,24 +67,23 @@ CK_RV C_OpenSession(CK_SLOT_ID slotID, /* the slot's ID */
goto out;
}
session = (struct sc_pkcs11_session*) calloc(1, sizeof(struct sc_pkcs11_session));
session = (struct sc_pkcs11_session *)calloc(1, sizeof(struct sc_pkcs11_session));
if (session == NULL) {
rv = CKR_HOST_MEMORY;
goto out;
}
session->slot = slot;
session->notify_callback = Notify;
session->notify_data = pApplication;
session->flags = flags;
rv = pool_insert(&session_pool, session, phSession);
if (rv != CKR_OK)
free(session);
else
slot->nsessions++;
out: sc_pkcs11_unlock();
slot->nsessions++;
session->handle = (CK_SESSION_HANDLE) session; // cast a pointer to long
list_append(&sessions, session);
*phSession = session->handle;
sc_debug(context, "C_OpenSession handle: 0x%lx", session->handle);
out:sc_debug(context, "C_OpenSession() = %s", lookup_enum(RV_T, rv));
sc_pkcs11_unlock();
return rv;
}
@ -86,11 +93,12 @@ static CK_RV sc_pkcs11_close_session(CK_SESSION_HANDLE hSession)
{
struct sc_pkcs11_slot *slot;
struct sc_pkcs11_session *session;
int rv;
rv = pool_find_and_delete(&session_pool, hSession, (void**) &session);
if (rv != CKR_OK)
return rv;
sc_debug(context, "real C_CloseSession(0x%lx)", hSession);
session = list_seek(&sessions, &hSession);
if (!session)
return CKR_SESSION_HANDLE_INVALID;
/* If we're the last session using this slot, make sure
* we log out */
@ -101,6 +109,8 @@ static CK_RV sc_pkcs11_close_session(CK_SESSION_HANDLE hSession)
slot->card->framework->logout(slot->card, slot->fw_data);
}
if (list_delete(&sessions, session) != 0)
sc_debug(context, "Could not delete session from list!");
free(session);
return CKR_OK;
}
@ -109,26 +119,24 @@ static CK_RV sc_pkcs11_close_session(CK_SESSION_HANDLE hSession)
* the global lock held */
CK_RV sc_pkcs11_close_all_sessions(CK_SLOT_ID slotID)
{
struct sc_pkcs11_pool_item *item, *next;
struct sc_pkcs11_session *session;
sc_debug(context, "C_CloseAllSessions(slot %d).\n", (int) slotID);
for (item = session_pool.head; item != NULL; item = next) {
session = (struct sc_pkcs11_session*) item->item;
next = item->next;
if (session->slot->id == (int)slotID)
sc_pkcs11_close_session(item->handle);
CK_RV rv = CKR_OK;
unsigned int i;
sc_debug(context, "real C_CloseAllSessions(0x%lx) %d", slotID, list_size(&sessions));
for (i = 0; i < list_size(&sessions); i++) {
session = list_get_at(&sessions, i);
if (session->slot->id == slotID)
if ((rv = sc_pkcs11_close_session(session->handle)) != CKR_OK)
return rv;
}
return CKR_OK;
}
CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) /* the session's handle */
{
CK_RV C_CloseSession(CK_SESSION_HANDLE hSession)
{ /* the session's handle */
int rv;
sc_debug(context, "C_CloseSession(%lx)\n", (long) hSession);
sc_debug(context, "C_CloseSession(0x%lx)\n", hSession);
rv = sc_pkcs11_lock();
if (rv == CKR_OK)
@ -137,11 +145,12 @@ CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) /* the session's handle */
return rv;
}
CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) /* the token's slot */
{
CK_RV C_CloseAllSessions(CK_SLOT_ID slotID)
{ /* the token's slot */
struct sc_pkcs11_slot *slot;
int rv;
sc_debug(context, "C_CloseAllSessions(0x%lx)\n", slotID);
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
return rv;
@ -152,17 +161,18 @@ CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) /* the token's slot */
rv = sc_pkcs11_close_all_sessions(slotID);
out: sc_pkcs11_unlock();
out:sc_pkcs11_unlock();
return rv;
}
CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_SESSION_INFO_PTR pInfo) /* receives session information */
{
CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_SESSION_INFO_PTR pInfo)
{ /* receives session information */
struct sc_pkcs11_session *session;
struct sc_pkcs11_slot *slot;
int rv;
sc_debug(context, "C_GetSessionInfo(0x%lx)", hSession);
rv = sc_pkcs11_lock();
if (rv != CKR_OK)
return rv;
@ -172,11 +182,13 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */
goto out;
}
rv = pool_find(&session_pool, hSession, (void**) &session);
if (rv != CKR_OK)
session = list_seek(&sessions, &hSession);
if (!session) {
rv = CKR_SESSION_HANDLE_INVALID;
goto out;
}
sc_debug(context, "C_GetSessionInfo(slot %d).\n", session->slot->id);
sc_debug(context, "C_GetSessionInfo(slot 0x%lx).", session->slot->id);
pInfo->slotID = session->slot->id;
pInfo->flags = session->flags;
pInfo->ulDeviceError = 0;
@ -184,41 +196,41 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */
slot = session->slot;
if (slot->login_user == CKU_SO) {
pInfo->state = CKS_RW_SO_FUNCTIONS;
} else
if (slot->login_user == CKU_USER
|| (!(slot->token_info.flags & CKF_LOGIN_REQUIRED))) {
} else if (slot->login_user == CKU_USER || (!(slot->token_info.flags & CKF_LOGIN_REQUIRED))) {
pInfo->state = (session->flags & CKF_RW_SESSION)
? CKS_RW_USER_FUNCTIONS : CKS_RO_USER_FUNCTIONS;
? CKS_RW_USER_FUNCTIONS : CKS_RO_USER_FUNCTIONS;
} else {
pInfo->state = (session->flags & CKF_RW_SESSION)
? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION;
? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION;
}
out: sc_pkcs11_unlock();
out:
sc_debug(context, "C_GetSessionInfo(0x%lx) = %s", hSession, lookup_enum(RV_T, rv));
sc_pkcs11_unlock();
return rv;
}
CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pOperationState, /* location receiving state */
CK_ULONG_PTR pulOperationStateLen) /* location receiving state length */
{
CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pOperationState, /* location receiving state */
CK_ULONG_PTR pulOperationStateLen)
{ /* location receiving state length */
return CKR_FUNCTION_NOT_SUPPORTED;
}
CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pOperationState, /* the location holding the state */
CK_ULONG ulOperationStateLen, /* location holding state length */
CK_OBJECT_HANDLE hEncryptionKey, /* handle of en/decryption key */
CK_OBJECT_HANDLE hAuthenticationKey) /* handle of sign/verify key */
{
CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pOperationState, /* the location holding the state */
CK_ULONG ulOperationStateLen, /* location holding state length */
CK_OBJECT_HANDLE hEncryptionKey, /* handle of en/decryption key */
CK_OBJECT_HANDLE hAuthenticationKey)
{ /* handle of sign/verify key */
return CKR_FUNCTION_NOT_SUPPORTED;
}
CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_USER_TYPE userType, /* the user type */
CK_CHAR_PTR pPin, /* the user's PIN */
CK_ULONG ulPinLen) /* the length of the PIN */
{
CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_USER_TYPE userType, /* the user type */
CK_CHAR_PTR pPin, /* the user's PIN */
CK_ULONG ulPinLen)
{ /* the length of the PIN */
int rv;
struct sc_pkcs11_session *session;
struct sc_pkcs11_slot *slot;
@ -236,12 +248,13 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */
rv = CKR_USER_TYPE_INVALID;
goto out;
}
rv = pool_find(&session_pool, hSession, (void**) &session);
if (rv != CKR_OK)
session = list_seek(&sessions, &hSession);
if (!session) {
rv = CKR_SESSION_HANDLE_INVALID;
goto out;
}
sc_debug(context, "Login for session %d; userType %d\n", hSession, userType);
sc_debug(context, "C_Login(0x%lx, %d)", hSession, userType);
slot = session->slot;
@ -250,25 +263,34 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */
goto out;
}
if (slot->login_user >= 0) {
if ((CK_USER_TYPE)slot->login_user == userType)
rv = CKR_USER_ALREADY_LOGGED_IN;
else
rv = CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
goto out;
/* TODO: check if context specific is valid */
if (userType == CKU_CONTEXT_SPECIFIC) {
if (slot->login_user == -1) {
rv = CKR_OPERATION_NOT_INITIALIZED;
goto out;
} else
userType = slot->login_user;
} else {
if (slot->login_user >= 0) {
if ((CK_USER_TYPE) slot->login_user == userType)
rv = CKR_USER_ALREADY_LOGGED_IN;
else
rv = CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
goto out;
}
}
rv = slot->card->framework->login(slot->card, slot->fw_data,
userType, pPin, ulPinLen);
rv = slot->card->framework->login(slot->card, slot->fw_data, userType, pPin, ulPinLen);
if (rv == CKR_OK)
slot->login_user = userType;
out: sc_pkcs11_unlock();
out:sc_pkcs11_unlock();
return rv;
}
CK_RV C_Logout(CK_SESSION_HANDLE hSession) /* the session's handle */
{
CK_RV C_Logout(CK_SESSION_HANDLE hSession)
{ /* the session's handle */
int rv;
struct sc_pkcs11_session *session;
struct sc_pkcs11_slot *slot;
@ -277,28 +299,27 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession) /* the session's handle */
if (rv != CKR_OK)
return rv;
rv = pool_find(&session_pool, hSession, (void**) &session);
if (rv != CKR_OK)
session = list_seek(&sessions, &hSession);
if (!session) {
rv = CKR_SESSION_HANDLE_INVALID;
goto out;
}
sc_debug(context, "Logout for session %d\n", hSession);
sc_debug(context, "C_Logout(0x%lx)", hSession);
slot = session->slot;
if (slot->login_user >= 0) {
slot->login_user = -1;
rv = slot->card->framework->logout(slot->card, slot->fw_data);
}
else
} else
rv = CKR_USER_NOT_LOGGED_IN;
out: sc_pkcs11_unlock();
out:sc_pkcs11_unlock();
return rv;
}
CK_RV C_InitPIN(CK_SESSION_HANDLE hSession,
CK_CHAR_PTR pPin,
CK_ULONG ulPinLen)
CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
{
struct sc_pkcs11_session *session;
struct sc_pkcs11_slot *slot;
@ -313,9 +334,11 @@ CK_RV C_InitPIN(CK_SESSION_HANDLE hSession,
goto out;
}
rv = pool_find(&session_pool, hSession, (void**) &session);
if (rv != CKR_OK)
session = list_seek(&sessions, &hSession);
if (!session) {
rv = CKR_SESSION_HANDLE_INVALID;
goto out;
}
if (!(session->flags & CKF_RW_SESSION)) {
rv = CKR_SESSION_READ_ONLY;
@ -325,23 +348,18 @@ CK_RV C_InitPIN(CK_SESSION_HANDLE hSession,
slot = session->slot;
if (slot->login_user != CKU_SO) {
rv = CKR_USER_NOT_LOGGED_IN;
} else
if (slot->card->framework->init_pin == NULL) {
} else if (slot->card->framework->init_pin == NULL) {
rv = CKR_FUNCTION_NOT_SUPPORTED;
} else {
rv = slot->card->framework->init_pin(slot->card, slot,
pPin, ulPinLen);
rv = slot->card->framework->init_pin(slot->card, slot, pPin, ulPinLen);
}
out: sc_pkcs11_unlock();
out:sc_pkcs11_unlock();
return rv;
}
CK_RV C_SetPIN(CK_SESSION_HANDLE hSession,
CK_CHAR_PTR pOldPin,
CK_ULONG ulOldLen,
CK_CHAR_PTR pNewPin,
CK_ULONG ulNewLen)
CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
{
int rv;
struct sc_pkcs11_session *session;
@ -352,17 +370,20 @@ CK_RV C_SetPIN(CK_SESSION_HANDLE hSession,
return rv;
if ((pOldPin == NULL_PTR && ulOldLen > 0)
|| (pNewPin == NULL_PTR && ulNewLen > 0)) {
|| (pNewPin == NULL_PTR && ulNewLen > 0)) {
rv = CKR_ARGUMENTS_BAD;
goto out;
}
rv = pool_find(&session_pool, hSession, (void**) &session);
if (rv != CKR_OK)
session = list_seek(&sessions, &hSession);
if (!session) {
rv = CKR_SESSION_HANDLE_INVALID;
goto out;
}
sc_debug(context, "Changing PIN (session 0x%lx; login user %d)\n", hSession,
slot->login_user);
slot = session->slot;
sc_debug(context, "Changing PIN (session %d; login user %d)\n", hSession, slot->login_user);
if (!(session->flags & CKF_RW_SESSION)) {
rv = CKR_SESSION_READ_ONLY;
@ -370,8 +391,9 @@ CK_RV C_SetPIN(CK_SESSION_HANDLE hSession,
}
rv = slot->card->framework->change_pin(slot->card, slot->fw_data,
slot->login_user, pOldPin, ulOldLen, pNewPin, ulNewLen);
slot->login_user, pOldPin, ulOldLen, pNewPin,
ulNewLen);
out: sc_pkcs11_unlock();
out:sc_pkcs11_unlock();
return rv;
}

View File

@ -34,6 +34,7 @@
#define CRYPTOKI_EXPORTS
#include <pkcs11.h>
#include <pkcs11-opensc.h>
#include "pkcs11-display.h"
#ifdef __cplusplus
extern "C" {
@ -70,27 +71,6 @@ struct sc_pkcs11_session;
struct sc_pkcs11_slot;
struct sc_pkcs11_card;
/* Object Pool */
struct sc_pkcs11_pool_item {
unsigned long int handle;
void *item;
struct sc_pkcs11_pool_item *next;
struct sc_pkcs11_pool_item *prev;
};
enum {
POOL_TYPE_SESSION,
POOL_TYPE_OBJECT
};
struct sc_pkcs11_pool {
int type;
int next_free_handle;
int num_items;
struct sc_pkcs11_pool_item *head;
struct sc_pkcs11_pool_item *tail;
};
struct sc_pkcs11_config {
unsigned int plug_and_play;
unsigned int max_virtual_slots;
@ -136,6 +116,7 @@ struct sc_pkcs11_object_ops {
};
struct sc_pkcs11_object {
CK_OBJECT_HANDLE handle;
int flags;
struct sc_pkcs11_object_ops *ops;
};
@ -205,16 +186,10 @@ typedef unsigned __int64 sc_timestamp_t;
#endif
struct sc_pkcs11_card {
int reader;
struct sc_card *card;
sc_reader_t *reader;
sc_card_t *card;
struct sc_pkcs11_framework_ops *framework;
void *fw_data;
sc_timestamp_t slot_state_expires;
/* Number of slots owned by this card object */
unsigned int num_slots;
unsigned int max_slots;
unsigned int first_slot;
/* List of supported mechanisms */
struct sc_pkcs11_mechanism_type **mechanisms;
@ -222,27 +197,17 @@ struct sc_pkcs11_card {
};
struct sc_pkcs11_slot {
int id;
int login_user;
/* Slot specific information (information about reader) */
CK_SLOT_INFO slot_info;
/* Token specific information (information about card) */
CK_TOKEN_INFO token_info;
/* Reader to which card is allocated (same as card->reader
* if there's a card present) */
int reader;
/* The card associated with this slot */
struct sc_pkcs11_card *card;
/* Card events SC_EVENT_CARD_{INSERTED,REMOVED} */
int events;
/* Framework specific data */
void *fw_data;
/* Object pools */
struct sc_pkcs11_pool object_pool;
/* Number of sessions using this slot */
unsigned int nsessions;
CK_SLOT_ID id; /* ID of the slot */
int login_user; /* Currently logged in user */
CK_SLOT_INFO slot_info; /* Slot specific information (information about reader) */
CK_TOKEN_INFO token_info; /* Token specific information (information about card) */
sc_reader_t *reader; /* same as card->reader if there's a card present */
struct sc_pkcs11_card *card; /* The card associated with this slot */
unsigned int events; /* Card events SC_EVENT_CARD_{INSERTED,REMOVED} */
void *fw_data; /* Framework specific data */
list_t objects; /* Objects in this slot */
unsigned int nsessions; /* Number of sessions using this slot */
sc_timestamp_t slot_state_expires;
};
typedef struct sc_pkcs11_slot sc_pkcs11_slot_t;
@ -325,6 +290,7 @@ struct sc_pkcs11_find_operation {
*/
struct sc_pkcs11_session {
CK_SESSION_HANDLE handle;
/* Session to this slot */
struct sc_pkcs11_slot *slot;
CK_FLAGS flags;
@ -338,18 +304,17 @@ typedef struct sc_pkcs11_session sc_pkcs11_session_t;
/* Module variables */
extern struct sc_context *context;
extern struct sc_pkcs11_pool session_pool;
extern struct sc_pkcs11_slot *virtual_slots;
extern struct sc_pkcs11_card card_table[SC_MAX_READERS];
extern struct sc_pkcs11_config sc_pkcs11_conf;
extern unsigned int first_free_slot;
extern list_t sessions;
extern list_t virtual_slots;
extern list_t cards;
/* Framework definitions */
extern struct sc_pkcs11_framework_ops framework_pkcs15;
extern struct sc_pkcs11_framework_ops framework_pkcs15init;
void strcpy_bp(u8 *dst, const char *src, size_t dstsize);
CK_RV sc_to_cryptoki_error(int rc, int reader);
CK_RV sc_to_cryptoki_error(int rc);
void sc_pkcs11_print_attrs(const char *file, unsigned int line, const char *function,
const char *info, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount);
#define dump_template(info, pTemplate, ulCount) \
@ -357,25 +322,19 @@ void sc_pkcs11_print_attrs(const char *file, unsigned int line, const char *func
info, pTemplate, ulCount)
/* Slot and card handling functions */
CK_RV card_initialize(int reader);
CK_RV card_detect_all(void);
CK_RV __card_detect_all(int);
CK_RV card_detect(int reader);
CK_RV card_removed(int reader);
CK_RV slot_initialize(int id, struct sc_pkcs11_slot *);
CK_RV slot_get_slot(int id, struct sc_pkcs11_slot **);
CK_RV slot_get_token(int id, struct sc_pkcs11_slot **);
CK_RV slot_token_removed(int id);
CK_RV slot_find_changed(CK_SLOT_ID_PTR idp, int mask);
CK_RV card_removed(sc_reader_t *reader);
CK_RV card_detect_all();
CK_RV create_slot(sc_reader_t *reader);
CK_RV initialize_reader(sc_reader_t *reader);
CK_RV card_detect(sc_reader_t *reader);
CK_RV slot_get_slot(CK_SLOT_ID id, struct sc_pkcs11_slot **);
CK_RV slot_get_token(CK_SLOT_ID id, struct sc_pkcs11_slot **);
CK_RV slot_token_removed(CK_SLOT_ID id);
CK_RV slot_allocate(struct sc_pkcs11_slot **, struct sc_pkcs11_card *);
/* Pool */
CK_RV pool_initialize(struct sc_pkcs11_pool *, int);
CK_RV pool_insert(struct sc_pkcs11_pool *, void *, CK_ULONG_PTR);
CK_RV pool_find(struct sc_pkcs11_pool *, CK_ULONG, void **);
CK_RV pool_find_and_delete(struct sc_pkcs11_pool *, CK_ULONG, void **);
CK_RV slot_find_changed(CK_SLOT_ID_PTR idp, int mask);
/* Session manipulation */
CK_RV get_session(CK_SESSION_HANDLE hSession, struct sc_pkcs11_session ** session);
CK_RV session_start_operation(struct sc_pkcs11_session *,
int, sc_pkcs11_mechanism_type_t *,
struct sc_pkcs11_operation **);
@ -425,7 +384,7 @@ CK_RV sc_pkcs11_verif_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
CK_RV sc_pkcs11_decr_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_MECHANISM_TYPE);
CK_RV sc_pkcs11_decr(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR);
sc_pkcs11_mechanism_type_t *sc_pkcs11_find_mechanism(struct sc_pkcs11_card *,
CK_MECHANISM_TYPE, int);
CK_MECHANISM_TYPE, unsigned int);
sc_pkcs11_mechanism_type_t *sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE,
CK_MECHANISM_INFO_PTR, CK_KEY_TYPE,
void *);

View File

@ -1,7 +1,8 @@
/*
* slot.c: smart card and slot related management functions
* slot.c: reader, smart card and slot related management functions
*
* Copyright (C) 2002 Timo Teräs <timo.teras@iki.fi>
* Copyright (C) 2009 Martin Paljak <martin@paljak.pri.ee>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -19,6 +20,7 @@
*/
#include <string.h>
#include <stdlib.h>
#include "sc-pkcs11.h"
static struct sc_pkcs11_framework_ops *frameworks[] = {
@ -31,11 +33,23 @@ static struct sc_pkcs11_framework_ops *frameworks[] = {
NULL
};
unsigned int first_free_slot = 0;
static struct sc_pkcs11_slot * reader_get_slot(sc_reader_t *reader)
{
unsigned int i;
/* 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) {
return slot;
}
}
return NULL;
}
static void init_slot_info(CK_SLOT_INFO_PTR pInfo)
{
strcpy_bp(pInfo->slotDescription, "Virtual slot", 64);
strcpy_bp(pInfo->slotDescription, "Virtual hotplug slot", 64);
strcpy_bp(pInfo->manufacturerID, "OpenSC (www.opensc-project.org)", 32);
pInfo->flags = CKF_REMOVABLE_DEVICE | CKF_HW_SLOT;
pInfo->hardwareVersion.major = 0;
@ -44,99 +58,157 @@ static void init_slot_info(CK_SLOT_INFO_PTR pInfo)
pInfo->firmwareVersion.minor = 0;
}
CK_RV card_initialize(int reader)
/* simclist helpers to locate interesting objects by ID */
static int object_list_seeker(const void *el, const void *key)
{
const struct sc_pkcs11_object *object = (struct sc_pkcs11_object *)el;
if ((el == NULL) || (key == NULL))
return 0;
if (object->handle == *(CK_OBJECT_HANDLE*)key)
return 1;
return 0;
}
CK_RV create_slot(sc_reader_t *reader)
{
struct sc_pkcs11_slot *slot;
slot = (struct sc_pkcs11_slot *)calloc(1, sizeof(struct sc_pkcs11_slot));
if (!slot)
return CKR_HOST_MEMORY;
list_append(&virtual_slots, slot);
slot->login_user = -1;
slot->id = (CK_SLOT_ID) list_locate(&virtual_slots, slot);
sc_debug(context, "Creating slot with id 0x%lx", slot->id);
list_init(&slot->objects);
list_attributes_seeker(&slot->objects, object_list_seeker);
init_slot_info(&slot->slot_info);
if (reader != NULL) {
slot->reader = reader;
strcpy_bp(slot->slot_info.slotDescription, reader->name, 64);
}
return CKR_OK;
}
/* create slots associated with a reader, called whenever a reader is seen. */
CK_RV initialize_reader(sc_reader_t *reader)
{
struct sc_pkcs11_card *card = card_table + reader;
unsigned int avail;
unsigned int i;
CK_RV rv;
if (reader < 0 || reader >= SC_MAX_READERS)
return CKR_FUNCTION_FAILED;
memset(card, 0, sizeof(struct sc_pkcs11_card));
card->reader = reader;
/* Always allocate a fixed slot range to one reader/card.
* Some applications get confused if readers pop up in
* different slots. */
avail = sc_pkcs11_conf.slots_per_card;
if (first_free_slot + avail > sc_pkcs11_conf.max_virtual_slots)
avail = sc_pkcs11_conf.max_virtual_slots - first_free_slot;
card->first_slot = first_free_slot;
card->max_slots = avail;
card->num_slots = 0;
for (i = 0; i < card->max_slots; i++) {
struct sc_pkcs11_slot *slot = virtual_slots + card->first_slot + i;
slot->reader = reader;
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);
}
first_free_slot += card->max_slots;
return CKR_OK;
}
CK_RV card_detect(int reader)
CK_RV card_removed(sc_reader_t * reader)
{
struct sc_pkcs11_card *card = &card_table[reader];
int rc, rv, i, retry = 1;
unsigned int i;
struct sc_pkcs11_card *card = NULL;
/* Mark all slots as "token not present" */
sc_debug(context, "%s: card removed", reader->name);
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) {
/* Save the "card" object */
if (slot->card)
card = slot->card;
slot_token_removed(slot->id);
}
}
if (card) {
card->framework->unbind(card);
sc_disconnect_card(card->card);
free(card);
}
return CKR_OK;
}
CK_RV card_detect(sc_reader_t *reader)
{
struct sc_pkcs11_card *p11card;
int rc, rv;
unsigned int i;
rv = CKR_OK;
sc_debug(context, "%d: Detecting smart card\n", reader);
for (i = card->max_slots; i--; ) {
struct sc_pkcs11_slot *slot;
sc_reader_t *rdr = sc_ctx_get_reader(context, (unsigned int)reader);
if (rdr == NULL)
return CKR_TOKEN_NOT_PRESENT;
slot = virtual_slots + card->first_slot + i;
strcpy_bp(slot->slot_info.slotDescription, rdr->name, 64);
slot->reader = reader;
}
/* Check if someone inserted a card */
again: rc = sc_detect_card_presence(sc_ctx_get_reader(context, reader), 0);
sc_debug(context, "%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, "Card detection failed for reader %d: %s\n",
reader, sc_strerror(rc));
return sc_to_cryptoki_error(rc, reader);
sc_debug(context, "%s: failed, %s\n", reader->name, sc_strerror(rc));
return sc_to_cryptoki_error(rc);
}
if (rc == 0) {
sc_debug(context, "%d: Card absent\n", reader);
card_removed(reader); /* Release all resources */
sc_debug(context, "%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_SLOT_CARD_CHANGED) {
sc_debug(context, "%d: Card changed\n", reader);
if (rc & SC_READER_CARD_CHANGED) {
sc_debug(context, "%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. */
* So better be fussy.
if (!retry--)
return CKR_TOKEN_NOT_PRESENT;
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 (card->card == NULL) {
sc_debug(context, "%d: Connecting to smart card\n", reader);
rc = sc_connect_card(sc_ctx_get_reader(context, reader), 0, &card->card);
if (p11card == NULL) {
sc_debug(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;
p11card->reader = reader;
}
if (p11card->card == NULL) {
sc_debug(context, "%s: Connecting ... ", reader->name);
rc = sc_connect_card(reader, &p11card->card);
if (rc != SC_SUCCESS)
return sc_to_cryptoki_error(rc, reader);
return sc_to_cryptoki_error(rc);
}
/* Detect the framework */
if (card->framework == NULL) {
sc_debug(context, "%d: Detecting Framework\n", reader);
if (p11card->framework == NULL) {
sc_debug(context, "%s: Detecting Framework\n", reader->name);
for (i = 0; frameworks[i]; i++) {
if (frameworks[i]->bind == NULL)
continue;
rv = frameworks[i]->bind(card);
rv = frameworks[i]->bind(p11card);
if (rv == CKR_OK)
break;
}
@ -145,117 +217,64 @@ again: rc = sc_detect_card_presence(sc_ctx_get_reader(context, reader), 0);
return CKR_TOKEN_NOT_RECOGNIZED;
/* Initialize framework */
sc_debug(context, "%d: Detected framework %d. Creating tokens.\n", reader, i);
rv = frameworks[i]->create_tokens(card);
sc_debug(context, "%s: Detected framework %d. Creating tokens.\n", reader->name, i);
rv = frameworks[i]->create_tokens(p11card);
if (rv != CKR_OK)
return rv;
card->framework = frameworks[i];
p11card->framework = frameworks[i];
}
sc_debug(context, "%d: Detection ended\n", reader);
return rv;
}
CK_RV __card_detect_all(int report_events)
{
int i;
if (context == NULL_PTR)
return CKR_CRYPTOKI_NOT_INITIALIZED;
for (i = 0; i < (int)sc_ctx_get_reader_count(context); i++)
card_detect(i);
if (!report_events) {
CK_SLOT_ID id;
for (id = 0; id < sc_pkcs11_conf.max_virtual_slots; id++)
virtual_slots[id].events = 0;
}
sc_debug(context, "%s: Detection ended\n", reader->name);
return CKR_OK;
}
CK_RV card_detect_all(void)
{
return __card_detect_all(1);
CK_RV card_detect_all() {
unsigned int i;
/* Detect cards in all initialized readers */
for (i=0; i< sc_ctx_get_reader_count(context); i++) {
sc_reader_t *reader = sc_ctx_get_reader(context, i);
if (!reader_get_slot(reader))
initialize_reader(reader);
card_detect(sc_ctx_get_reader(context, i));
}
return CKR_OK;
}
CK_RV card_removed(int reader)
/* Allocates an existing slot to a card */
CK_RV slot_allocate(struct sc_pkcs11_slot ** slot, struct sc_pkcs11_card * card)
{
unsigned int i;
struct sc_pkcs11_card *card;
unsigned int i;
struct sc_pkcs11_slot *tmp_slot = NULL;
sc_debug(context, "%d: smart card removed\n", reader);
for (i=0; i<sc_pkcs11_conf.max_virtual_slots; i++) {
if (virtual_slots[i].card &&
virtual_slots[i].card->reader == reader)
slot_token_removed(i);
/* Locate a free slot for this reader */
for (i=0; i< list_size(&virtual_slots); i++) {
tmp_slot = (struct sc_pkcs11_slot *)list_get_at(&virtual_slots, i);
if (tmp_slot->reader == card->reader && tmp_slot->card == NULL)
break;
}
/* beware - do not clean the entire sc_pkcs11_card struct;
* fields such as first_slot and max_slots are initialized
* _once_ and need to be left untouched across card removal/
* insertion */
card = &card_table[reader];
if (card->framework)
card->framework->unbind(card);
card->framework = NULL;
card->fw_data = NULL;
if (card->card)
sc_disconnect_card(card->card, 0);
card->card = NULL;
return CKR_OK;
}
CK_RV slot_initialize(int id, struct sc_pkcs11_slot *slot)
{
memset(slot, 0, sizeof(*slot));
slot->id = id;
slot->login_user = -1;
init_slot_info(&slot->slot_info);
pool_initialize(&slot->object_pool, POOL_TYPE_OBJECT);
return CKR_OK;
}
CK_RV slot_allocate(struct sc_pkcs11_slot **slot, struct sc_pkcs11_card *card)
{
unsigned int i, first, last;
if (card->num_slots >= card->max_slots)
if (!tmp_slot)
return CKR_FUNCTION_FAILED;
first = card->first_slot;
last = first + card->max_slots;
for (i = first; i < last; i++) {
if (!virtual_slots[i].card) {
sc_debug(context, "Allocated slot %d\n", i);
virtual_slots[i].card = card;
virtual_slots[i].events = SC_EVENT_CARD_INSERTED;
*slot = &virtual_slots[i];
card->num_slots++;
return CKR_OK;
}
}
return CKR_FUNCTION_FAILED;
sc_debug(context, "Allocated slot 0x%lx for card in reader %s", tmp_slot->id,
card->reader->name);
tmp_slot->card = card;
tmp_slot->events = SC_EVENT_CARD_INSERTED;
*slot = tmp_slot;
return CKR_OK;
}
CK_RV slot_get_slot(int id, struct sc_pkcs11_slot **slot)
CK_RV slot_get_slot(CK_SLOT_ID id, struct sc_pkcs11_slot ** slot)
{
if (context == NULL)
return CKR_CRYPTOKI_NOT_INITIALIZED;
if (id < 0 || id >= sc_pkcs11_conf.max_virtual_slots)
*slot = list_seek(&virtual_slots, &id); // FIXME: check for null?
if (!*slot)
return CKR_SLOT_ID_INVALID;
*slot = &virtual_slots[id];
return CKR_OK;
}
CK_RV slot_get_token(int id, struct sc_pkcs11_slot **slot)
CK_RV slot_get_token(CK_SLOT_ID id, struct sc_pkcs11_slot ** slot)
{
int rv;
@ -263,29 +282,29 @@ CK_RV slot_get_token(int id, struct sc_pkcs11_slot **slot)
if (rv != CKR_OK)
return rv;
if (!((*slot)->slot_info.flags & CKF_TOKEN_PRESENT))
{
rv = card_detect((*slot)->reader);
if (!((*slot)->slot_info.flags & CKF_TOKEN_PRESENT)) {
if ((*slot)->reader == NULL)
return CKR_TOKEN_NOT_PRESENT;
rv = card_detect((*slot)->reader);
if (rv != CKR_OK)
return CKR_TOKEN_NOT_PRESENT;
return rv;
}
if (!((*slot)->slot_info.flags & CKF_TOKEN_PRESENT))
{
if (!((*slot)->slot_info.flags & CKF_TOKEN_PRESENT)) {
sc_debug(context, "card detected, but slot not presenting token");
return CKR_TOKEN_NOT_PRESENT;
}
return CKR_OK;
}
CK_RV slot_token_removed(int id)
CK_RV slot_token_removed(CK_SLOT_ID id)
{
int rv, token_was_present;
unsigned int i;
struct sc_pkcs11_slot *slot;
struct sc_pkcs11_object *object;
CK_SLOT_INFO saved_slot_info;
int reader;
sc_debug(context, "slot_token_removed(0x%lx)", id);
rv = slot_get_slot(id, &slot);
if (rv != CKR_OK)
return rv;
@ -295,31 +314,24 @@ CK_RV slot_token_removed(int id)
/* Terminate active sessions */
sc_pkcs11_close_all_sessions(id);
/* Object pool */
while (pool_find_and_delete(&slot->object_pool, 0, (void**) &object) == CKR_OK) {
for (i=0; i<list_size(&slot->objects); i++) {
object = (struct sc_pkcs11_object *)list_get_at(&slot->objects, i);
if (object->ops->release)
object->ops->release(object);
}
list_delete(&slot->objects, object);
}
/* Release framework stuff */
if (slot->card != NULL) {
if (slot->fw_data != NULL &&
slot->card->framework != NULL &&
slot->card->framework->release_token != NULL)
slot->card->framework != NULL && slot->card->framework->release_token != NULL)
slot->card->framework->release_token(slot->card, slot->fw_data);
slot->card->num_slots--;
}
/* Zap everything else. Restore the slot_info afterwards (it contains the reader
* name, for instance) but clear its flags */
saved_slot_info = slot->slot_info;
reader = slot->reader;
memset(slot, 0, sizeof(*slot));
slot->slot_info = saved_slot_info;
slot->slot_info.flags = 0;
/* Reset relevant slot properties */
slot->slot_info.flags &= ~CKF_TOKEN_PRESENT;
slot->login_user = -1;
slot->reader = reader;
pool_initialize(&slot->object_pool, POOL_TYPE_OBJECT);
slot->card = NULL;
if (token_was_present)
slot->events = SC_EVENT_CARD_REMOVED;
@ -327,22 +339,28 @@ CK_RV slot_token_removed(int id)
return CKR_OK;
}
/* Called from C_WaitForSlotEvent */
CK_RV slot_find_changed(CK_SLOT_ID_PTR idp, int mask)
{
sc_pkcs11_slot_t *slot;
CK_SLOT_ID id;
unsigned int i;
SC_FUNC_CALLED(context, 3);
card_detect_all();
for (id = 0; id < sc_pkcs11_conf.max_virtual_slots; id++) {
slot = &virtual_slots[id];
for (i=0; i<list_size(&virtual_slots); i++) {
sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
sc_debug(context, "slot 0x%lx token: %d events: 0x%02X",slot->id, (slot->slot_info.flags & CKF_TOKEN_PRESENT), slot->events);
if ((slot->events & SC_EVENT_CARD_INSERTED)
&& !(slot->slot_info.flags & CKF_TOKEN_PRESENT))
&& !(slot->slot_info.flags & CKF_TOKEN_PRESENT)) {
/* If a token has not been initialized, clear the inserted event */
slot->events &= ~SC_EVENT_CARD_INSERTED;
}
sc_debug(context, "mask: 0x%02X events: 0x%02X result: %d", mask, slot->events, (slot->events & mask));
if (slot->events & mask) {
slot->events &= ~mask;
*idp = id;
return CKR_OK;
*idp = slot->id;
SC_FUNC_RETURN(context, 3, CKR_OK);
}
}
return CKR_NO_EVENT;
SC_FUNC_RETURN(context, 3, CKR_NO_EVENT);
}