aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libstrongswan/plugins/pkcs11/Makefile.am1
-rw-r--r--src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c268
-rw-r--r--src/libstrongswan/plugins/pkcs11/pkcs11_hasher.h47
-rw-r--r--src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c20
4 files changed, 336 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/pkcs11/Makefile.am b/src/libstrongswan/plugins/pkcs11/Makefile.am
index 44f5d085e..8da6a25d4 100644
--- a/src/libstrongswan/plugins/pkcs11/Makefile.am
+++ b/src/libstrongswan/plugins/pkcs11/Makefile.am
@@ -15,6 +15,7 @@ libstrongswan_pkcs11_la_SOURCES = \
pkcs11_library.h pkcs11_library.c \
pkcs11_creds.h pkcs11_creds.c \
pkcs11_private_key.h pkcs11_private_key.c \
+ pkcs11_hasher.h pkcs11_hasher.c \
pkcs11_manager.h pkcs11_manager.c
libstrongswan_pkcs11_la_LDFLAGS = -module -avoid-version
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c
new file mode 100644
index 000000000..db0cbec30
--- /dev/null
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c
@@ -0,0 +1,268 @@
+/*
+ * 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 "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;
+};
+
+METHOD(hasher_t, get_hash_size, size_t,
+ private_pkcs11_hasher_t *this)
+{
+ return this->size;
+}
+
+/**
+ * Try to handle errors
+ */
+static void handle_error(private_pkcs11_hasher_t *this, CK_RV rv)
+{
+ switch (rv)
+ {
+ 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;
+ }
+}
+
+METHOD(hasher_t, reset, void,
+ private_pkcs11_hasher_t *this)
+{
+ CK_RV rv;
+
+ while ((rv = this->lib->f->C_DigestInit(this->session,
+ this->mech)) != CKR_OK)
+ {
+ handle_error(this, rv);
+ }
+}
+
+METHOD(hasher_t, get_hash, void,
+ private_pkcs11_hasher_t *this, chunk_t chunk, u_int8_t *hash)
+{
+ CK_RV rv;
+ CK_ULONG len;
+
+ if (chunk.len)
+ {
+ while ((rv = this->lib->f->C_DigestUpdate(this->session,
+ chunk.ptr, chunk.len)) != CKR_OK)
+ {
+ handle_error(this, rv);
+ }
+ }
+ if (hash)
+ {
+ len = this->size;
+ while ((rv = this->lib->f->C_DigestFinal(this->session,
+ hash, &len)) != CKR_OK)
+ {
+ handle_error(this, rv);
+ }
+ reset(this);
+ }
+}
+
+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);
+ 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, &current, &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;
+ CK_RV rv;
+
+ INIT(this,
+ .public.hasher = {
+ .get_hash_size = _get_hash_size,
+ .reset = _reset,
+ .get_hash = _get_hash,
+ .allocate_hash = _allocate_hash,
+ .destroy = _destroy,
+ },
+ );
+
+ this->lib = find_token(algo, &this->session, &this->mech, &this->size);
+ if (!this->lib)
+ {
+ 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;
+}
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.h b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.h
new file mode 100644
index 000000000..9c55d463e
--- /dev/null
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup pkcs11_hasher pkcs11_hasher
+ * @{ @ingroup pkcs11
+ */
+
+#ifndef PKCS11_HASHER_H_
+#define PKCS11_HASHER_H_
+
+#include <crypto/hashers/hasher.h>
+
+typedef struct pkcs11_hasher_t pkcs11_hasher_t;
+
+/**
+ * Hash implementation using a PKCS#11 token.
+ */
+struct pkcs11_hasher_t {
+
+ /**
+ * Implements hasher_t interface.
+ */
+ hasher_t hasher;
+};
+
+/**
+ * Creates a PKCS#11 based hasher.
+ *
+ * @param algo hash algorithm
+ * @return hasher, NULL if not supported
+ */
+pkcs11_hasher_t *pkcs11_hasher_create(hash_algorithm_t algo);
+
+#endif /** PKCS11_HASHER_H_ @}*/
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c b/src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c
index e083af548..68e3076e2 100644
--- a/src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_plugin.c
@@ -23,6 +23,7 @@
#include "pkcs11_manager.h"
#include "pkcs11_creds.h"
#include "pkcs11_private_key.h"
+#include "pkcs11_hasher.h"
typedef struct private_pkcs11_plugin_t private_pkcs11_plugin_t;
@@ -111,6 +112,8 @@ METHOD(plugin_t, destroy, void,
lib->credmgr->remove_set(lib->credmgr, &creds->set);
creds->destroy(creds);
}
+ lib->crypto->remove_hasher(lib->crypto,
+ (hasher_constructor_t)pkcs11_hasher_create);
this->creds->destroy(this->creds);
this->manager->destroy(this->manager);
this->mutex->destroy(this->mutex);
@@ -130,6 +133,23 @@ plugin_t *pkcs11_plugin_create()
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
);
+ if (lib->settings->get_bool(lib->settings,
+ "libstrongswan.plugins.pkcs11.use_hasher", FALSE))
+ {
+ lib->crypto->add_hasher(lib->crypto, HASH_MD2,
+ (hasher_constructor_t)pkcs11_hasher_create);
+ lib->crypto->add_hasher(lib->crypto, HASH_MD5,
+ (hasher_constructor_t)pkcs11_hasher_create);
+ lib->crypto->add_hasher(lib->crypto, HASH_SHA1,
+ (hasher_constructor_t)pkcs11_hasher_create);
+ lib->crypto->add_hasher(lib->crypto, HASH_SHA256,
+ (hasher_constructor_t)pkcs11_hasher_create);
+ lib->crypto->add_hasher(lib->crypto, HASH_SHA384,
+ (hasher_constructor_t)pkcs11_hasher_create);
+ lib->crypto->add_hasher(lib->crypto, HASH_SHA512,
+ (hasher_constructor_t)pkcs11_hasher_create);
+ }
+
this->manager = pkcs11_manager_create((void*)token_event_cb, this);
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,