Exemplo n.º 1
0
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, event in 0x%lx", lookup_enum (RV_T, rv), *pSlot);
	sc_pkcs11_unlock();
	return rv;
}
CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,   /* the session's handle */
			CK_ATTRIBUTE_PTR  pTemplate,  /* attribute values to match */
			CK_ULONG          ulCount)    /* attributes in search template */
{
	CK_BBOOL is_private = TRUE;
	CK_ATTRIBUTE private_attribute = { CKA_PRIVATE, &is_private, sizeof(is_private) };

	int rv, match, hide_private;
	unsigned int j;
	struct sc_pkcs11_session *session;
	struct sc_pkcs11_object *object;
	struct sc_pkcs11_find_operation *operation;
	struct sc_pkcs11_pool_item *item;
	struct sc_pkcs11_slot *slot;

	rv = sc_pkcs11_lock();
	if (rv != CKR_OK)
		return rv;

	rv = pool_find(&session_pool, hSession, (void**) &session);
	if (rv != CKR_OK)
		goto out;

	sc_debug(context, "C_FindObjectsInit(slot = %d)\n", session->slot->id);
	dump_template("C_FindObjectsInit()", pTemplate, ulCount);

	rv = session_start_operation(session, SC_PKCS11_OPERATION_FIND,
                                     &find_mechanism,
				     (struct sc_pkcs11_operation**) &operation);
	if (rv != CKR_OK)
		goto out;

	operation->current_handle = 0;
	operation->num_handles = 0;
	slot = session->slot;

	/* Check whether we should hide private objects */
	hide_private = 0;
	if (slot->login_user != CKU_USER
	 && (slot->token_info.flags & CKF_LOGIN_REQUIRED))
		hide_private = 1;

	/* For each object in token do */
	for (item = slot->object_pool.head; item != NULL; item = item->next) {
		object = (struct sc_pkcs11_object*) item->item;

		/* User not logged in and private object? */
		if (hide_private) {
			if (object->ops->get_attribute(session, object, &private_attribute) != CKR_OK)
				continue;
			if (is_private) {
				sc_debug(context, "Object %d/%d: Private object and not logged in.\n",
					slot->id,
					item->handle);
				continue;
			}
		}

		/* Try to match every attribute */
		match = 1;
		for (j = 0; j < ulCount; j++) {
			rv = object->ops->cmp_attribute(session, object,
					&pTemplate[j]);
			if (rv == 0) {
				if (context->debug >= 4) {
					sc_debug(context, "Object %d/%d: Attribute 0x%x does NOT match.\n",
					      slot->id,
					      item->handle, pTemplate[j].type);
				}
				match = 0;
				break;
			}

			if (context->debug >= 4) {
				sc_debug(context, "Object %d/%d: Attribute 0x%x matches.\n",
				      slot->id,
				      item->handle, pTemplate[j].type);
			}
		}

		if (match) {
			sc_debug(context, "Object %d/%d matches\n",
			      slot->id, item->handle);
			/* Avoid buffer overflow --okir */
			if (operation->num_handles >= SC_PKCS11_FIND_MAX_HANDLES) {
				sc_debug(context, "Too many matching objects\n");
				break;
			}
			operation->handles[operation->num_handles++] = item->handle;
		}
	}
	rv = CKR_OK;

	sc_debug(context, "%d matching objects\n", operation->num_handles);

out:	sc_pkcs11_unlock();
	return rv;
}
Exemplo n.º 3
0
CK_RV C_GetSlotList(CK_BBOOL       tokenPresent,  /* only slots with token present */
		    CK_SLOT_ID_PTR pSlotList,     /* receives the array of slot IDs */
		    CK_ULONG_PTR   pulCount)      /* receives the number of slots */
{
	CK_SLOT_ID_PTR found = NULL;
	unsigned int i;
	CK_ULONG numMatches;
	sc_pkcs11_slot_t *slot;
	sc_reader_t *prev_reader = NULL;
	CK_RV rv;

	if (pulCount == NULL_PTR)
		return CKR_ARGUMENTS_BAD;

	if ((rv = sc_pkcs11_lock()) != CKR_OK) {
		return rv;
	}

	sc_log(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) {
		/* 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();

	found = calloc(list_size(&virtual_slots), sizeof(CK_SLOT_ID));

	if (found == NULL) {
		rv = CKR_HOST_MEMORY;
		goto out;
	}

	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);
		/* the list of available slots contains:
		 * - if present, virtual hotplug slot;
		 * - any slot with token;
		 * - without token(s), one empty slot per reader;
		 */
	        if ((!tokenPresent && !slot->reader)
				|| (!tokenPresent && slot->reader != prev_reader)
				|| (slot->slot_info.flags & CKF_TOKEN_PRESENT))
			found[numMatches++] = slot->id;
		prev_reader = slot->reader;
	}

	if (pSlotList == NULL_PTR) {
		sc_log(context, "was only a size inquiry (%d)\n", numMatches);
		*pulCount = numMatches;
		rv = CKR_OK;
		goto out;
	}

	if (*pulCount < numMatches) {
		sc_log(context, "buffer was too small (needed %d)\n", numMatches);
		*pulCount = numMatches;
		rv = CKR_BUFFER_TOO_SMALL;
		goto out;
	}

	memcpy(pSlotList, found, numMatches * sizeof(CK_SLOT_ID));
	*pulCount = numMatches;
	rv = CKR_OK;

	sc_log(context, "returned %d slots\n", numMatches);

out:
	if (found != NULL) {
		free (found);
		found = NULL;
	}
	sc_pkcs11_unlock();
	return rv;
}
CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession,   /* the session's handle */
			  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
			  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attributes, gets values */
			  CK_ULONG          ulCount)    /* attributes in template */
{
	static int precedence[] = {
		CKR_OK,
		CKR_BUFFER_TOO_SMALL,
		CKR_ATTRIBUTE_TYPE_INVALID,
		CKR_ATTRIBUTE_SENSITIVE,
		-1
	};
	char	object_name[64];
	int     j, rv;
	struct sc_pkcs11_session *session;
	struct sc_pkcs11_object *object;
	int	res, res_type;
	unsigned int i;

	rv = sc_pkcs11_lock();
	if (rv != CKR_OK)
		return rv;

	rv = pool_find(&session_pool, hSession, (void**) &session);
	if (rv != CKR_OK)
		goto out;

	rv = pool_find(&session->slot->object_pool, hObject, (void**) &object);
	if (rv != CKR_OK)
		goto out;

	/* Debug printf */
	snprintf(object_name, sizeof(object_name), "Object %lu",
			(unsigned long) hObject);

	res_type = 0;
	for (i = 0; i < ulCount; i++) {
		res = object->ops->get_attribute(session,
					object, &pTemplate[i]);
		if (res != CKR_OK)
			pTemplate[i].ulValueLen = (CK_ULONG) -1;

		dump_template(object_name, &pTemplate[i], 1);

		/* the pkcs11 spec has complicated rules on
		 * what errors take precedence:
		 * 	CKR_ATTRIBUTE_SENSITIVE
		 * 	CKR_ATTRIBUTE_INVALID
		 * 	CKR_BUFFER_TOO_SMALL
		 * It does not exactly specify how other errors
		 * should be handled - we give them highest
		 * precedence
		 */
		for (j = 0; precedence[j] != -1; j++) {
			if (precedence[j] == res)
				break;
		}
		if (j > res_type) {
			res_type = j;
			rv = res;
		}
	}

out:	sc_pkcs11_unlock();
	return rv;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
CK_RV
C_FindObjectsInit(CK_SESSION_HANDLE hSession,	/* the session's handle */
		CK_ATTRIBUTE_PTR pTemplate,	/* attribute values to match */
		CK_ULONG ulCount)		/* attributes in search template */
{
	CK_RV rv;
	CK_BBOOL is_private = TRUE;
	CK_ATTRIBUTE private_attribute = { CKA_PRIVATE, &is_private, sizeof(is_private) };
	int match, hide_private;
	unsigned int i, j;
	struct sc_pkcs11_session *session;
	struct sc_pkcs11_object *object;
	struct sc_pkcs11_find_operation *operation;
	struct sc_pkcs11_slot *slot;

	if (pTemplate == NULL_PTR && ulCount > 0)
		return CKR_ARGUMENTS_BAD;

	rv = sc_pkcs11_lock();
	if (rv != CKR_OK)
		return rv;

	rv = get_session(hSession, &session);
	if (rv != CKR_OK)
		goto out;

	sc_log(context, "C_FindObjectsInit(slot = %d)\n", session->slot->id);
	dump_template(SC_LOG_DEBUG_NORMAL, "C_FindObjectsInit()", pTemplate, ulCount);

	rv = session_start_operation(session, SC_PKCS11_OPERATION_FIND,
				     &find_mechanism, (struct sc_pkcs11_operation **)&operation);
	if (rv != CKR_OK)
		goto out;

	operation->current_handle = 0;
	operation->num_handles = 0;
	operation->allocated_handles = 0;
	operation->handles = NULL;
	slot = session->slot;

	/* Check whether we should hide private objects */
	hide_private = 0;
	if (slot->login_user != CKU_USER && (slot->token_info.flags & CKF_LOGIN_REQUIRED))
		hide_private = 1;

	/* For each object in token do */
	for (i=0; i<list_size(&slot->objects); i++) {
		object = (struct sc_pkcs11_object *)list_get_at(&slot->objects, i);
		sc_log(context, "Object with handle 0x%lx", object->handle);

		/* User not logged in and private object? */
		if (hide_private) {
			if (object->ops->get_attribute(session, object, &private_attribute) != CKR_OK)
			        continue;
			if (is_private) {
				sc_log(context, "Object %d/%d: Private object and not logged in.",
					 slot->id, object->handle);
				continue;
			}
		}

		/* Try to match every attribute */
		match = 1;
		for (j = 0; j < ulCount; j++) {
			rv = object->ops->cmp_attribute(session, object, &pTemplate[j]);
			if (rv == 0) {
				sc_log(context, "Object %d/%d: Attribute 0x%x does NOT match.",
					 slot->id, object->handle, pTemplate[j].type);
				match = 0;
				break;
			}

			if (context->debug >= 4) {
				sc_log(context, "Object %d/%d: Attribute 0x%x matches.",
					 slot->id, object->handle, pTemplate[j].type);
			}
		}

		if (match) {
			sc_log(context, "Object %d/%d matches\n", slot->id, object->handle);
			/* Realloc handles - remove restriction on only 32 matching objects -dee */
			if (operation->num_handles >= operation->allocated_handles) {
				operation->allocated_handles += SC_PKCS11_FIND_INC_HANDLES;
				sc_log(context, "realloc for %d handles", operation->allocated_handles);
				operation->handles = realloc(operation->handles,
					sizeof(CK_OBJECT_HANDLE) * operation->allocated_handles);
				if (operation->handles == NULL) {
					rv = CKR_HOST_MEMORY;
					goto out;
				}
			}
			operation->handles[operation->num_handles++] = object->handle;
		}
	}
	rv = CKR_OK;

	sc_log(context, "%d matching objects\n", operation->num_handles);

out:
	sc_pkcs11_unlock();
	return rv;
}
Exemplo n.º 7
0
CK_RV
C_GetAttributeValue(CK_SESSION_HANDLE hSession,	/* the session's handle */
		CK_OBJECT_HANDLE hObject,	/* the object's handle */
		CK_ATTRIBUTE_PTR pTemplate,	/* specifies attributes, gets values */
		CK_ULONG ulCount)		/* attributes in template */
{
	static int precedence[] = {
		CKR_OK,
		CKR_BUFFER_TOO_SMALL,
		CKR_ATTRIBUTE_TYPE_INVALID,
		CKR_ATTRIBUTE_SENSITIVE,
		-1
	};
	char object_name[64];
	int j;
	CK_RV rv;
	struct sc_pkcs11_session *session;
	struct sc_pkcs11_object *object;
	int res, res_type;
	unsigned int i;

	if (pTemplate == NULL_PTR || ulCount == 0)
		return CKR_ARGUMENTS_BAD;

	rv = sc_pkcs11_lock();
	if (rv != CKR_OK)
		return rv;

	rv = get_object_from_session(hSession, hObject, &session, &object);
	if (rv != CKR_OK)
		goto out;

	/* Debug printf */
	snprintf(object_name, sizeof(object_name), "Object %lu", (unsigned long)hObject);

	res_type = 0;
	for (i = 0; i < ulCount; i++) {
		res = object->ops->get_attribute(session, object, &pTemplate[i]);
		if (res != CKR_OK)
			pTemplate[i].ulValueLen = (CK_ULONG) - 1;

		dump_template(SC_LOG_DEBUG_NORMAL, object_name, &pTemplate[i], 1);

		/* the pkcs11 spec has complicated rules on
		 * what errors take precedence:
		 *      CKR_ATTRIBUTE_SENSITIVE
		 *      CKR_ATTRIBUTE_INVALID
		 *      CKR_BUFFER_TOO_SMALL
		 * It does not exactly specify how other errors
		 * should be handled - we give them highest
		 * precedence
		 */
		for (j = 0; precedence[j] != -1; j++) {
			if (precedence[j] == res)
				break;
		}
		if (j > res_type) {
			res_type = j;
			rv = res;
		}
	}

out:	sc_log(context, "C_GetAttributeValue(hSession=0x%lx, hObject=0x%lx) = %s",
			hSession, hObject, lookup_enum ( RV_T, rv ));
	sc_pkcs11_unlock();
	return rv;
}
Exemplo n.º 8
0
CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession,	/* the session's handle */
		  CK_MECHANISM_PTR pMechanism,	/* the key derivation mechanism */
		  CK_OBJECT_HANDLE hBaseKey,	/* handle of the base key */
		  CK_ATTRIBUTE_PTR pTemplate,	/* template for the new key */
		  CK_ULONG ulAttributeCount,	/* # of attributes in template */
		  CK_OBJECT_HANDLE_PTR phKey)	/* gets handle of derived key */
{
/* TODO: -DEE ECDH with Cofactor  on PIV is an example */
/* TODO: need to do a lot of checking, will only support ECDH for now.*/
	CK_RV rv;
	CK_BBOOL can_derive;
	CK_KEY_TYPE key_type;
	CK_ATTRIBUTE derive_attribute = { CKA_DERIVE, &can_derive, sizeof(can_derive) };
	CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
	struct sc_pkcs11_session *session;
	struct sc_pkcs11_object *object;
	struct sc_pkcs11_object *key_object;

	if (pMechanism == NULL_PTR)
		return CKR_ARGUMENTS_BAD;

	rv = sc_pkcs11_lock();
	if (rv != CKR_OK)
		return rv;

	rv = get_object_from_session(hSession, hBaseKey, &session, &object);
	if (rv != CKR_OK) {
		if (rv == CKR_OBJECT_HANDLE_INVALID)
			rv = CKR_KEY_HANDLE_INVALID;
		goto out;
	}

	if (object->ops->derive == NULL_PTR) {
		rv = CKR_KEY_TYPE_INCONSISTENT;
		goto out;
	}

	rv = object->ops->get_attribute(session, object, &derive_attribute);
	if (rv != CKR_OK || !can_derive) {
		rv = CKR_KEY_TYPE_INCONSISTENT;
		goto out;
	}
	rv = object->ops->get_attribute(session, object, &key_type_attr);
	if (rv != CKR_OK) {
		rv = CKR_KEY_TYPE_INCONSISTENT;
		goto out;
	}
	/* TODO DEE Should also check SENSITIVE, ALWAYS_SENSITIVE, EXTRACTABLE,
	   NEVER_EXTRACTABLE of the BaseKey against the template for the newkey.
	*/

	switch(key_type) {
	    case CKK_EC:

		rv = sc_create_object_int(hSession, pTemplate, ulAttributeCount, phKey, 0);
		if (rv != CKR_OK)
		    goto out;

		rv = get_object_from_session(hSession, *phKey, &session, &key_object);
		if (rv != CKR_OK) {
			if (rv == CKR_OBJECT_HANDLE_INVALID)
				rv = CKR_KEY_HANDLE_INVALID;
			goto out;
		}

		rv = sc_pkcs11_deri(session, pMechanism, object, key_type,
			hSession, *phKey, key_object);
		/* TODO if (rv != CK_OK) need to destroy the object */

		break;
	    default:
		rv = CKR_KEY_TYPE_INCONSISTENT;
	}

out:
	sc_pkcs11_unlock();
	return rv;
}