diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c | 147 |
1 files changed, 100 insertions, 47 deletions
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c index db0cbec30..d61083626 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c @@ -18,6 +18,7 @@ #include <unistd.h> #include <debug.h> +#include <threading/mutex.h> #include "pkcs11_manager.h" @@ -52,6 +53,26 @@ struct private_pkcs11_hasher_t { * size of the hash */ 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, @@ -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: - case CKR_SESSION_HANDLE_INVALID: - case CKR_USER_NOT_LOGGED_IN: - case CKR_PIN_EXPIRED: - case CKR_OPERATION_NOT_INITIALIZED: - /* reopen session if we are in DigestInit? */ - case CKR_CRYPTOKI_NOT_INITIALIZED: - case CKR_ARGUMENTS_BAD: - case CKR_DEVICE_ERROR: - case CKR_DEVICE_REMOVED: - case CKR_GENERAL_ERROR: - case CKR_MECHANISM_INVALID: - case CKR_MECHANISM_PARAM_INVALID: - DBG1(DBG_CFG, "PKCS#11 hasher fatal error: %N", ck_rv_names, rv); - abort(); - break; - case CKR_FUNCTION_CANCELED: - case CKR_FUNCTION_FAILED: - case CKR_OPERATION_ACTIVE: - case CKR_HOST_MEMORY: - case CKR_DEVICE_MEMORY: - DBG1(DBG_CFG, "PKCS#11 hasher critical error: %N", ck_rv_names, rv); - sleep(1); - break; + if (!this->state) + { + rv = this->lib->f->C_GetOperationState(this->session, NULL, + &this->state_len); + if (rv != CKR_OK) + { + break; + } + this->state = malloc(this->state_len); + } + rv = this->lib->f->C_GetOperationState(this->session, this->state, + &this->state_len); + switch (rv) + { + case CKR_BUFFER_TOO_SMALL: + free(this->state); + this->state = NULL; + continue; + case CKR_OK: + this->have_state = TRUE; + return; + default: + break; + } + break; } + DBG1(DBG_CFG, "C_GetOperationState() failed: %N", ck_rv_names, rv); + abort(); } -METHOD(hasher_t, reset, void, - private_pkcs11_hasher_t *this) +/** + * Load the Operation state from host memory + */ +static void load_state(private_pkcs11_hasher_t *this) { CK_RV rv; - while ((rv = this->lib->f->C_DigestInit(this->session, - this->mech)) != CKR_OK) + rv = this->lib->f->C_SetOperationState(this->session, this->state, + this->state_len, CK_INVALID_HANDLE, CK_INVALID_HANDLE); + if (rv != CKR_OK) { - handle_error(this, rv); + DBG1(DBG_CFG, "C_SetOperationState() failed: %N", ck_rv_names, rv); + abort(); } + this->have_state = FALSE; +} + +METHOD(hasher_t, reset, void, + private_pkcs11_hasher_t *this) +{ + this->have_state = FALSE; } METHOD(hasher_t, get_hash, void, @@ -112,24 +149,45 @@ METHOD(hasher_t, get_hash, void, CK_RV rv; 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) { - while ((rv = this->lib->f->C_DigestUpdate(this->session, - chunk.ptr, chunk.len)) != CKR_OK) + rv = this->lib->f->C_DigestUpdate(this->session, chunk.ptr, chunk.len); + if (rv != CKR_OK) { - handle_error(this, rv); + DBG1(DBG_CFG, "C_DigestUpdate() failed: %N", ck_rv_names, rv); + abort(); } } if (hash) { len = this->size; - while ((rv = this->lib->f->C_DigestFinal(this->session, - hash, &len)) != CKR_OK) + rv = this->lib->f->C_DigestFinal(this->session, + 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, @@ -150,6 +208,7 @@ METHOD(hasher_t, destroy, void, private_pkcs11_hasher_t *this) { this->lib->f->C_CloseSession(this->session); + this->mutex->destroy(this->mutex); 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) { private_pkcs11_hasher_t *this; - CK_RV rv; INIT(this, .public.hasher = { @@ -249,6 +307,7 @@ pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo) .allocate_hash = _allocate_hash, .destroy = _destroy, }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); 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); 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; } |