[pkg-opensc-commit] [opensc] 150/295: pkcs11: don't shrink the number of slots

Eric Dorland eric at moszumanska.debian.org
Sat Jun 24 21:11:26 UTC 2017


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to branch master
in repository opensc.

commit 24b7507a69704f69e371834953cf78cffec104b0
Author: Frank Morgner <frankmorgner at gmail.com>
Date:   Sat Sep 3 00:46:48 2016 +0200

    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
---
 src/pkcs11/framework-pkcs15.c |  3 +++
 src/pkcs11/pkcs11-global.c    | 10 ++++---
 src/pkcs11/sc-pkcs11.h        |  7 +++++
 src/pkcs11/slot.c             | 63 +++++++++++++++++++++++++++++--------------
 4 files changed, 60 insertions(+), 23 deletions(-)

diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c
index c5c8a1a..0c0af88 100644
--- a/src/pkcs11/framework-pkcs15.c
+++ b/src/pkcs11/framework-pkcs15.c
@@ -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");
diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c
index 11a49ac..9fd0f09 100644
--- a/src/pkcs11/pkcs11-global.c
+++ b/src/pkcs11/pkcs11-global.c
@@ -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;
 	}
 
diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h
index ab05ba6..5b51234 100644
--- a/src/pkcs11/sc-pkcs11.h
+++ b/src/pkcs11/sc-pkcs11.h
@@ -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;
 
diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c
index 45be6d4..ba5e4f4 100644
--- a/src/pkcs11/slot.c
+++ b/src/pkcs11/slot.c
@@ -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);
-	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_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;
 
-	list_init(&slot->objects);
-	list_attributes_seeker(&slot->objects, object_list_seeker);
+		memset(slot, 0, sizeof *slot);
 
-	list_init(&slot->logins);
+		slot->logins = logins;
+		slot->objects = objects;
+	}
 
+	slot->login_user = -1;
+	slot->id = (CK_SLOT_ID) list_locate(&virtual_slots, slot);
 	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;
 }
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/opensc.git



More information about the pkg-opensc-commit mailing list