From cf6037314fd73df23e9582269086bf9b97f03c82 Mon Sep 17 00:00:00 2001 From: okir Date: Mon, 17 Feb 2003 14:21:38 +0000 Subject: [PATCH] - Introduce locks around all pkcs11 operations, in case the caller is multithreaded and wants to access us from different threads. git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@912 c6295689-39f2-0310-b995-f0e70906c6a9 --- src/pkcs11/pkcs11-global.c | 213 +++++++++++++++++++++++------- src/pkcs11/pkcs11-object.c | 252 ++++++++++++++++++++++-------------- src/pkcs11/pkcs11-session.c | 122 ++++++++++++----- src/pkcs11/sc-pkcs11.h | 7 + src/pkcs11/slot.c | 2 +- 5 files changed, 421 insertions(+), 175 deletions(-) diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index f4ecfc2b..41bd1e91 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -32,15 +32,17 @@ extern CK_FUNCTION_LIST pkcs11_function_list; CK_RV C_Initialize(CK_VOID_PTR pReserved) { - int i, rc; + int i, rc, rv; if (context != NULL) { error(context, "C_Initialize(): Cryptoki already initialized\n"); return CKR_CRYPTOKI_ALREADY_INITIALIZED; } rc = sc_establish_context(&context, "opensc-pkcs11"); - if (rc != 0) - return CKR_DEVICE_ERROR; + if (rc != 0) { + rv = CKR_DEVICE_ERROR; + goto out; + } /* Load configuration */ load_pkcs11_parameters(&sc_pkcs11_conf, context); @@ -55,25 +57,34 @@ CK_RV C_Initialize(CK_VOID_PTR pReserved) /* Detect any card, but do not flag "insert" events */ __card_detect_all(0); - debug(context, "Cryptoki initialized\n"); - return CKR_OK; + rv = sc_pkcs11_init_lock((CK_C_INITIALIZE_ARGS_PTR) pReserved); + +out: debug(context, "C_Initialize: result = %d\n", rv); + return rv; } CK_RV C_Finalize(CK_VOID_PTR pReserved) { int i; + sc_pkcs11_lock(); + debug(context, "Shutting down Cryptoki\n"); for (i=0; ireader_count; i++) card_removed(i); sc_release_context(context); context = NULL; + sc_pkcs11_unlock(); + sc_pkcs11_free_lock(); + return CKR_OK; } CK_RV C_GetInfo(CK_INFO_PTR pInfo) { + sc_pkcs11_lock(); + debug(context, "Cryptoki info query\n"); memset(pInfo, 0, sizeof(CK_INFO)); @@ -88,6 +99,7 @@ CK_RV C_GetInfo(CK_INFO_PTR pInfo) pInfo->libraryVersion.major = 0; pInfo->libraryVersion.minor = 2; + sc_pkcs11_unlock(); return CKR_OK; } @@ -104,6 +116,9 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese CK_SLOT_ID found[SC_PKCS11_MAX_VIRTUAL_SLOTS]; int numMatches, i; sc_pkcs11_slot_t *slot; + CK_RV rv; + + sc_pkcs11_lock(); debug(context, "Getting slot listing\n"); card_detect_all(); @@ -119,20 +134,25 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese if (pSlotList == NULL_PTR) { debug(context, "was only a size inquiry (%d)\n", numMatches); *pulCount = numMatches; - return CKR_OK; + rv = CKR_OK; + goto out; } if (*pulCount < numMatches) { debug(context, "buffer was too small (needed %d)\n", numMatches); *pulCount = numMatches; - return CKR_BUFFER_TOO_SMALL; + rv = CKR_BUFFER_TOO_SMALL; + goto out; } memcpy(pSlotList, found, numMatches * sizeof(CK_SLOT_ID)); *pulCount = numMatches; + rv = CKR_OK; debug(context, "returned %d slots\n", numMatches); - return CKR_OK; + +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) @@ -140,19 +160,19 @@ CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) struct sc_pkcs11_slot *slot; CK_RV rv; - rv = slot_get_slot(slotID, &slot); - if (rv != CKR_OK) - return rv; - - if (!slot->card) { - rv = card_detect_all(); - if (rv != CKR_OK) - return rv; - } + sc_pkcs11_lock(); debug(context, "Getting info about slot %d\n", slotID); - memcpy(pInfo, &slot->slot_info, sizeof(CK_SLOT_INFO)); - return CKR_OK; + + rv = slot_get_slot(slotID, &slot); + if (rv == CKR_OK && !slot->card) + rv = card_detect_all(); + + if (rv == CKR_OK) + memcpy(pInfo, &slot->slot_info, sizeof(CK_SLOT_INFO)); + + sc_pkcs11_unlock(); + return rv; } CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) @@ -160,13 +180,16 @@ CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) struct sc_pkcs11_slot *slot; CK_RV rv; - rv = slot_get_token(slotID, &slot); - if (rv != CKR_OK) - return rv; + sc_pkcs11_lock(); debug(context, "Getting info about token in slot %d\n", slotID); - memcpy(pInfo, &slot->token_info, sizeof(CK_TOKEN_INFO)); - return CKR_OK; + + rv = slot_get_token(slotID, &slot); + if (rv == CKR_OK) + memcpy(pInfo, &slot->token_info, sizeof(CK_TOKEN_INFO)); + + sc_pkcs11_unlock(); + return rv; } CK_RV C_GetMechanismList(CK_SLOT_ID slotID, @@ -176,11 +199,14 @@ CK_RV C_GetMechanismList(CK_SLOT_ID slotID, struct sc_pkcs11_slot *slot; CK_RV rv; - rv = slot_get_token(slotID, &slot); - if (rv != CKR_OK) - return rv; + sc_pkcs11_lock(); - return sc_pkcs11_get_mechanism_list(slot->card, pMechanismList, pulCount); + rv = slot_get_token(slotID, &slot); + if (rv == CKR_OK) + rv = sc_pkcs11_get_mechanism_list(slot->card, pMechanismList, pulCount); + + sc_pkcs11_unlock(); + return rv; } CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, @@ -190,11 +216,14 @@ CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, struct sc_pkcs11_slot *slot; CK_RV rv; - rv = slot_get_token(slotID, &slot); - if (rv != CKR_OK) - return rv; + sc_pkcs11_lock(); - return sc_pkcs11_get_mechanism_info(slot->card, type, pInfo); + rv = slot_get_token(slotID, &slot); + if (rv == CKR_OK) + rv = sc_pkcs11_get_mechanism_info(slot->card, type, pInfo); + + sc_pkcs11_unlock(); + return rv; } CK_RV C_InitToken(CK_SLOT_ID slotID, @@ -207,15 +236,19 @@ CK_RV C_InitToken(CK_SLOT_ID slotID, struct sc_pkcs11_slot *slot; CK_RV rv; + sc_pkcs11_lock(); + rv = slot_get_token(slotID, &slot); if (rv != CKR_OK) - return rv; + 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; - if (session->slot == slot) - return CKR_SESSION_EXISTS; + if (session->slot == slot) { + rv = CKR_SESSION_EXISTS; + goto out; + } } if (slot->card->framework->init_token == NULL) @@ -223,12 +256,13 @@ CK_RV C_InitToken(CK_SLOT_ID slotID, rv = slot->card->framework->init_token(slot->card, slot->fw_data, pPin, ulPinLen, pLabel); - if (rv != CKR_OK) - return rv; + if (rv == CKR_OK) { + /* Now we should re-bind all tokens so they get the + * corresponding function vector and flags */ + } - /* Now we should re-bind all tokens so they get the - * corresponding function vector and flags */ - return CKR_OK; +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_WaitForSlotEvent(CK_FLAGS flags, /* blocking/nonblocking flag */ @@ -241,11 +275,13 @@ CK_RV C_WaitForSlotEvent(CK_FLAGS flags, /* blocking/nonblocking flag */ unsigned int mask, events; CK_RV rv; + sc_pkcs11_lock(); + mask = SC_EVENT_CARD_INSERTED|SC_EVENT_CARD_REMOVED; if ((rv = slot_find_changed(pSlot, mask)) == CKR_OK || (flags & CKF_DONT_BLOCK)) - return rv; + goto out; for (i = k = 0; i < context->reader_count; i++) { reader = context->reader[i]; @@ -255,16 +291,103 @@ CK_RV C_WaitForSlotEvent(CK_FLAGS flags, /* blocking/nonblocking flag */ } } + sc_pkcs11_unlock(); r = sc_wait_for_event(readers, slots, k, mask, &found, &events, -1); + sc_pkcs11_lock(); + if (r != SC_SUCCESS) { error(context, "sc_wait_for_event() returned %d\n", r); - return sc_to_cryptoki_error(r, -1); + rv = sc_to_cryptoki_error(r, -1); + goto out; } - if ((rv = slot_find_changed(pSlot, mask)) == CKR_OK) - return rv; + if ((rv = slot_find_changed(pSlot, mask)) != CKR_OK) + rv = CKR_FUNCTION_FAILED; - return CKR_FUNCTION_FAILED; +out: sc_pkcs11_unlock(); + return rv; +} + +/* + * Locking functions + */ +#include "../libopensc/internal.h" + +static CK_C_INITIALIZE_ARGS_PTR _locking; +static void * _lock = NULL; + +CK_RV +sc_pkcs11_init_lock(CK_C_INITIALIZE_ARGS_PTR args) +{ + int rv = CKR_OK; + + if (_lock) + return CKR_OK; + + /* No CK_C_INITIALIZE_ARGS pointer, no locking */ + if (!args) + return CKR_OK; + + if (args->pReserved) + return CKR_ARGUMENTS_BAD; + + /* If the app tells us OS locking is okay, + * use that. Otherwise use the supplied functions. + */ + _locking = NULL; + if (args->flags & CKF_OS_LOCKING_OK) { + if (!(_lock = sc_mutex_new())) + rv = CKR_CANT_LOCK; + } else + if (args->CreateMutex + && args->DestroyMutex + && args->LockMutex + && args->UnlockMutex) { + rv = args->CreateMutex(&_lock); + if (rv == CKR_OK) + _locking = args; + } + + return rv; +} + +void +sc_pkcs11_free_lock() +{ + if (!_lock) + return; + if (_locking) + _locking->DestroyMutex(_lock); + else + sc_mutex_free((sc_mutex_t *) _lock); + _locking = NULL; + _lock = NULL; +} + +void +sc_pkcs11_lock() +{ + if (!_lock) + return; + if (_locking) { + while (_locking->LockMutex(_lock) != CKR_OK) + ; + } else { + sc_mutex_lock((sc_mutex_t *) _lock); + } +} + +void +sc_pkcs11_unlock() +{ + if (!_lock) + return; + if (_locking) { + while (_locking->UnlockMutex(_lock) != CKR_OK) + ; + } else { + sc_mutex_unlock((sc_mutex_t *) _lock); + } } CK_FUNCTION_LIST pkcs11_function_list = { diff --git a/src/pkcs11/pkcs11-object.c b/src/pkcs11/pkcs11-object.c index cc47e4e5..7c0ead45 100644 --- a/src/pkcs11/pkcs11-object.c +++ b/src/pkcs11/pkcs11-object.c @@ -37,18 +37,22 @@ CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, /* the session's handle */ struct sc_pkcs11_card *card; int rv; + sc_pkcs11_lock(); dump_template("C_CreateObject()", pTemplate, ulCount); rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; card = session->slot->card; if (card->framework->create_object == NULL) - return CKR_FUNCTION_NOT_SUPPORTED; - - return card->framework->create_object(card, session->slot, + rv = CKR_FUNCTION_NOT_SUPPORTED; + else + rv = card->framework->create_object(card, session->slot, pTemplate, ulCount, phObject); + +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, /* the session's handle */ @@ -90,13 +94,15 @@ CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle struct sc_pkcs11_object *object; int res, res_type; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; rv = pool_find(&session->slot->object_pool, hObject, (void**) &object); if (rv != CKR_OK) - return rv; + goto out; res_type = 0; for (i = 0; i < ulCount; i++) { @@ -125,6 +131,7 @@ CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle } } +out: sc_pkcs11_unlock(); return rv; } @@ -137,24 +144,28 @@ CK_RV C_SetAttributeValue(CK_SESSION_HANDLE hSession, /* the session's handle struct sc_pkcs11_session *session; struct sc_pkcs11_object *object; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; rv = pool_find(&session->slot->object_pool, hObject, (void**) &object); if (rv != CKR_OK) - return rv; + goto out; if (object->ops->set_attribute == NULL) - return CKR_FUNCTION_NOT_SUPPORTED; - - for (i = 0; i < ulCount; i++) { - rv = object->ops->set_attribute(session, object, &pTemplate[i]); - if (rv != CKR_OK) - return rv; + rv = CKR_FUNCTION_NOT_SUPPORTED; + else { + for (i = 0; i < ulCount; i++) { + rv = object->ops->set_attribute(session, object, &pTemplate[i]); + if (rv != CKR_OK) + break; + } } - return CKR_OK; +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */ @@ -170,9 +181,11 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */ struct sc_pkcs11_find_operation *operation; struct sc_pkcs11_pool_item *item; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; debug(context, "C_FindObjectsInit(slot = %d)\n", session->slot->id); dump_template("C_FindObjectsInit()", pTemplate, ulCount); @@ -180,9 +193,8 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */ rv = session_start_operation(session, SC_PKCS11_OPERATION_FIND, &find_mechanism, (struct sc_pkcs11_operation**) &operation); - if (rv != CKR_OK) - return rv; + goto out; operation->current_handle = 0; operation->num_handles = 0; @@ -234,7 +246,9 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, /* the session's handle */ } debug(context, "%d matching objects\n", operation->num_handles); - return CKR_OK; + +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, /* the session's handle */ @@ -246,14 +260,16 @@ CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, /* the session's han struct sc_pkcs11_session *session; struct sc_pkcs11_find_operation *operation; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; rv = session_get_operation(session, SC_PKCS11_OPERATION_FIND, (sc_pkcs11_operation_t **) &operation); if (rv != CKR_OK) - return rv; + goto out; to_return = operation->num_handles - operation->current_handle; if (to_return > ulMaxObjectCount) @@ -267,7 +283,8 @@ CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, /* the session's han operation->current_handle += to_return; - return CKR_OK; +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession) /* the session's handle */ @@ -275,16 +292,18 @@ CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession) /* the session's handle */ int rv; struct sc_pkcs11_session *session; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; rv = session_get_operation(session, SC_PKCS11_OPERATION_FIND, NULL); - if (rv != CKR_OK) - return rv; + if (rv == CKR_OK) + session_stop_operation(session, SC_PKCS11_OPERATION_FIND); - session_stop_operation(session, SC_PKCS11_OPERATION_FIND); - return CKR_OK; +out: sc_pkcs11_unlock(); + return rv; } /* @@ -298,13 +317,14 @@ CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, /* the session's handle */ int rv; struct sc_pkcs11_session *session; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); - if (rv != CKR_OK) - return rv; - - rv = sc_pkcs11_md_init(session, pMechanism); - + if (rv == CKR_OK) + rv = sc_pkcs11_md_init(session, pMechanism); debug(context, "C_DigestInit returns %d\n", rv); + + sc_pkcs11_unlock(); return rv; } @@ -317,15 +337,19 @@ CK_RV C_Digest(CK_SESSION_HANDLE hSession, /* the session's handle */ int rv; struct sc_pkcs11_session *session; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; rv = sc_pkcs11_md_update(session, pData, ulDataLen); if (rv == CKR_OK) rv = sc_pkcs11_md_final(session, pDigest, pulDigestLen); - debug(context, "C_Digest returns %d\n", rv); +out: debug(context, "C_Digest returns %d\n", rv); + sc_pkcs11_unlock(); + return rv; } @@ -336,13 +360,14 @@ CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */ int rv; struct sc_pkcs11_session *session; - rv = pool_find(&session_pool, hSession, (void**) &session); - if (rv != CKR_OK) - return rv; + sc_pkcs11_lock(); - rv = sc_pkcs11_md_update(session, pPart, ulPartLen); + rv = pool_find(&session_pool, hSession, (void**) &session); + if (rv == CKR_OK) + rv = sc_pkcs11_md_update(session, pPart, ulPartLen); debug(context, "C_DigestUpdate returns %d\n", rv); + sc_pkcs11_unlock(); return rv; } @@ -359,13 +384,14 @@ CK_RV C_DigestFinal(CK_SESSION_HANDLE hSession, /* the session's handle */ int rv; struct sc_pkcs11_session *session; - rv = pool_find(&session_pool, hSession, (void**) &session); - if (rv != CKR_OK) - return rv; + sc_pkcs11_lock(); - rv = sc_pkcs11_md_final(session, pDigest, pulDigestLen); + rv = pool_find(&session_pool, hSession, (void**) &session); + if (rv == CKR_OK) + rv = sc_pkcs11_md_final(session, pDigest, pulDigestLen); debug(context, "C_DigestFinal returns %d\n", rv); + sc_pkcs11_unlock(); return rv; } @@ -377,34 +403,42 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_KEY_TYPE key_type; CK_ATTRIBUTE sign_attribute = { CKA_SIGN, &can_sign, sizeof(can_sign) }; CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) }; - - int rv; struct sc_pkcs11_session *session; struct sc_pkcs11_object *object; + int rv; + + sc_pkcs11_lock(); rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; rv = pool_find(&session->slot->object_pool, hKey, (void**) &object); if (rv != CKR_OK) - return rv; + goto out; - if (object->ops->sign == NULL_PTR) - return CKR_KEY_TYPE_INCONSISTENT; + if (object->ops->sign == NULL_PTR) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } rv = object->ops->get_attribute(session, object, &sign_attribute); - if (rv != CKR_OK || !can_sign) - return CKR_KEY_TYPE_INCONSISTENT; + if (rv != CKR_OK || !can_sign) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } rv = object->ops->get_attribute(session, object, &key_type_attr); - if (rv != CKR_OK) - return CKR_KEY_TYPE_INCONSISTENT; + if (rv != CKR_OK) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } debug(context, "Sign operation initialized\n"); - rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type); - debug(context, "Sign initialization returns %d\n", rv); +out: debug(context, "Sign initialization returns %d\n", rv); + sc_pkcs11_unlock(); + return rv; } @@ -418,9 +452,11 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, /* the session's handle */ struct sc_pkcs11_session *session; CK_ULONG length; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; /* According to the pkcs11 specs, we must not do any calls that * change our crypto state if the caller is just asking for the @@ -428,18 +464,20 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, /* the session's handle */ * CKR_BUFFER_TOO_SMALL. Thus we cannot do the sign_update call * below. */ if ((rv = sc_pkcs11_sign_size(session, &length)) != CKR_OK) - return rv; + goto out; if (pSignature == NULL || length > *pulSignatureLen) { *pulSignatureLen = length; - return pSignature? CKR_BUFFER_TOO_SMALL : CKR_OK; + rv = pSignature? CKR_BUFFER_TOO_SMALL : CKR_OK; + goto out; } rv = sc_pkcs11_sign_update(session, pData, ulDataLen); if (rv == CKR_OK) rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen); - debug(context, "Signing result was %d\n", rv); +out: debug(context, "Signing result was %d\n", rv); + sc_pkcs11_unlock(); return rv; } @@ -448,15 +486,17 @@ CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pPart, /* the data (digest) to be signed */ CK_ULONG ulPartLen) /* count of bytes to be signed */ { - int rv; struct sc_pkcs11_session *session; + int rv; + + sc_pkcs11_lock(); rv = pool_find(&session_pool, hSession, (void**) &session); - if (rv != CKR_OK) - return rv; + if (rv == CKR_OK) + rv = sc_pkcs11_sign_update(session, pPart, ulPartLen); - rv = sc_pkcs11_sign_update(session, pPart, ulPartLen); debug(context, "C_SignUpdate returns %d\n", rv); + sc_pkcs11_unlock(); return rv; } @@ -464,13 +504,15 @@ CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pSignature, /* receives the signature */ CK_ULONG_PTR pulSignatureLen) /* receives byte count of signature */ { - int rv; struct sc_pkcs11_session *session; CK_ULONG length; + int rv; + + sc_pkcs11_lock(); rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; /* According to the pkcs11 specs, we must not do any calls that * change our crypto state if the caller is just asking for the @@ -478,16 +520,18 @@ CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, /* the session's handle */ * CKR_BUFFER_TOO_SMALL. */ if ((rv = sc_pkcs11_sign_size(session, &length)) != CKR_OK) - return rv; + goto out; if (pSignature == NULL || length > *pulSignatureLen) { *pulSignatureLen = length; - return pSignature? CKR_BUFFER_TOO_SMALL : CKR_OK; + rv = pSignature? CKR_BUFFER_TOO_SMALL : CKR_OK; + } else { + rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen); } +out: debug(context, "C_SignFinal returns %d\n", rv); + sc_pkcs11_unlock(); - rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen); - debug(context, "C_SignFinal returns %d\n", rv); return rv; } @@ -499,28 +543,35 @@ CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_KEY_TYPE key_type; CK_ATTRIBUTE sign_attribute = { CKA_SIGN, &can_sign, sizeof(can_sign) }; CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) }; - - int rv; struct sc_pkcs11_session *session; struct sc_pkcs11_object *object; + int rv; + + sc_pkcs11_lock(); rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; rv = pool_find(&session->slot->object_pool, hKey, (void**) &object); if (rv != CKR_OK) - return rv; + goto out; - if (object->ops->sign == NULL_PTR) - return CKR_KEY_TYPE_INCONSISTENT; + if (object->ops->sign == NULL_PTR) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } rv = object->ops->get_attribute(session, object, &sign_attribute); - if (rv != CKR_OK || !can_sign) - return CKR_KEY_TYPE_INCONSISTENT; + if (rv != CKR_OK || !can_sign) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } rv = object->ops->get_attribute(session, object, &key_type_attr); - if (rv != CKR_OK) - return CKR_KEY_TYPE_INCONSISTENT; + if (rv != CKR_OK) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } /* XXX: need to tell the signature algorithm that we want * to recover the signature */ @@ -528,7 +579,8 @@ CK_RV C_SignRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */ rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type); - debug(context, "Sign initialization returns %d\n", rv); +out: debug(context, "Sign initialization returns %d\n", rv); + sc_pkcs11_unlock(); return rv; } @@ -681,21 +733,25 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, /* the session's handl CK_ULONG ulAttributeCount, /* # of attributes in template */ CK_OBJECT_HANDLE_PTR phKey) /* gets handle of recovered key */ { - int rv; struct sc_pkcs11_session *session; struct sc_pkcs11_object *object, *result; + int rv; + + sc_pkcs11_lock(); rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; rv = pool_find(&session->slot->object_pool, hUnwrappingKey, (void**) &object); if (rv != CKR_OK) - return rv; + goto out; - if (object->ops->sign == NULL_PTR) - return CKR_KEY_TYPE_INCONSISTENT; + if (object->ops->sign == NULL_PTR) { + rv = CKR_KEY_TYPE_INCONSISTENT; + goto out; + } rv = object->ops->unwrap_key(session, object, pMechanism, pWrappedKey, ulWrappedKeyLen, @@ -704,10 +760,10 @@ CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, /* the session's handl debug(context, "Unwrapping result was %d\n", rv); - if (rv != CKR_OK) - return rv; + if (rv == CKR_OK) + rv = pool_insert(&session->slot->object_pool, result, phKey); - rv = pool_insert(&session->slot->object_pool, result, phKey); +out: sc_pkcs11_unlock(); return rv; } @@ -729,11 +785,14 @@ CK_RV C_SeedRandom(CK_SESSION_HANDLE hSession, /* the session's handle */ struct sc_pkcs11_session *session; int rv; - rv = pool_find(&session_pool, hSession, (void**) &session); - if (rv != CKR_OK) - return rv; + sc_pkcs11_lock(); - return sc_pkcs11_openssl_add_seed_rand(session, pSeed, ulSeedLen); + rv = pool_find(&session_pool, hSession, (void**) &session); + if (rv == CKR_OK) + rv = sc_pkcs11_openssl_add_seed_rand(session, pSeed, ulSeedLen); + + sc_pkcs11_unlock(); + return rv; #else return CKR_FUNCTION_NOT_SUPPORTED; #endif @@ -747,11 +806,14 @@ CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession, /* the session's handle */ struct sc_pkcs11_session *session; int rv; - rv = pool_find(&session_pool, hSession, (void**) &session); - if (rv != CKR_OK) - return rv; + sc_pkcs11_lock(); - return sc_pkcs11_openssl_add_gen_rand(session, RandomData, ulRandomLen); + rv = pool_find(&session_pool, hSession, (void**) &session); + if (rv == CKR_OK) + rv = sc_pkcs11_openssl_add_gen_rand(session, RandomData, ulRandomLen); + + sc_pkcs11_unlock(); + return rv; #else return CKR_FUNCTION_NOT_SUPPORTED; #endif diff --git a/src/pkcs11/pkcs11-session.c b/src/pkcs11/pkcs11-session.c index 889c9978..ce2af645 100644 --- a/src/pkcs11/pkcs11-session.c +++ b/src/pkcs11/pkcs11-session.c @@ -33,18 +33,24 @@ CK_RV C_OpenSession(CK_SLOT_ID slotID, /* the slot's ID */ struct sc_pkcs11_session *session; int rv; + sc_pkcs11_lock(); + debug(context, "Opening new session for slot %d\n", slotID); - if (!(flags & CKF_SERIAL_SESSION)) - return CKR_SESSION_PARALLEL_NOT_SUPPORTED; + if (!(flags & CKF_SERIAL_SESSION)) { + rv = CKR_SESSION_PARALLEL_NOT_SUPPORTED; + goto out; + } rv = slot_get_token(slotID, &slot); if (rv != CKR_OK) - return rv; + goto out; /* Check that no conflictions sessions exist */ - if (!(flags & CKF_RW_SESSION) && (slot->login_user == CKU_SO)) - return CKR_SESSION_READ_WRITE_SO_EXISTS; + if (!(flags & CKF_RW_SESSION) && (slot->login_user == CKU_SO)) { + rv = CKR_SESSION_READ_WRITE_SO_EXISTS; + goto out; + } session = (struct sc_pkcs11_session*) malloc(sizeof(struct sc_pkcs11_session)); memset(session, 0, sizeof(struct sc_pkcs11_session)); @@ -59,18 +65,21 @@ CK_RV C_OpenSession(CK_SLOT_ID slotID, /* the slot's ID */ else slot->nsessions++; +out: sc_pkcs11_unlock(); return rv; } CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) /* the session's handle */ { struct sc_pkcs11_slot *slot; - int rv; struct sc_pkcs11_session *session; + int rv; + + sc_pkcs11_lock(); rv = pool_find_and_delete(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; debug(context, "C_CloseSession(slot %d)\n", session->slot->id); @@ -84,10 +93,14 @@ CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) /* the session's handle */ } free(session); - return CKR_OK; + +out: sc_pkcs11_unlock(); + return rv; } -CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) /* the token's slot */ +/* Internal version of C_CloseAllSessions that gets called with + * 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; @@ -105,15 +118,27 @@ CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) /* the token's slot */ return CKR_OK; } +CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) /* the token's slot */ +{ + int rv; + + sc_pkcs11_lock(); + rv = sc_pkcs11_close_all_sessions(slotID); + 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 */ { - int rv; struct sc_pkcs11_session *session; + int rv; + + sc_pkcs11_lock(); rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; debug(context, "C_GetSessionInfo(slot %d).\n", session->slot->id); pInfo->slotID = session->slot->id; @@ -133,7 +158,8 @@ CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, /* the session's handle */ ? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION; } - return CKR_OK; +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, /* the session's handle */ @@ -161,22 +187,30 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */ struct sc_pkcs11_session *session; struct sc_pkcs11_slot *slot; - if (userType != CKU_USER && userType != CKU_SO) - return CKR_USER_TYPE_INVALID; + sc_pkcs11_lock(); + + if (userType != CKU_USER && userType != CKU_SO) { + rv = CKR_USER_TYPE_INVALID; + goto out; + } rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; debug(context, "Login for session %d\n", hSession); slot = session->slot; - if (!(slot->token_info.flags & CKF_USER_PIN_INITIALIZED)) - return CKR_USER_PIN_NOT_INITIALIZED; + if (!(slot->token_info.flags & CKF_USER_PIN_INITIALIZED)) { + rv = CKR_USER_PIN_NOT_INITIALIZED; + goto out; + } - if (slot->login_user >= 0) - return CKR_USER_ALREADY_LOGGED_IN; + if (slot->login_user >= 0) { + rv = CKR_USER_ALREADY_LOGGED_IN; + goto out; + } rv = slot->card->framework->login(slot->card, slot->fw_data, @@ -184,6 +218,7 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */ if (rv == CKR_OK) slot->login_user = userType; +out: sc_pkcs11_unlock(); return rv; } @@ -193,19 +228,23 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession) /* the session's handle */ struct sc_pkcs11_session *session; struct sc_pkcs11_slot *slot; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; debug(context, "Logout for session %d\n", hSession); slot = session->slot; - if (slot->login_user < 0) - return CKR_OK; + if (slot->login_user >= 0) { + slot->login_user = -1; + rv = slot->card->framework->logout(slot->card, slot->fw_data); + } - slot->login_user = -1; - return slot->card->framework->logout(slot->card, slot->fw_data); +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, @@ -216,17 +255,25 @@ CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, struct sc_pkcs11_slot *slot; int rv; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; slot = session->slot; - if (slot->login_user != CKU_SO) - return CKR_USER_NOT_LOGGED_IN; - if (slot->card->framework->init_pin == NULL) - return CKR_FUNCTION_NOT_SUPPORTED; - return slot->card->framework->init_pin(slot->card, slot, + if (slot->login_user != CKU_SO) { + rv = CKR_USER_NOT_LOGGED_IN; + } 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); + } + +out: sc_pkcs11_unlock(); + return rv; } CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, @@ -239,18 +286,25 @@ CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, struct sc_pkcs11_session *session; struct sc_pkcs11_slot *slot; + sc_pkcs11_lock(); + rv = pool_find(&session_pool, hSession, (void**) &session); if (rv != CKR_OK) - return rv; + goto out; debug(context, "Changing PIN (session %d)\n", hSession); #if 0 - if (!(ses->flags & CKF_RW_SESSION)) - return CKR_SESSION_READ_ONLY; + if (!(ses->flags & CKF_RW_SESSION)) { + rv = CKR_SESSION_READ_ONLY; + goto out; + } #endif slot = session->slot; - return slot->card->framework->change_pin(slot->card, slot->fw_data, + rv = slot->card->framework->change_pin(slot->card, slot->fw_data, pOldPin, ulOldLen, pNewPin, ulNewLen); + +out: sc_pkcs11_unlock(); + return rv; } diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index e053961b..f564a817 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -314,6 +314,7 @@ CK_RV session_start_operation(struct sc_pkcs11_session *, CK_RV session_get_operation(struct sc_pkcs11_session *, int, struct sc_pkcs11_operation **); CK_RV session_stop_operation(struct sc_pkcs11_session *, int); +CK_RV sc_pkcs11_close_all_sessions(CK_SLOT_ID); /* Generic secret key stuff */ CK_RV sc_pkcs11_create_secret_key(struct sc_pkcs11_session *, @@ -372,6 +373,12 @@ CK_RV sc_pkcs11_openssl_add_gen_rand(struct sc_pkcs11_session *, CK_BYTE_PTR, CK /* Load configuration defaults */ void load_pkcs11_parameters(struct sc_pkcs11_config *, struct sc_context *); +/* Locking primitives at the pkcs11 level */ +CK_RV sc_pkcs11_init_lock(CK_C_INITIALIZE_ARGS_PTR); +void sc_pkcs11_lock(void); +void sc_pkcs11_unlock(void); +void sc_pkcs11_free_lock(void); + #ifdef __cplusplus } #endif diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c index 4d5d630d..f45e8eb6 100644 --- a/src/pkcs11/slot.c +++ b/src/pkcs11/slot.c @@ -278,7 +278,7 @@ CK_RV slot_token_removed(int id) token_was_present = (slot->slot_info.flags & CKF_TOKEN_PRESENT); /* Terminate active sessions */ - C_CloseAllSessions(id); + sc_pkcs11_close_all_sessions(id); /* Object pool */ while (pool_find_and_delete(&slot->object_pool, 0, (void**) &object) == CKR_OK) {