Save/Load state of PKCS#11 hasher

This commit is contained in:
Martin Willi
2010-08-04 09:26:22 +02:00
parent 83e52fd12d
commit 6e4f4d2fdf
+102 -49
View File
@@ -18,6 +18,7 @@
#include <unistd.h> #include <unistd.h>
#include <debug.h> #include <debug.h>
#include <threading/mutex.h>
#include "pkcs11_manager.h" #include "pkcs11_manager.h"
@@ -52,6 +53,26 @@ struct private_pkcs11_hasher_t {
* size of the hash * size of the hash
*/ */
size_t size; size_t size;
/**
* Mutex to lock the tokens hashing engine
*/
mutex_t *mutex;
/**
* do we have an initialized state?
*/
bool have_state;
/**
* state buffer
*/
CK_BYTE_PTR state;
/**
* Length of the state buffer
*/
CK_ULONG state_len;
}; };
METHOD(hasher_t, get_hash_size, size_t, METHOD(hasher_t, get_hash_size, size_t,
@@ -61,49 +82,65 @@ METHOD(hasher_t, get_hash_size, size_t,
} }
/** /**
* Try to handle errors * Save the Operation state to host memory
*/ */
static void handle_error(private_pkcs11_hasher_t *this, CK_RV rv) static void save_state(private_pkcs11_hasher_t *this)
{ {
switch (rv) CK_RV rv;
while (TRUE)
{ {
case CKR_SESSION_CLOSED: if (!this->state)
case CKR_SESSION_HANDLE_INVALID: {
case CKR_USER_NOT_LOGGED_IN: rv = this->lib->f->C_GetOperationState(this->session, NULL,
case CKR_PIN_EXPIRED: &this->state_len);
case CKR_OPERATION_NOT_INITIALIZED: if (rv != CKR_OK)
/* reopen session if we are in DigestInit? */ {
case CKR_CRYPTOKI_NOT_INITIALIZED: break;
case CKR_ARGUMENTS_BAD: }
case CKR_DEVICE_ERROR: this->state = malloc(this->state_len);
case CKR_DEVICE_REMOVED: }
case CKR_GENERAL_ERROR: rv = this->lib->f->C_GetOperationState(this->session, this->state,
case CKR_MECHANISM_INVALID: &this->state_len);
case CKR_MECHANISM_PARAM_INVALID: switch (rv)
DBG1(DBG_CFG, "PKCS#11 hasher fatal error: %N", ck_rv_names, rv); {
abort(); case CKR_BUFFER_TOO_SMALL:
break; free(this->state);
case CKR_FUNCTION_CANCELED: this->state = NULL;
case CKR_FUNCTION_FAILED: continue;
case CKR_OPERATION_ACTIVE: case CKR_OK:
case CKR_HOST_MEMORY: this->have_state = TRUE;
case CKR_DEVICE_MEMORY: return;
DBG1(DBG_CFG, "PKCS#11 hasher critical error: %N", ck_rv_names, rv); default:
sleep(1); break;
break; }
break;
} }
DBG1(DBG_CFG, "C_GetOperationState() failed: %N", ck_rv_names, rv);
abort();
}
/**
* Load the Operation state from host memory
*/
static void load_state(private_pkcs11_hasher_t *this)
{
CK_RV rv;
rv = this->lib->f->C_SetOperationState(this->session, this->state,
this->state_len, CK_INVALID_HANDLE, CK_INVALID_HANDLE);
if (rv != CKR_OK)
{
DBG1(DBG_CFG, "C_SetOperationState() failed: %N", ck_rv_names, rv);
abort();
}
this->have_state = FALSE;
} }
METHOD(hasher_t, reset, void, METHOD(hasher_t, reset, void,
private_pkcs11_hasher_t *this) private_pkcs11_hasher_t *this)
{ {
CK_RV rv; this->have_state = FALSE;
while ((rv = this->lib->f->C_DigestInit(this->session,
this->mech)) != CKR_OK)
{
handle_error(this, rv);
}
} }
METHOD(hasher_t, get_hash, void, METHOD(hasher_t, get_hash, void,
@@ -112,24 +149,45 @@ METHOD(hasher_t, get_hash, void,
CK_RV rv; CK_RV rv;
CK_ULONG len; CK_ULONG len;
this->mutex->lock(this->mutex);
if (this->have_state)
{
load_state(this);
}
else
{
rv = this->lib->f->C_DigestInit(this->session, this->mech);
if (rv != CKR_OK)
{
DBG1(DBG_CFG, "C_DigestInit() failed: %N", ck_rv_names, rv);
abort();
}
}
if (chunk.len) if (chunk.len)
{ {
while ((rv = this->lib->f->C_DigestUpdate(this->session, rv = this->lib->f->C_DigestUpdate(this->session, chunk.ptr, chunk.len);
chunk.ptr, chunk.len)) != CKR_OK) if (rv != CKR_OK)
{ {
handle_error(this, rv); DBG1(DBG_CFG, "C_DigestUpdate() failed: %N", ck_rv_names, rv);
abort();
} }
} }
if (hash) if (hash)
{ {
len = this->size; len = this->size;
while ((rv = this->lib->f->C_DigestFinal(this->session, rv = this->lib->f->C_DigestFinal(this->session,
hash, &len)) != CKR_OK) hash, &len);
if (rv != CKR_OK)
{ {
handle_error(this, rv); DBG1(DBG_CFG, "C_DigestFinal() failed: %N", ck_rv_names, rv);
abort();
} }
reset(this);
} }
else
{
save_state(this);
}
this->mutex->unlock(this->mutex);
} }
METHOD(hasher_t, allocate_hash, void, METHOD(hasher_t, allocate_hash, void,
@@ -150,6 +208,7 @@ METHOD(hasher_t, destroy, void,
private_pkcs11_hasher_t *this) private_pkcs11_hasher_t *this)
{ {
this->lib->f->C_CloseSession(this->session); this->lib->f->C_CloseSession(this->session);
this->mutex->destroy(this->mutex);
free(this); free(this);
} }
@@ -239,7 +298,6 @@ static pkcs11_library_t* find_token(hash_algorithm_t algo,
pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo) pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo)
{ {
private_pkcs11_hasher_t *this; private_pkcs11_hasher_t *this;
CK_RV rv;
INIT(this, INIT(this,
.public.hasher = { .public.hasher = {
@@ -249,6 +307,7 @@ pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo)
.allocate_hash = _allocate_hash, .allocate_hash = _allocate_hash,
.destroy = _destroy, .destroy = _destroy,
}, },
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
); );
this->lib = find_token(algo, &this->session, &this->mech, &this->size); this->lib = find_token(algo, &this->session, &this->mech, &this->size);
@@ -257,12 +316,6 @@ pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo)
free(this); free(this);
return NULL; return NULL;
} }
rv = this->lib->f->C_DigestInit(this->session, this->mech);
if (rv != CKR_OK)
{
DBG1(DBG_CFG, "C_DigestInit() failed: %N", ck_rv_names, rv);
destroy(this);
return NULL;
}
return &this->public; return &this->public;
} }