From d108e2008ec7205ef3907296fd3e5a810e45919b Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Tue, 9 Dec 2008 20:09:51 +0000 Subject: First shot at renaming the project. --- p11-capi-session.c | 983 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 983 insertions(+) create mode 100644 p11-capi-session.c (limited to 'p11-capi-session.c') diff --git a/p11-capi-session.c b/p11-capi-session.c new file mode 100644 index 0000000..e921875 --- /dev/null +++ b/p11-capi-session.c @@ -0,0 +1,983 @@ +/* + * Copyright (C) 2007 Stef Walter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "p11-capi.h" +#include "p11-capi-builtin.h" +#include "p11-capi-cert.h" +#include "p11-capi-key.h" +#include "p11-capi-object.h" +#include "p11-capi-rsa.h" +#include "p11-capi-session.h" +#include "p11-capi-token.h" +#include "p11-capi-trust.h" + +/* For operation_type in P11cSession */ +enum +{ + OPERATION_NONE, + OPERATION_FIND, + OPERATION_SIGN, + OPERATION_DECRYPT +}; + +static P11cArray* all_sessions = NULL; + +static void +object_data_release(P11cObjectData* objdata) +{ + ASSERT(objdata->data_funcs); + ASSERT(objdata->data_funcs->release); + (objdata->data_funcs->release)(objdata); +} + +CK_RV +p11c_session_create(CK_SLOT_ID slot, P11cSession** ret) +{ + P11cSession* sess; + const char *store; + DWORD err; + + sess = calloc(1, sizeof(P11cSession)); + if(!sess) + return CKR_HOST_MEMORY; + + sess->object_data = p11c_hash_new(NULL, NULL); + if(!sess->object_data) { + free(sess); + return CKR_HOST_MEMORY; + } + + sess->mutex = CreateMutex(NULL, FALSE, NULL); + if(!sess->mutex) { + p11c_hash_free(sess->object_data, NULL); + free(sess); + return CKR_HOST_MEMORY; + } + + store = p11c_token_get_store_name(slot); + if(store) + { + sess->store = CertOpenSystemStore((HCRYPTPROV)NULL, store); + if(sess->store == NULL) + { + err = GetLastError(); + + /* Store not found, we don't care */ + if(err != ERROR_FILE_NOT_FOUND) + { + p11c_hash_free(sess->object_data, NULL); + CloseHandle(sess->mutex); + free(sess); + return p11c_winerr_to_ckr(err); + } + } + } + + sess->slot = slot; + + DBGS(sess, "created"); + + *ret = sess; + return CKR_OK; +} + +CK_RV +p11c_session_register(P11cSession* sess) +{ + P11cSession* blank = NULL; + CK_SESSION_HANDLE id = 0; + CK_RV ret = CKR_OK; + size_t i; + + ASSERT(sess); + ASSERT(sess->id == 0 && sess->refs == 0); + + DBGS(sess, "registering new session"); + + p11c_lock_global(); + + /* Find a nice session identifier */ + while(id == 0) { + + /* Allocate sessions properly */ + if(!all_sessions) + { + all_sessions = p11c_array_new(0, 1, sizeof(P11cSession*)); + if(!all_sessions) + { + ret = CKR_HOST_MEMORY; + break; + } + + /* A blank entry for '0' */ + p11c_array_append(all_sessions, blank); + + DBG(("allocated new session list")); + } + + /* + * PKCS#11 GRAY AREA: We're assuming we can reuse session + * handles. PKCS#11 spec says they're like file handles, + * and file handles get reused :) + */ + + /* Note we never put anything in array position '0' */ + for(i = 1; i < all_sessions->len; ++i) + { + /* Any empty position will do */ + if(!p11c_array_index(all_sessions, P11cSession*, i)) + { + id = i; + break; + } + } + + /* Couldn't find a handle, append a handle */ + if(id == 0) + { + id = all_sessions->len; + p11c_array_append(all_sessions, blank); + } + } + + if(ret == CKR_OK) + { + ASSERT(id > 0 && id < all_sessions->len); + ASSERT(!p11c_array_index(all_sessions, P11cSession*, id)); + + + /* And assign it to the session handle */ + p11c_array_index(all_sessions, P11cSession*, i) = sess; + sess->id = id; + + /* The session list reference */ + ASSERT(sess->refs == 0); + sess->refs++; + + DBGS(sess, "registered sesson id"); + } + + p11c_unlock_global(); + + return ret; +} + +void +p11c_session_destroy(P11cSession* sess) +{ + ASSERT(sess); + ASSERT(sess->refs == 0); + + /* Ask any pending operations to cleanup */ + if(sess->operation_type) + { + ASSERT(sess->operation_cancel); + (sess->operation_cancel)(sess); + } + + ASSERT(sess->operation_type == 0); + ASSERT(sess->operation_data == NULL); + ASSERT(sess->operation_cancel == NULL); + + if(sess->store) + CertCloseStore(sess->store, 0); + + /* Make all the object adat go away */ + ASSERT(sess->object_data != NULL); + p11c_hash_free(sess->object_data, object_data_release); + + /* And make the mutex go away */ + ASSERT(sess->mutex != NULL); + CloseHandle(sess->mutex); + + DBGS(sess, "destroyed"); + free(sess); +} + +void +p11c_session_get_info(P11cSession* sess, CK_SESSION_INFO_PTR info) +{ + ASSERT(sess); + ASSERT(info); + + info->slotID = sess->slot; + info->flags = CKF_SERIAL_SESSION; + if(sess->read_write) + info->flags |= CKF_RW_SESSION; + + if(p11c_token_is_logged_in(sess->slot)) + info->state = sess->read_write ? CKS_RW_USER_FUNCTIONS : CKS_RO_USER_FUNCTIONS; + else + info->state = sess->read_write ? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION; + + /* TODO: We could implement some use of GetLastError() here */ + info->ulDeviceError = 0; +} + +static CK_RV +lock_ref_internal(P11cArray* sessions, CK_SESSION_HANDLE id, + BOOL remove, BOOL writable, P11cSession** sess_ret) +{ + P11cSession *sess; + DWORD r; + + ASSERT(sessions); + ASSERT(sess_ret); + + if(id >= sessions->len) + { + DBG(("invalid session id: %d", id)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* A seemingly valid id */ + ASSERT(sessions); + sess = p11c_array_index(sessions, P11cSession*, id); + + if(!sess) + { + DBG(("session does not exist: %d", id)); + return CKR_SESSION_HANDLE_INVALID; + } + + /* Make sure it's the right kind of session */ + if(writable && !sess->read_write) + return CKR_SESSION_READ_ONLY; + + ASSERT(sess->id == id); + + /* Closing takes precedence over active operations */ + if(!remove) + { + /* + * An initial check is done to make sure this session is not active. + * This is done outside of the lock. The real check is done later + * inside a lock. This is so we can return quickly without blocking + * in most cases. + */ + + if(sess->in_call) + { + DBGS(sess, ("an operation is already active in this session")); + return CKR_OPERATION_ACTIVE; + } + } + + /* Lock the CallP11cSession */ + r = WaitForSingleObject(sess->mutex, INFINITE); + ASSERT(r == WAIT_OBJECT_0); + + /* Do the real check */ + if(!remove && sess->in_call) + { + ReleaseMutex(sess->mutex); + DBGS(sess, ("an operation is already active in this session")); + return CKR_OPERATION_ACTIVE; + } + + /* Make sure it doesn't go away */ + ASSERT(sess->refs > 0); + sess->refs++; + + DBGS(sess, "found and locked session"); + + /* And remove it if necessary */ + if(remove) + { + p11c_array_index(sessions, P11cSession*, id) = NULL; + + /* The session list reference */ + sess->refs--; + ASSERT(sess->refs > 0); + + DBGS(sess, "removed session from list"); + } + else + { + ASSERT(!sess->in_call); + sess->in_call = 1; + } + + *sess_ret = sess; + return CKR_OK; +} + +CK_RV +p11c_session_get_lock_ref(CK_ULONG id, BOOL writable, P11cSession **sess) +{ + /* This must be called without any locks held */ + + CK_RV ret = CKR_OK; + + ASSERT(sess); + + if(id <= 0) + { + DBG(("invalid session id passed: %d", id)); + return CKR_ARGUMENTS_BAD; + } + + p11c_lock_global(); + + ret = lock_ref_internal (all_sessions, id, FALSE, writable, sess); + + p11c_unlock_global(); + + return ret; +} + +CK_RV +p11c_session_remove_lock_ref(CK_ULONG id, P11cSession **sess) +{ + /* This must be called without any locks held */ + + CK_RV ret = CKR_OK; + + ASSERT(sess); + + if(id <= 0) + { + DBG(("invalid session id passed: %d", id)); + return CKR_ARGUMENTS_BAD; + } + + p11c_lock_global(); + + ret = lock_ref_internal (all_sessions, id, TRUE, FALSE, sess); + + p11c_unlock_global(); + + return ret; +} + +void +p11c_session_unref_unlock(P11cSession* sess) +{ + /* The CallP11cSession must be locked at this point */ + + int refs; + BOOL r; + + ASSERT(sess); + + ASSERT(sess->refs > 0); + sess->refs--; + refs = sess->refs; + + sess->in_call = 0; + + DBGS(sess, "unlocked session"); + + r = ReleaseMutex(sess->mutex); + ASSERT(r == TRUE); + + /* + * At this point if no references are held, then we can safely + * delete. No other thread should be involved. + */ + + if(refs == 0) + p11c_session_destroy(sess); +} + +CK_RV +p11c_session_close_all(CK_SLOT_ID slot) +{ + /* This must be called without any locks held */ + + P11cArray* sessions; + P11cSession *sess; + size_t i; + CK_RV ret = CKR_OK; + + /* + * PKCS#11 GRAY AREA: What happens when this gets called + * concurrently? We don't return an error on the second call, + * because by the time it returns, all sessions should be closed. + */ + + DBG(("closing all sessions for: %d", slot)); + + if(!all_sessions) + return CKR_OK; + + p11c_lock_global(); + + sessions = p11c_array_sized_new(0, 1, sizeof(P11cSession*), + all_sessions->len); + if(!sessions) + ret = CKR_HOST_MEMORY; + + /* Steal all the session data */ + if(ret == CKR_OK) + { + for(i = 0; i < all_sessions->len; ++i) + { + sess = p11c_array_index(all_sessions, P11cSession*, i); + if(sess && (slot == ((CK_SLOT_ID)-1) || sess->slot == slot)) + { + /* Steal this session */ + p11c_array_index(all_sessions, P11cSession*, i) = NULL; + } + else + { + /* Not a session we're interested in */ + sess = NULL; + } + + /* Both null and normal sessions are set to preserve indexes */ + p11c_array_append(sessions, sess); + } + + ASSERT(sessions->len == all_sessions->len); + } + + p11c_unlock_global(); + + if(ret != CKR_OK) + return ret; + + /* Close each session in turn */ + for(i = 0; i < sessions->len; ++i) + { + if(!p11c_array_index(sessions, P11cSession*, i)) + continue; + + /* We need any calls in other threads to finish, so wait here */ + if(lock_ref_internal(sessions, i, TRUE, FALSE, &sess) == CKR_OK) + p11c_session_unref_unlock(sess); + } + + /* We stole the memory above, free it now */ + p11c_array_free(sessions, 1); + return CKR_OK; +} + +void +p11c_session_cleanup_all() +{ + p11c_session_close_all((CK_SLOT_ID)-1); + + p11c_lock_global(); + + p11c_array_free(all_sessions, 1); + all_sessions = NULL; + + p11c_unlock_global(); +} + +/* ---------------------------------------------------------------------------- + * OBJECT DATA + */ + +CK_RV +p11c_session_get_object_data(P11cSession* sess, P11cObject* obj, + P11cObjectData** objdata) +{ + CK_OBJECT_HANDLE id; + P11cObjectData* newdata; + CK_RV ret; + + ASSERT(sess); + ASSERT(sess->object_data); + ASSERT(obj); + ASSERT(obj->obj_funcs); + ASSERT(obj->obj_funcs->load_data); + ASSERT(objdata); + + id = obj->id; + + *objdata = p11c_hash_get(sess->object_data, p11c_hash_key(id)); + if(*objdata) + return CKR_OK; + + ret = (obj->obj_funcs->load_data)(sess, obj, &newdata); + if(ret != CKR_OK) + return ret; + + newdata->object = id; + ASSERT(newdata->data_funcs); + + if(!p11c_hash_set(sess->object_data, p11c_hash_key(id), newdata)) + { + object_data_release(newdata); + return CKR_HOST_MEMORY; + } + + *objdata = newdata; + return CKR_OK; +} + +void +p11c_session_clear_object_data(P11cSession* sess, P11cObject* obj) +{ + P11cObjectData* objdata; + + ASSERT(sess); + ASSERT(sess->object_data); + ASSERT(obj); + + objdata = (P11cObjectData*)p11c_hash_rem(sess->object_data, p11c_hash_key(obj->id)); + if(objdata) + object_data_release(objdata); +} + +void +p11c_session_enum_object_data(P11cSession* sess, + P11cEnumObjectData enum_func, void* arg) +{ + CK_OBJECT_HANDLE i, max; + P11cObject* obj; + P11cObjectData* objdata; + + ASSERT(sess); + ASSERT(sess->object_data); + ASSERT(enum_func); + + max = p11c_token_get_max_handle(); + for(i = 0; i < max; ++i) + { + objdata = (P11cObjectData*)p11c_hash_get(sess->object_data, p11c_hash_key(i)); + if(!objdata) + continue; + + obj = p11c_token_lookup_object(sess->slot, i); + if(!obj) + continue; + + (enum_func)(sess, obj, objdata, arg); + } +} + +CK_RV +p11c_session_get_object_data_for(P11cSession* sess, CK_OBJECT_HANDLE hand, + P11cObjectData** objdata) +{ + P11cObject* obj; + + obj = p11c_token_lookup_object(sess->slot, hand); + if(!obj) + return CKR_OBJECT_HANDLE_INVALID; + + return p11c_session_get_object_data(sess, obj, objdata); +} + +void +p11c_session_take_object_data(P11cSession* sess, P11cObject* obj, + P11cObjectData* objdata) +{ + P11cObjectData* prev; + + ASSERT(obj); + ASSERT(sess); + ASSERT(sess->object_data); + + ASSERT(objdata); + objdata->object = obj->id; + + prev = p11c_hash_rem(sess->object_data, p11c_hash_key(obj->id)); + if(prev) + object_data_release(prev); + + if(!p11c_hash_set(sess->object_data, p11c_hash_key(obj->id), objdata)) + object_data_release(objdata); +} + + +/* ---------------------------------------------------------------------------- + * FIND OPERATION + */ + +static BOOL +get_ulong_attribute(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR templ, + CK_ULONG count, CK_ULONG* val) +{ + CK_ULONG i; + + ASSERT(val); + ASSERT(!count || templ); + + for(i = 0; i < count; ++i) + { + if(templ[i].type == type) + { + *val = *((CK_ULONG*)templ[i].pValue); + return TRUE; + } + } + + return FALSE; +} + +static CK_RV +gather_objects(P11cSession* sess, CK_ATTRIBUTE_PTR match, + CK_ULONG count, P11cArray* arr) +{ + CK_OBJECT_CLASS ocls = CKO_ANY; + CK_RV ret = CKR_OK; + + get_ulong_attribute(CKA_CLASS, match, count, &ocls); + + /* Search for builtins */ + ret = p11c_builtin_find(sess, ocls, match, count, arr); + if(ret != CKR_OK) + return ret; + + /* + * Search through certificates. + * + * We always do this search first. In Windows a lots hangs off + * the certificates. For example private keys are not contained + * in the same stores that certificates are in. There are a different + * set of key containers many of which can be used together + * with a certificate stored in any store. + * + * The trust objects we expose also depend on the certificates + * loaded. + */ + ret = p11c_cert_find(sess, ocls, match, count, arr); + if(ret != CKR_OK) + return ret; + + /* Search through trust objects */ + ret = p11c_trust_find(sess, ocls, match, count, arr); + if(ret != CKR_OK) + return ret; + + /* Search through key objects */ + ret = p11c_key_find(sess, ocls, match, count, arr); + if(ret != CKR_OK) + return ret; + + return ret; +} + +void +cleanup_find_operation(P11cSession* sess) +{ + ASSERT(sess->operation_type == OPERATION_FIND); + if(sess->operation_data) + p11c_array_free((P11cArray*)sess->operation_data, TRUE); + sess->operation_type = OPERATION_NONE; + sess->operation_data = NULL; + sess->operation_cancel = NULL; +} + +void +purge_duplicate_objects(P11cArray* arr) +{ + P11cHash* checks; + CK_OBJECT_HANDLE v; + size_t i; + + checks = p11c_hash_new(NULL, NULL); + if(!checks) + return; + + for(i = 0; i < arr->len; ) + { + v = p11c_array_index(arr, CK_OBJECT_HANDLE, i); + if(p11c_hash_get(checks, p11c_hash_key(v))) + { + p11c_array_remove_index(arr, i); + /* Look at same i again */ + } + else + { + if(!p11c_hash_set(checks, p11c_hash_key(v), arr)) + break; + ++i; + } + } + + p11c_hash_free(checks, NULL); +} + +CK_RV +p11c_session_find_init(P11cSession* sess, CK_ATTRIBUTE_PTR match, + CK_ULONG count) +{ + P11cArray* arr; + CK_RV ret; + + ASSERT(sess); + ASSERT(!count || match); + + if(sess->operation_type != OPERATION_NONE) + return CKR_OPERATION_ACTIVE; + + arr = p11c_array_new(0, 1, sizeof(CK_OBJECT_HANDLE)); + if(!arr) + return CKR_HOST_MEMORY; + + ret = gather_objects(sess, match, count, arr); + if(ret != CKR_OK) + { + p11c_array_free(arr, TRUE); + return ret; + } + + /* Cleanup all duplicates in the array */ + purge_duplicate_objects(arr); + + sess->operation_type = OPERATION_FIND; + sess->operation_data = arr; + sess->operation_cancel = cleanup_find_operation; + + return CKR_OK; +} + +CK_RV +p11c_session_find(P11cSession* sess, CK_OBJECT_HANDLE_PTR objects, + CK_ULONG max_object_count, CK_ULONG_PTR object_count) +{ + P11cArray* arr; + size_t i; + + ASSERT(sess); + ASSERT(object_count); + ASSERT(!max_object_count || objects); + + if(sess->operation_type != OPERATION_FIND) + return CKR_OPERATION_NOT_INITIALIZED; + + if(!max_object_count) + { + *object_count = 0; + return CKR_OK; + } + + arr = (P11cArray*)sess->operation_data; + *object_count = (max_object_count > arr->len ? arr->len : max_object_count); + for(i = 0; i < *object_count; ++i) + objects[i] = p11c_array_index(arr, CK_OBJECT_HANDLE, i); + + p11c_array_remove_range(arr, 0, *object_count); + + return CKR_OK; +} + +CK_RV +p11c_session_find_final(P11cSession* sess) +{ + ASSERT(sess); + + if(sess->operation_type != OPERATION_FIND) + return CKR_OPERATION_NOT_INITIALIZED; + + cleanup_find_operation(sess); + return CKR_OK; +} + + +/* ---------------------------------------------------------------------------- + * CRYPTO OPERATIONS + */ + +typedef struct _CryptoContext +{ + CK_MECHANISM_TYPE mech_type; + P11cDestroyFunc mech_cleanup; + void* mech_data; +} +CryptoContext; + +void +cleanup_crypto_operation(P11cSession* sess) +{ + CryptoContext* ctx; + + if(sess->operation_data) + { + ctx = (CryptoContext*)sess->operation_data; + if(ctx->mech_cleanup) + (ctx->mech_cleanup)(ctx->mech_data); + free(ctx); + } + + sess->operation_type = OPERATION_NONE; + sess->operation_data = NULL; + sess->operation_cancel = NULL; +} + +CK_RV +p11c_session_sign_init(P11cSession* sess, CK_MECHANISM_PTR mech, + P11cObjectData *objdata) +{ + CryptoContext* ctx; + CK_RV ret; + + ASSERT(sess); + ASSERT(mech); + ASSERT(objdata); + + if(sess->operation_type != OPERATION_NONE) + return CKR_OPERATION_ACTIVE; + + ctx = calloc(1, sizeof(CryptoContext)); + if(!ctx) + return CKR_HOST_MEMORY; + + ctx->mech_type = mech->mechanism; + + switch(mech->mechanism) + { + case CKM_RSA_PKCS: + ret = p11c_rsa_pkcs_sign_init(objdata, &ctx->mech_data); + ctx->mech_cleanup = p11c_rsa_pkcs_sign_cleanup; + break; + default: + ret = CKR_MECHANISM_INVALID; + break; + }; + + if(ret != CKR_OK) + { + free(ctx); + ASSERT(!sess->operation_data); + return ret; + } + + sess->operation_type = OPERATION_SIGN; + sess->operation_data = ctx; + sess->operation_cancel = cleanup_crypto_operation; + return CKR_OK; +} + +CK_RV +p11c_session_sign(P11cSession* sess, CK_BYTE_PTR data, CK_ULONG n_data, + CK_BYTE_PTR signature, CK_ULONG_PTR n_signature) +{ + CryptoContext *ctx; + BOOL incomplete; + CK_RV ret; + + ASSERT(sess); + ASSERT(data); + ASSERT(n_data); + + if(sess->operation_type != OPERATION_SIGN) + return CKR_OPERATION_NOT_INITIALIZED; + + ctx = (CryptoContext*)sess->operation_data; + switch(ctx->mech_type) + { + case CKM_RSA_PKCS: + ret = p11c_rsa_pkcs_sign_perform(data, n_data, signature, n_signature, + &ctx->mech_data); + break; + + default: + ASSERT(FALSE); + ret = CKR_GENERAL_ERROR; + break; + } + + /* Buffer calculation, we don't end operation */ + incomplete = (ret == CKR_BUFFER_TOO_SMALL || (ret == CKR_OK && !signature)); + + if(!incomplete) + cleanup_crypto_operation(sess); + + return ret; +} + +CK_RV +p11c_session_decrypt_init(P11cSession* sess, CK_MECHANISM_PTR mech, + P11cObjectData *objdata) +{ + CryptoContext* ctx; + CK_RV ret; + + ASSERT(sess); + ASSERT(mech); + ASSERT(objdata); + + if(sess->operation_type != OPERATION_NONE) + return CKR_OPERATION_ACTIVE; + + ctx = calloc(1, sizeof(CryptoContext)); + if(!ctx) + return CKR_HOST_MEMORY; + + ctx->mech_type = mech->mechanism; + + switch(mech->mechanism) + { + case CKM_RSA_PKCS: + ret = p11c_rsa_pkcs_decrypt_init(objdata, &ctx->mech_data); + ctx->mech_cleanup = p11c_rsa_pkcs_decrypt_cleanup; + break; + default: + ret = CKR_MECHANISM_INVALID; + break; + }; + + if(ret != CKR_OK) + { + free(ctx); + ASSERT(!sess->operation_data); + return ret; + } + + sess->operation_type = OPERATION_DECRYPT; + sess->operation_data = ctx; + sess->operation_cancel = cleanup_crypto_operation; + return CKR_OK; +} + +CK_RV +p11c_session_decrypt(P11cSession* sess, CK_BYTE_PTR encdata, CK_ULONG n_encdata, + CK_BYTE_PTR result, CK_ULONG_PTR n_result) +{ + CryptoContext *ctx; + BOOL incomplete; + CK_RV ret; + + ASSERT(sess); + ASSERT(encdata); + ASSERT(n_encdata); + + if(sess->operation_type != OPERATION_DECRYPT) + return CKR_OPERATION_NOT_INITIALIZED; + + ctx = (CryptoContext*)sess->operation_data; + switch(ctx->mech_type) + { + case CKM_RSA_PKCS: + ret = p11c_rsa_pkcs_decrypt_perform(encdata, n_encdata, result, n_result, + &ctx->mech_data); + break; + + default: + ASSERT(FALSE); + ret = CKR_GENERAL_ERROR; + break; + } + + /* Buffer calculation, we don't end operation */ + incomplete = (ret == CKR_BUFFER_TOO_SMALL || (ret == CKR_OK && !result)); + + if(!incomplete) + cleanup_crypto_operation(sess); + + return ret; +} -- cgit v1.2.3