summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/pkcs11/pkcs11_rng.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/pkcs11/pkcs11_rng.c')
-rw-r--r--src/libstrongswan/plugins/pkcs11/pkcs11_rng.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_rng.c b/src/libstrongswan/plugins/pkcs11/pkcs11_rng.c
new file mode 100644
index 000000000..45cf0b7c2
--- /dev/null
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_rng.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2011 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
+ * 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_rng.h"
+
+#include <debug.h>
+
+#include "pkcs11_manager.h"
+
+typedef struct private_pkcs11_rng_t private_pkcs11_rng_t;
+
+/**
+ * Private data of an pkcs11_rng_t object.
+ */
+struct private_pkcs11_rng_t {
+
+ /**
+ * Public interface.
+ */
+ pkcs11_rng_t public;
+
+ /**
+ * PKCS#11 library
+ */
+ pkcs11_library_t *lib;
+
+ /**
+ * Mechanism for this rng
+ */
+ CK_SESSION_HANDLE session;
+
+};
+
+METHOD(rng_t, get_bytes, void,
+ private_pkcs11_rng_t *this, size_t bytes, u_int8_t *buffer)
+{
+ CK_RV rv;
+ rv = this->lib->f->C_GenerateRandom(this->session, buffer, bytes);
+ if (rv != CKR_OK)
+ {
+ DBG1(DBG_CFG, "C_GenerateRandom() failed: %N", ck_rv_names, rv);
+ abort();
+ }
+}
+
+METHOD(rng_t, allocate_bytes, void,
+ private_pkcs11_rng_t *this, size_t bytes, chunk_t *chunk)
+{
+ *chunk = chunk_alloc(bytes);
+ get_bytes(this, chunk->len, chunk->ptr);
+}
+
+METHOD(rng_t, destroy, void,
+ private_pkcs11_rng_t *this)
+{
+ this->lib->f->C_CloseSession(this->session);
+ free(this);
+}
+
+/**
+ * Find a token with its own RNG
+ */
+static pkcs11_library_t *find_token(CK_SESSION_HANDLE *session)
+{
+ enumerator_t *tokens;
+ pkcs11_manager_t *manager;
+ pkcs11_library_t *current, *found = NULL;
+ CK_SLOT_ID slot;
+
+ manager = lib->get(lib, "pkcs11-manager");
+ if (!manager)
+ {
+ return NULL;
+ }
+ tokens = manager->create_token_enumerator(manager);
+ while (tokens->enumerate(tokens, &current, &slot))
+ {
+ CK_TOKEN_INFO info;
+ CK_RV rv;
+ rv = current->f->C_GetTokenInfo(slot, &info);
+ if (rv != CKR_OK)
+ {
+ continue;
+ }
+ if (info.flags & CKF_RNG)
+ {
+ if (current->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
+ NULL, NULL, session) == CKR_OK)
+ {
+ found = current;
+ break;
+ }
+ }
+ }
+ tokens->destroy(tokens);
+ return found;
+}
+
+/*
+ * Described in header.
+ */
+pkcs11_rng_t *pkcs11_rng_create(rng_quality_t quality)
+{
+ private_pkcs11_rng_t *this;
+
+ INIT(this,
+ .public = {
+ .rng = {
+ .get_bytes = _get_bytes,
+ .allocate_bytes = _allocate_bytes,
+ .destroy = _destroy,
+ },
+ },
+ );
+
+ this->lib = find_token(&this->session);
+ if (!this->lib)
+ {
+ free(this);
+ return NULL;
+ }
+
+ return &this->public;
+}
+