pkcs11: don't shrink the number of slots
... as required by PKCS#11 2.30, if the application doesn't call `C_GetSlotList` with `NULL`. Fixes ghost tokens in Firefox when detaching a reader that contained a card. Fixes https://github.com/OpenSC/OpenSC/issues/629
This commit is contained in:
parent
7e6dc25c40
commit
24b7507a69
|
@ -486,6 +486,9 @@ CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (slot->p11card == NULL)
|
||||
return CKR_TOKEN_NOT_PRESENT;
|
||||
|
||||
fw_data = (struct pkcs15_fw_data *) slot->p11card->fws_data[slot->fw_data_idx];
|
||||
if (!fw_data)
|
||||
return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetTokenInfo");
|
||||
|
|
|
@ -405,16 +405,20 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese
|
|||
prev_reader = NULL;
|
||||
numMatches = 0;
|
||||
for (i=0; i<list_size(&virtual_slots); i++) {
|
||||
slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
|
||||
slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
|
||||
/* the list of available slots contains:
|
||||
* - if present, virtual hotplug slot;
|
||||
* - any slot with token;
|
||||
* - without token(s), one empty slot per reader;
|
||||
* - any slot that has already been seen;
|
||||
*/
|
||||
if ((!tokenPresent && !slot->reader)
|
||||
if ((!tokenPresent && !slot->reader)
|
||||
|| (!tokenPresent && slot->reader != prev_reader)
|
||||
|| (slot->slot_info.flags & CKF_TOKEN_PRESENT))
|
||||
|| (slot->slot_info.flags & CKF_TOKEN_PRESENT)
|
||||
|| (slot->flags & SC_PKCS11_SLOT_FLAG_SEEN)) {
|
||||
found[numMatches++] = slot->id;
|
||||
slot->flags |= SC_PKCS11_SLOT_FLAG_SEEN;
|
||||
}
|
||||
prev_reader = slot->reader;
|
||||
}
|
||||
|
||||
|
|
|
@ -205,6 +205,12 @@ struct sc_pkcs11_card {
|
|||
unsigned int nmechanisms;
|
||||
};
|
||||
|
||||
/* If the slot did already show with `C_GetSlotList`, then we need to keep this
|
||||
* slot alive. PKCS#11 2.30 allows allows adding but not removing slots until
|
||||
* the application calls `C_GetSlotList` with `NULL`. This flag tracks the
|
||||
* visibility to the application */
|
||||
#define SC_PKCS11_SLOT_FLAG_SEEN 1
|
||||
|
||||
struct sc_pkcs11_slot {
|
||||
CK_SLOT_ID id; /* ID of the slot */
|
||||
int login_user; /* Currently logged in user */
|
||||
|
@ -221,6 +227,7 @@ struct sc_pkcs11_slot {
|
|||
int fw_data_idx; /* Index of framework data */
|
||||
struct sc_app_info *app_info; /* Application assosiated to slot */
|
||||
list_t logins; /* tracks all calls to C_Login if atomic operations are requested */
|
||||
int flags;
|
||||
};
|
||||
typedef struct sc_pkcs11_slot sc_pkcs11_slot_t;
|
||||
|
||||
|
|
|
@ -75,26 +75,39 @@ static int object_list_seeker(const void *el, const void *key)
|
|||
|
||||
CK_RV create_slot(sc_reader_t *reader)
|
||||
{
|
||||
struct sc_pkcs11_slot *slot;
|
||||
/* find unused virtual hotplug slots */
|
||||
struct sc_pkcs11_slot *slot = reader_get_slot(NULL);
|
||||
|
||||
if (list_size(&virtual_slots) >= sc_pkcs11_conf.max_virtual_slots)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
/* create a new slot if no empty slot is available */
|
||||
if (!slot) {
|
||||
if (list_size(&virtual_slots) >= sc_pkcs11_conf.max_virtual_slots)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
slot = (struct sc_pkcs11_slot *)calloc(1, sizeof(struct sc_pkcs11_slot));
|
||||
if (!slot)
|
||||
return CKR_HOST_MEMORY;
|
||||
slot = (struct sc_pkcs11_slot *)calloc(1, sizeof(struct sc_pkcs11_slot));
|
||||
if (!slot)
|
||||
return CKR_HOST_MEMORY;
|
||||
|
||||
list_append(&virtual_slots, slot);
|
||||
list_init(&slot->objects);
|
||||
list_attributes_seeker(&slot->objects, object_list_seeker);
|
||||
|
||||
list_init(&slot->logins);
|
||||
} else {
|
||||
/* reuse the old list of logins/objects since they should be empty */
|
||||
list_t logins = slot->logins;
|
||||
list_t objects = slot->objects;
|
||||
|
||||
memset(slot, 0, sizeof *slot);
|
||||
|
||||
slot->logins = logins;
|
||||
slot->objects = objects;
|
||||
}
|
||||
|
||||
list_append(&virtual_slots, slot);
|
||||
slot->login_user = -1;
|
||||
slot->id = (CK_SLOT_ID) list_locate(&virtual_slots, slot);
|
||||
sc_log(context, "Creating slot with id 0x%lx", slot->id);
|
||||
|
||||
list_init(&slot->objects);
|
||||
list_attributes_seeker(&slot->objects, object_list_seeker);
|
||||
|
||||
list_init(&slot->logins);
|
||||
|
||||
init_slot_info(&slot->slot_info);
|
||||
sc_log(context, "Initializing slot with id 0x%lx", slot->id);
|
||||
|
||||
if (reader != NULL) {
|
||||
slot->reader = reader;
|
||||
strcpy_bp(slot->slot_info.manufacturerID, reader->vendor, 32);
|
||||
|
@ -106,13 +119,21 @@ CK_RV create_slot(sc_reader_t *reader)
|
|||
return CKR_OK;
|
||||
}
|
||||
|
||||
void delete_slot(struct sc_pkcs11_slot *slot)
|
||||
void empty_slot(struct sc_pkcs11_slot *slot)
|
||||
{
|
||||
if (slot) {
|
||||
list_destroy(&slot->objects);
|
||||
list_destroy(&slot->logins);
|
||||
list_delete(&virtual_slots, slot);
|
||||
free(slot);
|
||||
if (slot->flags & SC_PKCS11_SLOT_FLAG_SEEN) {
|
||||
/* Keep the slot visible to the application. The slot's state has
|
||||
* already been reset by `slot_token_removed()`, lists have been
|
||||
* emptied. We replace the reader with a virtual hotplug slot. */
|
||||
slot->reader = NULL;
|
||||
init_slot_info(&slot->slot_info);
|
||||
} else {
|
||||
list_destroy(&slot->objects);
|
||||
list_destroy(&slot->logins);
|
||||
list_delete(&virtual_slots, slot);
|
||||
free(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,7 +364,7 @@ card_detect_all(void)
|
|||
struct sc_pkcs11_slot *slot;
|
||||
card_removed(reader);
|
||||
while ((slot = reader_get_slot(reader))) {
|
||||
delete_slot(slot);
|
||||
empty_slot(slot);
|
||||
}
|
||||
_sc_delete_reader(context, reader);
|
||||
i--;
|
||||
|
@ -444,17 +465,19 @@ CK_RV slot_token_removed(CK_SLOT_ID id)
|
|||
slot->p11card->framework->release_token(slot->p11card, slot->fw_data);
|
||||
slot->fw_data = NULL;
|
||||
}
|
||||
slot->p11card = NULL;
|
||||
}
|
||||
|
||||
/* Reset relevant slot properties */
|
||||
slot->slot_info.flags &= ~CKF_TOKEN_PRESENT;
|
||||
slot->login_user = -1;
|
||||
pop_all_login_states(slot);
|
||||
slot->p11card = NULL;
|
||||
|
||||
if (token_was_present)
|
||||
slot->events = SC_EVENT_CARD_REMOVED;
|
||||
|
||||
memset(&slot->token_info, 0, sizeof slot->token_info);
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue