diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-11-28 11:42:20 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2010-11-28 11:42:20 +0000 |
commit | f73fba54dc8b30c6482e1e8abf15bbf455592fcd (patch) | |
tree | a449515607c5e51a5c703d7a9b1149c9e4a11560 /src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c | |
parent | b8064f4099997a9e2179f3ad4ace605f5ccac3a1 (diff) | |
download | vyos-strongswan-f73fba54dc8b30c6482e1e8abf15bbf455592fcd.tar.gz vyos-strongswan-f73fba54dc8b30c6482e1e8abf15bbf455592fcd.zip |
[svn-upgrade] new version strongswan (4.5.0)
Diffstat (limited to 'src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c')
-rw-r--r-- | src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c new file mode 100644 index 000000000..6d327be40 --- /dev/null +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program 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 General Public License + * for more details. + */ + +#include "pkcs11_hasher.h" + +#include <unistd.h> + +#include <debug.h> +#include <threading/mutex.h> + +#include "pkcs11_manager.h" + +typedef struct private_pkcs11_hasher_t private_pkcs11_hasher_t; + +/** + * Private data of an pkcs11_hasher_t object. + */ +struct private_pkcs11_hasher_t { + + /** + * Public pkcs11_hasher_t interface. + */ + pkcs11_hasher_t public; + + /** + * PKCS#11 library + */ + pkcs11_library_t *lib; + + /** + * Mechanism for this hasher + */ + CK_MECHANISM_PTR mech; + + /** + * Token session + */ + CK_SESSION_HANDLE session; + + /** + * 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, + private_pkcs11_hasher_t *this) +{ + return this->size; +} + +/** + * Save the Operation state to host memory + */ +static void save_state(private_pkcs11_hasher_t *this) +{ + CK_RV rv; + + while (TRUE) + { + 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(); +} + +/** + * 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, + private_pkcs11_hasher_t *this) +{ + this->have_state = FALSE; +} + +METHOD(hasher_t, get_hash, void, + private_pkcs11_hasher_t *this, chunk_t chunk, u_int8_t *hash) +{ + 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) + { + rv = this->lib->f->C_DigestUpdate(this->session, chunk.ptr, chunk.len); + if (rv != CKR_OK) + { + DBG1(DBG_CFG, "C_DigestUpdate() failed: %N", ck_rv_names, rv); + abort(); + } + } + if (hash) + { + len = this->size; + rv = this->lib->f->C_DigestFinal(this->session, + hash, &len); + if (rv != CKR_OK) + { + DBG1(DBG_CFG, "C_DigestFinal() failed: %N", ck_rv_names, rv); + abort(); + } + } + else + { + save_state(this); + } + this->mutex->unlock(this->mutex); +} + +METHOD(hasher_t, allocate_hash, void, + private_pkcs11_hasher_t *this, chunk_t chunk, chunk_t *hash) +{ + if (hash) + { + *hash = chunk_alloc(this->size); + get_hash(this, chunk, hash->ptr); + } + else + { + get_hash(this, chunk, NULL); + } +} + +METHOD(hasher_t, destroy, void, + private_pkcs11_hasher_t *this) +{ + this->lib->f->C_CloseSession(this->session); + this->mutex->destroy(this->mutex); + free(this); +} + +/** + * Get the Cryptoki mechanism for a hash algorithm + */ +static CK_MECHANISM_PTR algo_to_mechanism(hash_algorithm_t algo, size_t *size) +{ + static struct { + hash_algorithm_t algo; + CK_MECHANISM mechanism; + size_t size; + } mappings[] = { + {HASH_MD2, {CKM_MD2, NULL, 0}, HASH_SIZE_MD2}, + {HASH_MD5, {CKM_MD5, NULL, 0}, HASH_SIZE_MD5}, + {HASH_SHA1, {CKM_SHA_1, NULL, 0}, HASH_SIZE_SHA1}, + {HASH_SHA256, {CKM_SHA256, NULL, 0}, HASH_SIZE_SHA256}, + {HASH_SHA384, {CKM_SHA384, NULL, 0}, HASH_SIZE_SHA384}, + {HASH_SHA512, {CKM_SHA512, NULL, 0}, HASH_SIZE_SHA512}, + }; + int i; + + for (i = 0; i < countof(mappings); i++) + { + if (mappings[i].algo == algo) + { + *size = mappings[i].size; + return &mappings[i].mechanism; + } + } + return NULL; +} + +/** + * Find a token we can use for a hash algorithm + */ +static pkcs11_library_t* find_token(hash_algorithm_t algo, + CK_SESSION_HANDLE *session, CK_MECHANISM_PTR *mout, size_t *size) +{ + enumerator_t *tokens, *mechs; + pkcs11_manager_t *manager; + pkcs11_library_t *current, *found = NULL; + CK_MECHANISM_TYPE type; + CK_MECHANISM_PTR mech; + CK_SLOT_ID slot; + + mech = algo_to_mechanism(algo, size); + if (!mech) + { + return NULL; + } + manager = pkcs11_manager_get(); + if (!manager) + { + return NULL; + } + tokens = manager->create_token_enumerator(manager); + while (tokens->enumerate(tokens, ¤t, &slot)) + { + mechs = current->create_mechanism_enumerator(current, slot); + while (mechs->enumerate(mechs, &type, NULL)) + { + if (type == mech->mechanism) + { + if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION, + NULL, NULL, session) == CKR_OK) + { + found = current; + *mout = mech; + break; + } + } + } + mechs->destroy(mechs); + if (found) + { + break; + } + } + tokens->destroy(tokens); + return found; +} + +/** + * See header + */ +pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo) +{ + private_pkcs11_hasher_t *this; + + INIT(this, + .public = { + .hasher = { + .get_hash_size = _get_hash_size, + .reset = _reset, + .get_hash = _get_hash, + .allocate_hash = _allocate_hash, + .destroy = _destroy, + }, + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + + this->lib = find_token(algo, &this->session, &this->mech, &this->size); + if (!this->lib) + { + free(this); + return NULL; + } + + return &this->public; +} |