Save/Load state of PKCS#11 hasher
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user