summaryrefslogtreecommitdiff
path: root/p11-kit
diff options
context:
space:
mode:
Diffstat (limited to 'p11-kit')
-rw-r--r--p11-kit/Makefile.am7
-rw-r--r--p11-kit/deprecated.h97
-rw-r--r--p11-kit/docs.h38
-rw-r--r--p11-kit/modules.c1366
-rw-r--r--p11-kit/modules.h51
-rw-r--r--p11-kit/p11-kit.h63
-rw-r--r--p11-kit/private.h6
-rw-r--r--p11-kit/proxy.c231
-rw-r--r--p11-kit/tests/Makefile.am10
-rw-r--r--p11-kit/tests/files/system-pkcs11.conf5
-rw-r--r--p11-kit/tests/files/user-modules/one.module3
-rw-r--r--p11-kit/tests/test-deprecated.c521
-rw-r--r--p11-kit/tests/test-init.c176
-rw-r--r--p11-kit/tests/test-iter.c72
-rw-r--r--p11-kit/tests/test-managed.c168
-rw-r--r--p11-kit/tests/test-mock.c1687
-rw-r--r--p11-kit/tests/test-modules.c124
-rw-r--r--p11-kit/tests/test-proxy.c94
18 files changed, 4355 insertions, 364 deletions
diff --git a/p11-kit/Makefile.am b/p11-kit/Makefile.am
index 027b7c8..d7e1694 100644
--- a/p11-kit/Makefile.am
+++ b/p11-kit/Makefile.am
@@ -14,6 +14,7 @@ INCLUDES = \
incdir = $(includedir)/p11-kit-1/p11-kit
inc_HEADERS = \
+ deprecated.h \
iter.h \
p11-kit.h \
pin.h \
@@ -24,7 +25,7 @@ MODULE_SRCS = \
util.c \
conf.c conf.h \
iter.c \
- modules.c \
+ modules.c modules.h \
pkcs11.h \
pin.c \
pkcs11.h \
@@ -103,7 +104,9 @@ example_DATA = pkcs11.conf.example
EXTRA_DIST = \
p11-kit-1.pc.in \
- pkcs11.conf.example.in
+ pkcs11.conf.example.in \
+ docs.h \
+ $(NULL)
# Proxy module is actually same as library, so install a link
install-exec-hook:
diff --git a/p11-kit/deprecated.h b/p11-kit/deprecated.h
new file mode 100644
index 0000000..ffe5d9d
--- /dev/null
+++ b/p11-kit/deprecated.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+#ifndef __P11_KIT_DEPRECATED_H__
+#define __P11_KIT_DEPRECATED_H__
+
+#ifndef __P11_KIT_H__
+#error "Please include <p11-kit/p11-kit.h> instead of this file."
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef P11_KIT_NO_DEPRECATIONS
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define P11_KIT_DEPRECATED_FOR(f) __attribute__((deprecated("Use " #f " instead")))
+#elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#define P11_KIT_DEPRECATED_FOR(f) __attribute__((__deprecated__))
+#endif
+#endif
+
+#ifndef P11_KIT_DEPRECATED_FOR
+#define P11_KIT_DEPRECATED_FOR(f)
+#endif
+
+#ifndef P11_KIT_DISABLE_DEPRECATED
+
+P11_KIT_DEPRECATED_FOR (p11_kit_modules_load)
+CK_RV p11_kit_initialize_registered (void);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_modules_release)
+CK_RV p11_kit_finalize_registered (void);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_modules_release)
+CK_FUNCTION_LIST_PTR * p11_kit_registered_modules (void);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_module_for_name)
+CK_FUNCTION_LIST_PTR p11_kit_registered_name_to_module (const char *name);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_module_get_name)
+char * p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_config_option)
+char * p11_kit_registered_option (CK_FUNCTION_LIST_PTR module,
+ const char *field);
+
+P11_KIT_DEPRECATED_FOR (module->C_Initialize)
+CK_RV p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module);
+
+P11_KIT_DEPRECATED_FOR (module->C_Finalize)
+CK_RV p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module);
+
+P11_KIT_DEPRECATED_FOR (p11_kit_module_load)
+CK_RV p11_kit_load_initialize_module (const char *module_path,
+ CK_FUNCTION_LIST_PTR *module);
+
+#endif /* P11_KIT_DISABLE_DEPRECATED */
+
+#undef P11_KIT_DEPRECATED_FOR
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __P11_KIT_DEPRECATED_H__ */
diff --git a/p11-kit/docs.h b/p11-kit/docs.h
new file mode 100644
index 0000000..7b29e3d
--- /dev/null
+++ b/p11-kit/docs.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+/* This header is not used by anything, and merely to help gtk-doc be sane */
+
+#define P11_KIT_MODULE_UNMANAGED 1
+#define P11_KIT_MODULE_CRITICAL 1
diff --git a/p11-kit/modules.c b/p11-kit/modules.c
index e62a43c..c6f1bee 100644
--- a/p11-kit/modules.c
+++ b/p11-kit/modules.c
@@ -35,16 +35,21 @@
#include "config.h"
-#include "conf.h"
+/* We use and define deprecated functions here */
+#define P11_KIT_NO_DEPRECATIONS
#define P11_DEBUG_FLAG P11_DEBUG_LIB
+
+#include "conf.h"
#include "debug.h"
#include "dict.h"
#include "library.h"
#include "message.h"
+#include "modules.h"
#include "path.h"
#include "pkcs11.h"
#include "p11-kit.h"
#include "private.h"
+#include "virtual.h"
#include <sys/stat.h>
#include <sys/types.h>
@@ -70,44 +75,90 @@
* crypto objects (like keys and certificates) and to perform crypto operations.
*
* In order for applications to behave consistently with regard to the user's
- * installed PKCS\#11 modules, each module must be registered so that applications
+ * installed PKCS\#11 modules, each module must be configured so that applications
* or libraries know that they should load it.
*
- * The functions here provide support for initializing registered modules. The
- * p11_kit_initialize_registered() function should be used to load and initialize
- * the registered modules. When done, the p11_kit_finalize_registered() function
+ * When multiple consumers of a module (such as libraries or applications) are
+ * in the same process, coordination of the initialization and finalization
+ * of PKCS\#11 modules is required. To do this modules are managed by p11-kit.
+ * This means that various unsafe methods are coordinated between callers. Unmanaged
+ * modules are simply the raw PKCS\#11 module pointers without p11-kit getting in the
+ * way. It is highly recommended that the default managed behavior is used.
+ *
+ * The functions here provide support for initializing configured modules. The
+ * p11_kit_modules_load() function should be used to load and initialize
+ * the configured modules. When done, the p11_kit_modules_release() function
* should be used to release those modules and associated resources.
*
- * In addition p11_kit_registered_option() can be used to access other parts
+ * In addition p11_kit_config_option() can be used to access other parts
* of the module configuration.
*
- * When multiple consumers of a module (such as libraries or applications) are
- * in the same process, coordination of the initialization and finalization
- * of PKCS\#11 modules is required. The functions here automatically provide
- * initialization reference counting to make this work.
- *
* If a consumer wishes to load an arbitrary PKCS\#11 module that's not
- * registered, that module should be initialized with p11_kit_initialize_module()
- * and finalized with p11_kit_finalize_module(). The module's own
- * <code>C_Initialize</code> and <code>C_Finalize</code> methods should not
- * be called directly.
+ * configured use p11_kit_module_load() to do so. And use p11_kit_module_release()
+ * to later release it.
*
* Modules are represented by a pointer to their <code>CK_FUNCTION_LIST</code>
- * entry points. This means that callers can load modules elsewhere, using
- * dlopen() for example, and then still use these methods on them.
+ * entry points.
+ */
+
+/**
+ * SECTION:p11-kit-deprecated
+ * @title: Deprecated
+ * @short_description: Deprecated functions
+ *
+ * These functions have been deprecated from p11-kit and are not recommended for
+ * general usage. In large part they were deprecated because they did not adequately
+ * insulate multiple callers of a PKCS\#11 module from another, and could not
+ * support the 'managed' mode needed to do this.
+ */
+
+/**
+ * P11_KIT_MODULE_UNMANAGED:
+ *
+ * Module is loaded in non 'managed' mode. This is not recommended,
+ * disables many features, and prevents coordination between multiple
+ * callers of the same module.
+ */
+
+/**
+ * P11_KIT_MODULE_CRITICAL:
+ *
+ * Flag to load a module in 'critical' mode. Failure to load a critical module
+ * will prevent all other modules from loading. A failure when loading a
+ * non-critical module skips that module.
*/
typedef struct _Module {
- CK_FUNCTION_LIST_PTR funcs;
+ /*
+ * When using managed modules, this forms the base of the
+ * virtual stack into which all the other modules call. This is also
+ * the first field in this structure so we can cast between them.
+ */
+ p11_virtual virt;
+
+ /*
+ * The actual function pointers retrieved from the module. This is
+ * not necessarily populated. For non dl modules, such as rpc
+ * modules, this will be NULL.
+ */
+ CK_FUNCTION_LIST *funcs;
+
+ /* The initialize args built from configuration */
CK_C_INITIALIZE_ARGS init_args;
int ref_count;
+ int init_count;
/* Registered modules */
char *name;
p11_dict *config;
+ bool critical;
- /* Loaded modules */
- dl_module_t dl_module;
+ /*
+ * This is a pointer to the actual dl shared module, or perhaps
+ * the RPC client context.
+ */
+ void *loaded_module;
+ p11_kit_destroyer loaded_destroy;
/* Initialization, mutex must be held */
p11_mutex_t initialize_mutex;
@@ -115,12 +166,18 @@ typedef struct _Module {
p11_thread_id_t initialize_thread;
} Module;
+typedef struct {
+ p11_virtual virt;
+ Module *mod;
+} Managed;
+
/*
* Shared data between threads, protected by the mutex, a structure so
* we can audit thread safety easier.
*/
static struct _Shared {
p11_dict *modules;
+ p11_dict *managed;
p11_dict *config;
} gl = { NULL, NULL };
@@ -184,15 +241,19 @@ free_module_unlocked (void *data)
assert (mod != NULL);
- /* Module must be finalized */
- assert (!mod->initialize_called);
- assert (mod->initialize_thread == 0);
-
/* Module must have no outstanding references */
assert (mod->ref_count == 0);
- if (mod->dl_module)
- p11_dl_close (mod->dl_module);
+ if (mod->init_count > 0) {
+ p11_debug_precond ("module unloaded without C_Finalize having been "
+ "called for each C_Initialize");
+ } else {
+ assert (!mod->initialize_called);
+ assert (mod->initialize_thread == 0);
+ }
+
+ if (mod->loaded_destroy)
+ mod->loaded_destroy (mod->loaded_module);
p11_mutex_uninit (&mod->initialize_mutex);
p11_dict_free (mod->config);
@@ -215,28 +276,50 @@ alloc_module_unlocked (void)
mod->init_args.flags = CKF_OS_LOCKING_OK;
p11_mutex_init (&mod->initialize_mutex);
+ /*
+ * The default for configured modules is non-critical, but for
+ * modules loaded explicitly, and not from config, we treat them
+ * as critical. So this gets overridden for configured modules
+ * later when the config is loaded.
+ */
+ mod->critical = true;
+
return mod;
}
+static void
+module_setup_with_functions (Module *mod,
+ CK_FUNCTION_LIST *funcs)
+{
+ mod->funcs = funcs;
+ p11_virtual_init (&mod->virt, &p11_virtual_base, funcs, NULL);
+}
+
static CK_RV
dlopen_and_get_function_list (Module *mod, const char *path)
{
+ CK_FUNCTION_LIST *funcs;
CK_C_GetFunctionList gfl;
+ dl_module_t dl;
char *error;
CK_RV rv;
- assert (mod);
- assert (path);
+ assert (mod != NULL);
+ assert (path != NULL);
- mod->dl_module = p11_dl_open (path);
- if (mod->dl_module == NULL) {
+ dl = p11_dl_open (path);
+ if (dl == NULL) {
error = p11_dl_error ();
p11_message ("couldn't load module: %s: %s", path, error);
free (error);
return CKR_GENERAL_ERROR;
}
- gfl = p11_dl_symbol (mod->dl_module, "C_GetFunctionList");
+ /* When the Module goes away, dlclose the loaded module */
+ mod->loaded_destroy = (p11_kit_destroyer)p11_dl_close;
+ mod->loaded_module = dl;
+
+ gfl = p11_dl_symbol (dl, "C_GetFunctionList");
if (!gfl) {
error = p11_dl_error ();
p11_message ("couldn't find C_GetFunctionList entry point in module: %s: %s",
@@ -245,13 +328,19 @@ dlopen_and_get_function_list (Module *mod, const char *path)
return CKR_GENERAL_ERROR;
}
- rv = gfl (&mod->funcs);
+ rv = gfl (&funcs);
if (rv != CKR_OK) {
p11_message ("call to C_GetFunctiontList failed in module: %s: %s",
path, p11_kit_strerror (rv));
return rv;
}
+ if (mod->funcs == &_p11_proxy_function_list) {
+ p11_message ("refusing to load the p11-kit-proxy.so module as a registered module");
+ return CKR_FUNCTION_FAILED;
+ }
+
+ module_setup_with_functions (mod, funcs);
p11_debug ("opened module: %s", path);
return CKR_OK;
}
@@ -273,6 +362,7 @@ load_module_from_file_unlocked (const char *path, Module **result)
}
/* Do we have a previous one like this, if so ignore load */
+ assert (mod->funcs != NULL);
prev = p11_dict_get (gl.modules, mod->funcs);
if (prev != NULL) {
@@ -360,8 +450,9 @@ is_module_enabled_unlocked (const char *name,
}
static CK_RV
-take_config_and_load_module_unlocked (char **name,
- p11_dict **config)
+take_config_and_load_module_inlock (char **name,
+ p11_dict **config,
+ bool critical)
{
Module *mod, *prev;
const char *module_filename;
@@ -401,6 +492,7 @@ take_config_and_load_module_unlocked (char **name,
*config = NULL;
mod->name = *name;
*name = NULL;
+ mod->critical = critical;
rv = dlopen_and_get_function_list (mod, path);
if (rv != CKR_OK) {
@@ -415,6 +507,7 @@ take_config_and_load_module_unlocked (char **name,
*/
mod->init_args.pReserved = p11_dict_get (mod->config, "x-init-reserved");
+ assert (mod->funcs != NULL);
prev = p11_dict_get (gl.modules, mod->funcs);
/* If same module was loaded previously, just take over config */
@@ -485,8 +578,7 @@ load_registered_modules_unlocked (void)
/* Is this a critical module, should abort loading of others? */
critical = _p11_conf_parse_boolean (p11_dict_get (config, "critical"), false);
-
- rv = take_config_and_load_module_unlocked (&name, &config);
+ rv = take_config_and_load_module_inlock (&name, &config, critical);
/*
* These variables will be cleared if ownership is transeferred
@@ -510,10 +602,11 @@ load_registered_modules_unlocked (void)
}
static CK_RV
-initialize_module_unlocked_reentrant (Module *mod)
+initialize_module_inlock_reentrant (Module *mod)
{
CK_RV rv = CKR_OK;
p11_thread_id_t self;
+
assert (mod);
self = p11_thread_id_self ();
@@ -535,19 +628,12 @@ initialize_module_unlocked_reentrant (Module *mod)
p11_mutex_lock (&mod->initialize_mutex);
if (!mod->initialize_called) {
- assert (mod->funcs);
+ p11_debug ("C_Initialize: calling");
- if (mod->funcs == &_p11_proxy_function_list) {
- p11_message ("refusing to load the p11-kit-proxy.so module as a registered module");
- rv = CKR_FUNCTION_FAILED;
-
- } else {
- p11_debug ("C_Initialize: calling");
+ rv = mod->virt.funcs.C_Initialize (&mod->virt.funcs,
+ &mod->init_args);
- rv = mod->funcs->C_Initialize (&mod->init_args);
-
- p11_debug ("C_Initialize: result: %lu", rv);
- }
+ p11_debug ("C_Initialize: result: %lu", rv);
/* Module was initialized and C_Finalize should be called */
if (rv == CKR_OK)
@@ -561,10 +647,14 @@ initialize_module_unlocked_reentrant (Module *mod)
p11_mutex_unlock (&mod->initialize_mutex);
p11_lock ();
- /* Don't claim reference if failed */
- if (rv != CKR_OK)
- --mod->ref_count;
+ if (rv == CKR_OK) {
+ /* Matches the ref count in finalize_module_inlock_reentrant() */
+ if (mod->init_count == 0)
+ mod->ref_count++;
+ mod->init_count++;
+ }
+ mod->ref_count--;
mod->initialize_thread = 0;
return rv;
}
@@ -605,6 +695,11 @@ init_globals_unlocked (void)
return_val_if_fail (gl.modules != NULL, CKR_HOST_MEMORY);
}
+ if (!gl.managed) {
+ gl.managed = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, NULL, NULL);
+ return_val_if_fail (gl.managed != NULL, CKR_HOST_MEMORY);
+ }
+
if (once)
return CKR_OK;
@@ -631,12 +726,14 @@ free_modules_when_no_refs_unlocked (void)
p11_dict_free (gl.modules);
gl.modules = NULL;
+ p11_dict_free (gl.managed);
+ gl.managed = NULL;
p11_dict_free (gl.config);
gl.config = NULL;
}
static CK_RV
-finalize_module_unlocked_reentrant (Module *mod)
+finalize_module_inlock_reentrant (Module *mod)
{
assert (mod);
@@ -647,7 +744,7 @@ finalize_module_unlocked_reentrant (Module *mod)
if (mod->ref_count == 0)
return CKR_ARGUMENTS_BAD;
- if (--mod->ref_count > 0)
+ if (--mod->init_count > 0)
return CKR_OK;
/*
@@ -655,24 +752,20 @@ finalize_module_unlocked_reentrant (Module *mod)
* the ref count. This prevents module from being freed out
* from ounder us.
*/
- ++mod->ref_count;
- p11_mutex_lock (&mod->initialize_mutex);
p11_unlock ();
+ p11_mutex_lock (&mod->initialize_mutex);
if (mod->initialize_called) {
-
- assert (mod->funcs);
- mod->funcs->C_Finalize (NULL);
-
+ mod->virt.funcs.C_Finalize (&mod->virt.funcs, NULL);
mod->initialize_called = false;
}
p11_mutex_unlock (&mod->initialize_mutex);
p11_lock ();
- /* Match the increment above */
- --mod->ref_count;
+ /* Match the ref increment in initialize_module_inlock_reentrant() */
+ mod->ref_count--;
free_modules_when_no_refs_unlocked ();
return CKR_OK;
@@ -693,14 +786,18 @@ find_module_for_name_unlocked (const char *name)
return NULL;
}
-CK_RV
-_p11_kit_initialize_registered_unlocked_reentrant (void)
+static CK_RV
+initialize_registered_inlock_reentrant (void)
{
Module *mod;
p11_dictiter iter;
- int critical;
CK_RV rv;
+ /*
+ * This is only called by deprecated code. The caller expects all
+ * configured and enabled modules to be initialized.
+ */
+
rv = init_globals_unlocked ();
if (rv != CKR_OK)
return rv;
@@ -708,25 +805,20 @@ _p11_kit_initialize_registered_unlocked_reentrant (void)
rv = load_registered_modules_unlocked ();
if (rv == CKR_OK) {
p11_dict_iterate (gl.modules, &iter);
- while (p11_dict_next (&iter, NULL, (void **)&mod)) {
+ while (rv == CKR_OK && p11_dict_next (&iter, NULL, (void **)&mod)) {
- /* Skip all modules that aren't registered */
+ /* Skip all modules that aren't registered or enabled */
if (mod->name == NULL || !is_module_enabled_unlocked (mod->name, mod->config))
continue;
- rv = initialize_module_unlocked_reentrant (mod);
-
- /*
- * Module failed to initialize. If this is a critical module,
- * then this, should abort loading of others.
- */
+ rv = initialize_module_inlock_reentrant (mod);
if (rv != CKR_OK) {
- p11_message ("failed to initialize module: %s: %s",
- mod->name, p11_kit_strerror (rv));
-
- critical = _p11_conf_parse_boolean (p11_dict_get (mod->config, "critical"), false);
- if (!critical) {
- p11_debug ("ignoring failure, non-critical module: %s", mod->name);
+ if (mod->critical) {
+ p11_message ("initialization of critical module '%s' failed: %s",
+ mod->name, p11_kit_strerror (rv));
+ } else {
+ p11_message ("skipping module '%s' whose initialization failed: %s",
+ mod->name, p11_kit_strerror (rv));
rv = CKR_OK;
}
}
@@ -751,6 +843,8 @@ _p11_kit_initialize_registered_unlocked_reentrant (void)
* If this function fails, then an error message will be available via the
* p11_kit_message() function.
*
+ * Deprecated: Since: 0.16: Use p11_kit_modules_load() instead.
+ *
* Returns: CKR_OK if the initialization succeeded, or an error code.
*/
CK_RV
@@ -768,7 +862,7 @@ p11_kit_initialize_registered (void)
p11_message_clear ();
/* WARNING: Reentrancy can occur here */
- rv = _p11_kit_initialize_registered_unlocked_reentrant ();
+ rv = initialize_registered_inlock_reentrant ();
_p11_kit_default_message (rv);
@@ -782,14 +876,21 @@ p11_kit_initialize_registered (void)
return rv;
}
-CK_RV
-_p11_kit_finalize_registered_unlocked_reentrant (void)
+static CK_RV
+finalize_registered_inlock_reentrant (void)
{
Module *mod;
p11_dictiter iter;
Module **to_finalize;
int i, count;
+ /*
+ * This is only called from deprecated code. The caller expects all
+ * modules initialized earlier to be finalized (once). If non-critical
+ * modules failed to initialize, then it is not possible to completely
+ * guarantee the internal state.
+ */
+
if (!gl.modules)
return CKR_CRYPTOKI_NOT_INITIALIZED;
@@ -804,7 +905,7 @@ _p11_kit_finalize_registered_unlocked_reentrant (void)
while (p11_dict_next (&iter, NULL, (void **)&mod)) {
/* Skip all modules that aren't registered */
- if (mod->name)
+ if (mod->name && mod->init_count)
to_finalize[count++] = mod;
}
@@ -812,7 +913,7 @@ _p11_kit_finalize_registered_unlocked_reentrant (void)
for (i = 0; i < count; ++i) {
/* WARNING: Reentrant calls can occur here */
- finalize_module_unlocked_reentrant (to_finalize[i]);
+ finalize_module_inlock_reentrant (to_finalize[i]);
}
free (to_finalize);
@@ -837,6 +938,8 @@ _p11_kit_finalize_registered_unlocked_reentrant (void)
* If this function fails, then an error message will be available via the
* p11_kit_message() function.
*
+ * Deprecated: Since 0.16: Use p11_kit_modules_release() instead.
+ *
* Returns: CKR_OK if the finalization succeeded, or an error code.
*/
@@ -855,7 +958,7 @@ p11_kit_finalize_registered (void)
p11_message_clear ();
/* WARNING: Reentrant calls can occur here */
- rv = _p11_kit_finalize_registered_unlocked_reentrant ();
+ rv = finalize_registered_inlock_reentrant ();
_p11_kit_default_message (rv);
@@ -875,8 +978,14 @@ compar_priority (const void *one,
const char *v1, *v2;
int o1, o2;
- m1 = p11_dict_get (gl.modules, f1);
- m2 = p11_dict_get (gl.modules, f2);
+ m1 = p11_dict_get (gl.managed, f1);
+ if (m1 == NULL)
+ m1 = p11_dict_get (gl.modules, f1);
+
+ m2 = p11_dict_get (gl.managed, f2);
+ if (m2 == NULL)
+ m2 = p11_dict_get (gl.modules, f2);
+
assert (m1 != NULL && m2 != NULL);
v1 = p11_dict_get (m1->config, "priority");
@@ -910,16 +1019,21 @@ sort_modules_by_priority (CK_FUNCTION_LIST_PTR *modules,
qsort (modules, count, sizeof (CK_FUNCTION_LIST_PTR), compar_priority);
}
-CK_FUNCTION_LIST_PTR_PTR
-_p11_kit_registered_modules_unlocked (void)
+static CK_FUNCTION_LIST **
+list_registered_modules_inlock (void)
{
- CK_FUNCTION_LIST_PTR_PTR result = NULL;
+ CK_FUNCTION_LIST **result = NULL;
Module *mod;
p11_dictiter iter;
int i = 0;
+ /*
+ * This is only called by deprecated code. The caller expects to get
+ * a list of all registered enabled modules that have been initialized.
+ */
+
if (gl.modules) {
- result = calloc (p11_dict_size (gl.modules) + 1, sizeof (CK_FUNCTION_LIST_PTR));
+ result = calloc (p11_dict_size (gl.modules) + 1, sizeof (CK_FUNCTION_LIST *));
return_val_if_fail (result != NULL, NULL);
p11_dict_iterate (gl.modules, &iter);
@@ -936,7 +1050,7 @@ _p11_kit_registered_modules_unlocked (void)
* having initialized. This is a corner case, but want to make
* sure to cover it.
*/
- if (mod->ref_count && mod->name &&
+ if (mod->ref_count && mod->name && mod->init_count && mod->funcs &&
is_module_enabled_unlocked (mod->name, mod->config)) {
result[i++] = mod->funcs;
}
@@ -957,6 +1071,10 @@ _p11_kit_registered_modules_unlocked (void)
* The returned value is a <code>NULL</code> terminated array of
* <code>CK_FUNCTION_LIST_PTR</code> pointers.
*
+ * The returned modules are unmanaged.
+ *
+ * Deprecated: Since 0.16: Use p11_kit_modules_load() instead.
+ *
* Returns: A list of all the registered modules. Use the free() function to
* free the list.
*/
@@ -971,7 +1089,7 @@ p11_kit_registered_modules (void)
p11_message_clear ();
- result = _p11_kit_registered_modules_unlocked ();
+ result = list_registered_modules_inlock ();
p11_unlock ();
@@ -987,6 +1105,8 @@ p11_kit_registered_modules (void)
* You can use p11_kit_registered_modules() to get a list of all the registered
* modules. This name is specified by the registered module configuration.
*
+ * Deprecated: Since 0.16: Use p11_kit_module_get_name() instead.
+ *
* Returns: A newly allocated string containing the module name, or
* <code>NULL</code> if no such registered module exists. Use free() to
* free this string.
@@ -994,6 +1114,28 @@ p11_kit_registered_modules (void)
char*
p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module)
{
+ return_val_if_fail (module != NULL, NULL);
+ return p11_kit_module_get_name (module);
+}
+
+/**
+ * p11_kit_module_get_name:
+ * @module: pointer to a loaded module
+ *
+ * Get the configured name of the PKCS\#11 module.
+ *
+ * Configured modules are loaded by p11_kit_modules_load(). The module
+ * passed to this function can be either managed or unmanaged. Non
+ * configured modules will return %NULL.
+ *
+ * Use free() to release the return value when you're done with it.
+ *
+ * Returns: a newly allocated string containing the module name, or
+ * <code>NULL</code> if the module is not a configured module
+ */
+char *
+p11_kit_module_get_name (CK_FUNCTION_LIST *module)
+{
Module *mod;
char *name = NULL;
@@ -1005,9 +1147,13 @@ p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module)
p11_message_clear ();
- mod = module && gl.modules ? p11_dict_get (gl.modules, module) : NULL;
- if (mod && mod->name)
- name = strdup (mod->name);
+ if (gl.modules) {
+ mod = p11_dict_get (gl.modules, module);
+ if (mod == NULL)
+ mod = p11_dict_get (gl.managed, module);
+ if (mod && mod->name)
+ name = strdup (mod->name);
+ }
p11_unlock ();
@@ -1015,12 +1161,60 @@ p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module)
}
/**
+ * p11_kit_module_get_flags:
+ * @module: the module
+ *
+ * Get the flags for this module.
+ *
+ * The %P11_KIT_MODULE_UNMANAGED flag will be set if the module is not
+ * managed by p11-kit. It is a raw PKCS\#11 module function list.
+ *
+ * The %P11_KIT_MODULE_CRITICAL flag will be set if the module is configured
+ * to be critical, and not be skipped over if it fails to initialize or
+ * load. This flag is also set for modules that are not configured, but have
+ * been loaded in another fashion.
+ *
+ * Returns: the flags for the module
+ */
+int
+p11_kit_module_get_flags (CK_FUNCTION_LIST *module)
+{
+ Module *mod;
+ int flags = 0;
+
+ return_val_if_fail (module != NULL, 0);
+
+ p11_library_init_once ();
+
+ p11_lock ();
+
+ p11_message_clear ();
+
+ if (gl.modules) {
+ if (p11_virtual_is_wrapper (module)) {
+ mod = p11_dict_get (gl.managed, module);
+ } else {
+ flags |= P11_KIT_MODULE_UNMANAGED;
+ mod = p11_dict_get (gl.modules, module);
+ }
+ if (!mod || mod->critical)
+ flags |= P11_KIT_MODULE_CRITICAL;
+ }
+
+ p11_unlock ();
+
+ return flags;
+}
+
+/**
* p11_kit_registered_name_to_module:
* @name: name of a registered module
*
* Lookup a registered PKCS\#11 module by its name. This name is specified by
* the registered module configuration.
*
+ * Deprecated: Since 0.16: Use p11_kit_module_for_name() instead.
+ *
* Returns: a pointer to a PKCS\#11 module, or <code>NULL</code> if this name was
* not found.
*/
@@ -1034,17 +1228,83 @@ p11_kit_registered_name_to_module (const char *name)
p11_lock ();
+ p11_message_clear ();
+
+ if (gl.modules) {
+ mod = find_module_for_name_unlocked (name);
+ if (mod != NULL && mod->funcs && is_module_enabled_unlocked (name, mod->config))
+ module = mod->funcs;
+ }
+
+ p11_unlock ();
+
+ return module;
+}
+
+/**
+ * p11_kit_module_for_name:
+ * @modules: a list of modules to look through
+ * @name: the name of the module to find
+ *
+ * Look through the list of @modules and return the module whose @name
+ * matches.
+ *
+ * Only configured modules have names. Configured modules are loaded by
+ * p11_kit_modules_load(). The module passed to this function can be either
+ * managed or unmanaged.
+ *
+ * The return value is not copied or duplicated in anyway. It is still
+ * 'owned' by the @modules list.
+ *
+ * Returns: the module which matches the name, or %NULL if no match.
+ */
+CK_FUNCTION_LIST *
+p11_kit_module_for_name (CK_FUNCTION_LIST **modules,
+ const char *name)
+{
+ CK_FUNCTION_LIST *ret = NULL;
+ Module *mod;
+ int i;
+
+ return_val_if_fail (name != NULL, NULL);
+
+ if (!modules)
+ return NULL;
+
+ p11_library_init_once ();
+
+ p11_lock ();
+
p11_message_clear ();
- if (gl.modules) {
- mod = find_module_for_name_unlocked (name);
- if (mod != NULL && is_module_enabled_unlocked (name, mod->config))
- module = mod->funcs;
+ for (i = 0; gl.modules && modules[i] != NULL; i++) {
+ mod = p11_dict_get (gl.modules, modules[i]);
+ if (mod == NULL)
+ mod = p11_dict_get (gl.managed, modules[i]);
+ if (mod && mod->name && strcmp (mod->name, name) == 0) {
+ ret = modules[i];
+ break;
+ }
}
p11_unlock ();
- return module;
+ return ret;
+}
+
+static const char *
+module_get_option_inlock (Module *mod,
+ const char *option)
+{
+ p11_dict *config;
+
+ if (mod == NULL)
+ config = gl.config;
+ else
+ config = mod->config;
+ if (config == NULL)
+ return NULL;
+ return p11_dict_get (config, option);
}
/**
@@ -1056,6 +1316,8 @@ p11_kit_registered_name_to_module (const char *name)
* <code>NULL</code> module argument is specified, then this will lookup
* the configuration option in the global config file.
*
+ * Deprecated: Since 0.16: Use p11_kit_config_option() instead.
+ *
* Returns: A newly allocated string containing the option value, or
* <code>NULL</code> if the registered module or the option were not found.
* Use free() to free the returned string.
@@ -1065,7 +1327,7 @@ p11_kit_registered_option (CK_FUNCTION_LIST_PTR module, const char *field)
{
Module *mod = NULL;
char *option = NULL;
- p11_dict *config = NULL;
+ const char *value;
return_val_if_fail (field != NULL, NULL);
@@ -1075,24 +1337,611 @@ p11_kit_registered_option (CK_FUNCTION_LIST_PTR module, const char *field)
p11_message_clear ();
- if (module == NULL) {
- config = gl.config;
-
- } else {
+ if (module == NULL)
+ mod = NULL;
+ else
mod = gl.modules ? p11_dict_get (gl.modules, module) : NULL;
- if (mod)
- config = mod->config;
+
+ value = module_get_option_inlock (mod, field);
+ if (value)
+ option = strdup (value);
+
+ p11_unlock ();
+
+ return option;
+}
+
+/**
+ * p11_kit_config_option:
+ * @module: the module to retrieve the option for, or %NULL for global options
+ * @option: the option to retrieve
+ *
+ * Retrieve the value for a configured option.
+ *
+ * If @module is %NULL, then the global option with the given name will
+ * be retrieved. Otherwise @module should point to a configured loaded module.
+ * If no such @option or configured @module exists, then %NULL will be returned.
+ *
+ * Use free() to release the returned value.
+ *
+ * Returns: the option value or %NULL
+ */
+char *
+p11_kit_config_option (CK_FUNCTION_LIST *module,
+ const char *option)
+{
+ Module *mod = NULL;
+ const char *value = NULL;
+ char *ret = NULL;
+
+ return_val_if_fail (option != NULL, NULL);
+
+ p11_library_init_once ();
+
+ p11_lock ();
+
+ p11_message_clear ();
+
+ if (gl.modules) {
+ if (module != NULL) {
+ mod = p11_dict_get (gl.managed, module);
+ if (mod == NULL) {
+ mod = p11_dict_get (gl.modules, module);
+ if (mod == NULL)
+ goto cleanup;
+ }
+ }
+
+ value = module_get_option_inlock (mod, option);
+ if (value)
+ ret = strdup (value);
}
- if (config && field) {
- option = p11_dict_get (config, field);
- if (option)
- option = strdup (option);
+
+cleanup:
+ p11_unlock ();
+ return ret;
+}
+
+static CK_RV
+managed_C_Initialize (CK_X_FUNCTION_LIST *self,
+ CK_VOID_PTR init_args)
+{
+ Module *mod = ((Managed *)self)->mod;
+ CK_RV rv;
+
+ p11_debug ("in");
+ p11_lock ();
+
+ rv = initialize_module_inlock_reentrant (mod);
+
+ p11_unlock ();
+ p11_debug ("out: %lu", rv);
+
+ return rv;
+}
+
+static CK_RV
+managed_C_Finalize (CK_X_FUNCTION_LIST *self,
+ CK_VOID_PTR reserved)
+{
+ Module *mod = ((Managed *)self)->mod;
+ CK_RV rv;
+
+ p11_debug ("in");
+ p11_lock ();
+
+ rv = finalize_module_inlock_reentrant (mod);
+
+ p11_unlock ();
+ p11_debug ("out: %lu", rv);
+
+ return rv;
+}
+
+static void
+managed_free_inlock (void *data)
+{
+ Managed *managed = data;
+ managed->mod->ref_count--;
+ free (managed);
+}
+
+static p11_virtual *
+managed_create_inlock (Module *mod)
+{
+ Managed *managed;
+
+ managed = calloc (1, sizeof (Managed));
+ return_val_if_fail (managed != NULL, NULL);
+
+ p11_virtual_init (&managed->virt, &p11_virtual_stack,
+ &mod->virt, NULL);
+ managed->virt.funcs.C_Initialize = managed_C_Initialize;
+ managed->virt.funcs.C_Finalize = managed_C_Finalize;
+ managed->mod = mod;
+ mod->ref_count++;
+
+ return &managed->virt;
+}
+
+static bool
+lookup_managed_option (Module *mod,
+ const char *option,
+ bool def_value)
+{
+ const char *string;
+ bool supported;
+ bool value;
+
+ /* Whether managed stuff is supported or not */
+ supported = p11_virtual_can_wrap ();
+
+ string = module_get_option_inlock (NULL, option);
+ if (!string)
+ string = module_get_option_inlock (mod, option);
+ if (!string) {
+ if (!supported)
+ return false;
+ return def_value;
+ }
+
+ value = _p11_conf_parse_boolean (string, def_value);
+
+ if (!supported && value != supported) {
+ /*
+ * This is because libffi dependency was not built. The libffi dependency
+ * is highly recommended and building without it results in a large loss
+ * of functionality.
+ */
+ p11_message ("the '%s' option for module '%s' is not supported on this system",
+ option, mod->name);
+ return false;
+ }
+
+ return value;
+}
+
+static CK_RV
+release_module_inlock_rentrant (CK_FUNCTION_LIST *module,
+ const char *caller_func)
+{
+ Module *mod;
+
+ assert (module != NULL);
+
+ /* See if a managed module, and finalize if so */
+ mod = p11_dict_get (gl.managed, module);
+ if (mod != NULL) {
+ if (!p11_dict_remove (gl.managed, module))
+ assert_not_reached ();
+ p11_virtual_unwrap (module);
+
+ /* If an unmanaged module then caller should have finalized */
+ } else {
+ mod = p11_dict_get (gl.modules, module);
+ if (mod == NULL) {
+ p11_debug_precond ("invalid module pointer passed to %s", caller_func);
+ return CKR_ARGUMENTS_BAD;
}
+ }
+
+ /* Matches the ref in prepare_module_inlock_reentrant() */
+ mod->ref_count--;
+ return CKR_OK;
+}
+
+CK_RV
+p11_modules_release_inlock_reentrant (CK_FUNCTION_LIST **modules)
+{
+ CK_RV ret = CKR_OK;
+ CK_RV rv;
+ int i;
+
+ for (i = 0; modules[i] != NULL; i++) {
+ rv = release_module_inlock_rentrant (modules[i], __PRETTY_FUNCTION__);
+ if (rv != CKR_OK)
+ ret = rv;
+ }
+
+ free (modules);
+
+ /* In case nothing loaded, free up internal memory */
+ free_modules_when_no_refs_unlocked ();
+
+ return ret;
+}
+
+static CK_RV
+prepare_module_inlock_reentrant (Module *mod,
+ int flags,
+ CK_FUNCTION_LIST **module)
+{
+ p11_destroyer destroyer;
+ p11_virtual *virt;
+ bool is_managed;
+
+ assert (module != NULL);
+
+ if (flags & P11_KIT_MODULE_UNMANAGED)
+ is_managed = false;
+ else
+ is_managed = lookup_managed_option (mod, "managed", true);
+
+ if (is_managed) {
+ virt = managed_create_inlock (mod);
+ return_val_if_fail (virt != NULL, CKR_HOST_MEMORY);
+ destroyer = managed_free_inlock;
+
+ *module = p11_virtual_wrap (virt, destroyer);
+ return_val_if_fail (*module != NULL, CKR_GENERAL_ERROR);
+
+ if (!p11_dict_set (gl.managed, *module, mod))
+ return_val_if_reached (CKR_HOST_MEMORY);
+
+ } else if (mod->funcs) {
+ *module = mod->funcs;
+
+ } else {
+ return CKR_FUNCTION_NOT_SUPPORTED;
+ }
+
+ /* Matches the deref in release_module_inlock_rentrant() */
+ mod->ref_count++;
+ return CKR_OK;
+}
+
+CK_RV
+p11_modules_load_inlock_reentrant (int flags,
+ CK_FUNCTION_LIST ***results)
+{
+ CK_FUNCTION_LIST **modules;
+ Module *mod;
+ p11_dictiter iter;
+ CK_RV rv;
+ int at;
+
+ rv = init_globals_unlocked ();
+ if (rv != CKR_OK)
+ return rv;
+
+ rv = load_registered_modules_unlocked ();
+ if (rv != CKR_OK)
+ return rv;
+
+ modules = calloc (p11_dict_size (gl.modules) + 1, sizeof (CK_FUNCTION_LIST *));
+ return_val_if_fail (modules != NULL, CKR_HOST_MEMORY);
+
+ at = 0;
+ rv = CKR_OK;
+
+ p11_dict_iterate (gl.modules, &iter);
+ while (p11_dict_next (&iter, NULL, (void **)&mod)) {
+
+ /*
+ * We don't include unreferenced modules. We don't include
+ * modules that have been initialized but aren't in the
+ * registry. These have a NULL name.
+ *
+ * In addition we check again that the module isn't disabled
+ * using enable-in or disable-in. This is because a caller
+ * can change the progname we recognize the process as after
+ * having initialized. This is a corner case, but want to make
+ * sure to cover it.
+ */
+ if (!mod->name || !is_module_enabled_unlocked (mod->name, mod->config))
+ continue;
+
+ rv = prepare_module_inlock_reentrant (mod, flags, modules + at);
+ if (rv == CKR_OK)
+ at++;
+ else if (rv != CKR_FUNCTION_NOT_SUPPORTED)
+ break;
+ }
+
+ modules[at] = NULL;
+
+ if (rv != CKR_OK) {
+ p11_modules_release_inlock_reentrant (modules);
+ return rv;
+ }
+
+ sort_modules_by_priority (modules, at);
+ *results = modules;
+ return CKR_OK;
+}
+
+/**
+ * p11_kit_modules_load:
+ * @reserved: set to %NULL
+ * @flags: flags to use to load the module
+ *
+ * Load the configured PKCS\#11 modules.
+ *
+ * If @flags contains the %P11_KIT_MODULE_UNMANAGED flag, then the
+ * modules will be not be loaded in 'managed' mode regardless of its
+ * configuration. This is not recommended for general usage.
+ *
+ * If @flags contains the %P11_KIT_MODULE_CRITICAL flag then the
+ * modules will all be treated as 'critical', regardless of the module
+ * configuration. This means that a failure to load any module will
+ * cause this funtion to fail.
+ *
+ * For unmanaged modules there is no guarantee to the state of the
+ * modules. Other callers may be using the modules. Using unmanaged
+ * modules haphazardly is not recommended for this reason. Some
+ * modules (such as those configured with RPC) cannot be loaded in
+ * unmanaged mode, and will be skipped.
+ *
+ * Use p11_kit_modules_release() to release the modules returned by
+ * this function.
+ *
+ * If this function fails, then an error message will be available via the
+ * p11_kit_message() function.
+ *
+ * Returns: a null terminated list of modules represented as PKCS\#11
+ * function lists, or %NULL on failure
+ */
+CK_FUNCTION_LIST **
+p11_kit_modules_load (const char *reserved,
+ int flags)
+{
+ CK_FUNCTION_LIST **modules;
+ CK_RV rv;
+
+ /* progname attribute not implemented yet */
+ return_val_if_fail (reserved == NULL, NULL);
+
+ p11_library_init_once ();
+
+ /* WARNING: This function must be reentrant */
+ p11_debug ("in");
+
+ p11_lock ();
+
+ p11_message_clear ();
+
+ /* WARNING: Reentrancy can occur here */
+ rv = p11_modules_load_inlock_reentrant (flags, &modules);
p11_unlock ();
- return option;
+ if (rv != CKR_OK)
+ modules = NULL;
+
+ p11_debug ("out: %s", modules ? "success" : "fail");
+ return modules;
+}
+
+/**
+ * p11_kit_modules_initialize:
+ * @modules: a %NULL terminated list of modules
+ * @failure_callback: called with modules that fail to initialize
+ *
+ * Initialize all the modules in the @modules list by calling their
+ * <literal>C_Initialize</literal> function.
+ *
+ * For managed modules the <literal>C_Initialize</literal> function
+ * is overridden so that multiple callers can initialize the same
+ * modules. In addition for managed modules multiple callers can
+ * initialize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to initialize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_ALREADY_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers initialize from
+ * different threads.
+ *
+ * When a module fails to initialize it is removed from the @modules list.
+ * If the @failure_callback is not %NULL then it is called with the modules that
+ * fail to initialize. For example, you may pass p11_kit_module_release()
+ * as a @failure_callback if the @modules list was loaded wit p11_kit_modules_load().
+ *
+ * The return value will return the failure code of the last critical
+ * module that failed to initialize. Non-critical module failures do not affect
+ * the return value. If no critical modules failed to initialize then the
+ * return value will be <literal>CKR_OK</literal>.
+ *
+ * When modules are removed, the list will be %NULL terminated at the
+ * appropriate place so it can continue to be used as a modules list.
+ *
+ * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument.
+ * Custom initialization arguments cannot be supported when multiple consumers
+ * load the same module.
+ *
+ * Returns: <literal>CKR_OK</literal> or the failure code of the last critical
+ * module that failed to initialize.
+ */
+CK_RV
+p11_kit_modules_initialize (CK_FUNCTION_LIST **modules,
+ p11_kit_destroyer failure_callback)
+{
+ CK_RV ret = CKR_OK;
+ CK_RV rv;
+ bool critical;
+ char *name;
+ int i, out;
+
+ return_val_if_fail (modules != NULL, CKR_ARGUMENTS_BAD);
+
+ for (i = 0, out = 0; modules[i] != NULL; i++, out++) {
+ rv = modules[i]->C_Initialize (NULL);
+ if (rv != CKR_OK) {
+ name = p11_kit_module_get_name (modules[i]);
+ if (name == NULL)
+ name = strdup ("(unknown)");
+ return_val_if_fail (name != NULL, CKR_HOST_MEMORY);
+ critical = (p11_kit_module_get_flags (modules[i]) & P11_KIT_MODULE_CRITICAL);
+ p11_message ("%s: module failed to initialize%s: %s",
+ name, critical ? "" : ", skipping", p11_kit_strerror (rv));
+ if (critical)
+ ret = rv;
+ if (failure_callback)
+ failure_callback (modules[i]);
+ out--;
+ free (name);
+ }
+ }
+
+ /* NULL terminate after above changes */
+ modules[out] = NULL;
+ return ret;
+}
+
+/**
+ * p11_kit_modules_load_and_initialize:
+ * @flags: flags to use to load the modules
+ *
+ * Load and initialize configured modules.
+ *
+ * If a critical module fails to load or initialize then the function will
+ * return <literal>NULL</literal>. Non-critical modules will be skipped
+ * and not included in the returned module list.
+ *
+ * Use p11_kit_modules_finalize_and_release() when you're done with the
+ * modules returned by this function.
+ *
+ * Returns: a <literal>NULL</literal> terminated list of modules, or
+ * <literal>NULL</literal> on failure
+ */
+CK_FUNCTION_LIST **
+p11_kit_modules_load_and_initialize (int flags)
+{
+ CK_FUNCTION_LIST **modules;
+ CK_RV rv;
+
+ modules = p11_kit_modules_load (NULL, flags);
+ if (modules == NULL)
+ return NULL;
+
+ rv = p11_kit_modules_initialize (modules, (p11_destroyer)p11_kit_module_release);
+ if (rv != CKR_OK) {
+ p11_kit_modules_release (modules);
+ modules = NULL;
+ }
+
+ return modules;
+}
+
+/**
+ * p11_kit_modules_finalize:
+ * @modules: a <literal>NULL</literal> terminated list of modules
+ *
+ * Finalize each module in the @modules list by calling its
+ * <literal>C_Finalize</literal> function. Regardless of failures, all
+ * @modules will have their <literal>C_Finalize</literal> function called.
+ *
+ * If a module returns a failure from its <literal>C_Finalize</literal>
+ * method it will be returned. If multiple modules fail, the last failure
+ * will be returned.
+ *
+ * For managed modules the <literal>C_Finalize</literal> function
+ * is overridden so that multiple callers can finalize the same
+ * modules. In addition for managed modules multiple callers can
+ * finalize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to finalize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers finalize from
+ * different threads.
+ *
+ * Returns: <literal>CKR_OK</literal> or the failure code of the last
+ * module that failed to finalize
+ */
+CK_RV
+p11_kit_modules_finalize (CK_FUNCTION_LIST **modules)
+{
+ CK_RV ret = CKR_OK;
+ CK_RV rv;
+ char *name;
+ int i;
+
+ return_val_if_fail (modules != NULL, CKR_ARGUMENTS_BAD);
+
+ for (i = 0; modules[i] != NULL; i++) {
+ rv = modules[i]->C_Finalize (NULL);
+ if (rv != CKR_OK) {
+ name = p11_kit_module_get_name (modules[i]);
+ p11_message ("%s: module failed to finalize: %s",
+ name ? name : "(unknown)", p11_kit_strerror (rv));
+ free (name);
+ ret = rv;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * p11_kit_modules_release:
+ * @modules: the modules to release
+ *
+ * Release the a set of loaded PKCS\#11 modules.
+ *
+ * The modules may be either managed or unmanaged. The array containing
+ * the module pointers is also freed by this function.
+ *
+ * Managed modules will not be actually released until all
+ * callers using them have done so. If the modules were initialized, they
+ * should have been finalized first.
+ */
+void
+p11_kit_modules_release (CK_FUNCTION_LIST **modules)
+{
+ p11_library_init_once ();
+
+ return_if_fail (modules != NULL);
+
+ /* WARNING: This function must be reentrant */
+ p11_debug ("in");
+
+ p11_lock ();
+
+ p11_message_clear ();
+ p11_modules_release_inlock_reentrant (modules);
+
+ p11_unlock ();
+
+ p11_debug ("out");
+}
+
+/**
+ * p11_kit_modules_finalize_and_release:
+ * @modules: the modules to release
+ *
+ * Finalize and then release the a set of loaded PKCS\#11 modules.
+ *
+ * The modules may be either managed or unmanaged. The array containing
+ * the module pointers is also freed by this function.
+ *
+ * Modules are released even if their finalization returns an error code.
+ * Managed modules will not be actually finalized or released until all
+ * callers using them have done so.
+ *
+ * For managed modules the <literal>C_Finalize</literal> function
+ * is overridden so that multiple callers can finalize the same
+ * modules. In addition for managed modules multiple callers can
+ * finalize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to finalize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers initialize from
+ * different threads.
+ */
+void
+p11_kit_modules_finalize_and_release (CK_FUNCTION_LIST **modules)
+{
+ return_if_fail (modules != NULL);
+ p11_kit_modules_finalize (modules);
+ p11_kit_modules_release (modules);
}
/**
@@ -1123,14 +1972,17 @@ p11_kit_registered_option (CK_FUNCTION_LIST_PTR module, const char *field)
* If this function fails, then an error message will be available via the
* p11_kit_message() function.
*
+ * Deprecated: Since 0.16: Use p11_kit_module_initialize() instead.
+ *
* Returns: CKR_OK if the initialization was successful.
*/
CK_RV
p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module)
{
- Module *allocated = NULL;
+ CK_FUNCTION_LIST_PTR result;
Module *mod;
- CK_RV rv = CKR_OK;
+ int flags;
+ CK_RV rv;
return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD);
@@ -1143,34 +1995,134 @@ p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module)
p11_message_clear ();
- rv = init_globals_unlocked ();
- if (rv == CKR_OK) {
+ flags = P11_KIT_MODULE_CRITICAL | P11_KIT_MODULE_UNMANAGED;
+ rv = p11_module_load_inlock_reentrant (module, flags, &result);
+
+ /* An unmanaged module should return the same pointer */
+ assert (rv != CKR_OK || result == module);
+ if (rv == CKR_OK) {
mod = p11_dict_get (gl.modules, module);
- if (mod == NULL) {
- p11_debug ("allocating new module");
- allocated = mod = alloc_module_unlocked ();
- if (mod == NULL)
- rv = CKR_HOST_MEMORY;
- else
- mod->funcs = module;
+ assert (mod != NULL);
+ rv = initialize_module_inlock_reentrant (mod);
+ if (rv != CKR_OK) {
+ p11_message ("module initialization failed: %s", p11_kit_strerror (rv));
+ p11_module_release_inlock_reentrant (module);
}
+ }
- /* If this was newly allocated, add it to the list */
- if (rv == CKR_OK && allocated) {
- if (p11_dict_set (gl.modules, allocated->funcs, allocated))
- allocated = NULL;
- else
- rv = CKR_HOST_MEMORY;
- }
+ p11_unlock ();
+
+ p11_debug ("out: %lu", rv);
+ return rv;
+}
+
+CK_RV
+p11_module_load_inlock_reentrant (CK_FUNCTION_LIST *module,
+ int flags,
+ CK_FUNCTION_LIST **result)
+{
+ Module *allocated = NULL;
+ Module *mod;
+ CK_RV rv = CKR_OK;
+
+ rv = init_globals_unlocked ();
+ if (rv == CKR_OK) {
+
+ mod = p11_dict_get (gl.modules, module);
+ if (mod == NULL) {
+ p11_debug ("allocating new module");
+ allocated = mod = alloc_module_unlocked ();
+ if (mod == NULL)
+ rv = CKR_HOST_MEMORY;
+ else
+ module_setup_with_functions (mod, module);
+ }
+ /* If this was newly allocated, add it to the list */
+ if (rv == CKR_OK && allocated) {
+ if (p11_dict_set (gl.modules, allocated->funcs, allocated))
+ allocated = NULL;
+ else
+ rv = CKR_HOST_MEMORY;
+ }
+
+ if (rv == CKR_OK) {
+ /* WARNING: Reentrancy can occur here */
+ rv = prepare_module_inlock_reentrant (mod, flags, result);
+ }
+
+ free (allocated);
+ }
+
+ /*
+ * If initialization failed, we may need to cleanup.
+ * If we added this module above, then this will
+ * clean things up as expected.
+ */
+ if (rv != CKR_OK)
+ free_modules_when_no_refs_unlocked ();
+
+ _p11_kit_default_message (rv);
+ return rv;
+}
+
+/**
+ * p11_kit_module_load:
+ * @module_path: full file path of module library
+ * @flags: flags to use when loading the module
+ *
+ * Load an arbitrary PKCS\#11 module from a dynamic library file, and
+ * initialize it. Normally using the p11_kit_modules_load() function
+ * is preferred.
+ *
+ * Using this function to load modules allows coordination between multiple
+ * callers of the same module in a single process. If @flags contains the
+ * %P11_KIT_MODULE_UNMANAGED flag, then the modules will be not be loaded
+ * in 'managed' mode and not be coordinated. This is not recommended
+ * for general usage.
+ *
+ * Subsequent calls to this function for the same module will result in an
+ * initialization count being incremented for the module. It is safe (although
+ * usually unnecessary) to use this function on registered modules.
+ *
+ * The module should be released with p11_kit_module_release().
+ *
+ * If this function fails, then an error message will be available via the
+ * p11_kit_message() function.
+ *
+ * Returns: the loaded module PKCS\#11 functions or %NULL on failure
+ */
+CK_FUNCTION_LIST *
+p11_kit_module_load (const char *module_path,
+ int flags)
+{
+ CK_FUNCTION_LIST *module;
+ CK_RV rv;
+ Module *mod;
+
+ return_val_if_fail (module_path != NULL, NULL);
+
+ p11_library_init_once ();
+
+ /* WARNING: This function must be reentrant for the same arguments */
+ p11_debug ("in: %s", module_path);
+
+ p11_lock ();
+
+ p11_message_clear ();
+
+ rv = init_globals_unlocked ();
+ if (rv == CKR_OK) {
+
+ rv = load_module_from_file_unlocked (module_path, &mod);
if (rv == CKR_OK) {
/* WARNING: Reentrancy can occur here */
- rv = initialize_module_unlocked_reentrant (mod);
+ rv = prepare_module_inlock_reentrant (mod, flags, &module);
+ if (rv != CKR_OK)
+ module = NULL;
}
-
- free (allocated);
}
/*
@@ -1181,12 +2133,11 @@ p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module)
if (rv != CKR_OK)
free_modules_when_no_refs_unlocked ();
- _p11_kit_default_message (rv);
-
p11_unlock ();
- p11_debug ("out: %lu", rv);
- return rv;
+ p11_debug ("out: %s", module ? "success" : "fail");
+ return module;
+
}
/**
@@ -1198,7 +2149,7 @@ p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module)
* p11_kit_finalize_registered() instead of this function.
*
* Using this function to finalize modules allows coordination between
- * multiple users of the same module in a single process. The caller should
+ * multiple users of the same module in a single process. The caller should not
* call the module's <code>C_Finalize</code> method. This function will call
* <code>C_Finalize</code> as necessary.
*
@@ -1211,10 +2162,13 @@ p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module)
* If this function fails, then an error message will be available via the
* p11_kit_message() function.
*
+ * Deprecated: Since 0.16: Use p11_kit_module_finalize() and
+ * p11_kit_module_release() instead.
+ *
* Returns: CKR_OK if the finalization was successful.
*/
CK_RV
-p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module)
+p11_kit_finalize_module (CK_FUNCTION_LIST *module)
{
Module *mod;
CK_RV rv = CKR_OK;
@@ -1236,7 +2190,7 @@ p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module)
rv = CKR_ARGUMENTS_BAD;
} else {
/* WARNING: Rentrancy can occur here */
- rv = finalize_module_unlocked_reentrant (mod);
+ rv = finalize_module_inlock_reentrant (mod);
}
_p11_kit_default_message (rv);
@@ -1248,6 +2202,130 @@ p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module)
}
/**
+ * p11_kit_module_initialize:
+ * @module: the module to initialize
+ *
+ * Initialize a PKCS\#11 module by calling its <literal>C_Initialize</literal>
+ * function.
+ *
+ * For managed modules the <literal>C_Initialize</literal> function
+ * is overridden so that multiple callers can initialize the same
+ * modules. In addition for managed modules multiple callers can
+ * initialize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to initialize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_ALREADY_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers initialize from
+ * different threads.
+ *
+ * This function does not accept a <code>CK_C_INITIALIZE_ARGS</code> argument.
+ * Custom initialization arguments cannot be supported when multiple consumers
+ * load the same module.
+ *
+ * Returns: <literal>CKR_OK</literal> or a failure code
+ */
+CK_RV
+p11_kit_module_initialize (CK_FUNCTION_LIST *module)
+{
+ char *name;
+ CK_RV rv;
+
+ return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD);
+
+ rv = module->C_Initialize (NULL);
+ if (rv != CKR_OK) {
+ name = p11_kit_module_get_name (module);
+ p11_message ("%s: module failed to initialize: %s",
+ name ? name : "(unknown)", p11_kit_strerror (rv));
+ free (name);
+ }
+
+ return rv;
+}
+
+/**
+ * p11_kit_module_finalize:
+ * @module: the module to finalize
+ *
+ * Finalize a PKCS\#11 module by calling its <literal>C_Finalize</literal>
+ * function.
+ *
+ * For managed modules the <literal>C_Finalize</literal> function
+ * is overridden so that multiple callers can finalize the same
+ * modules. In addition for managed modules multiple callers can
+ * finalize from different threads, and still guarantee consistent
+ * thread-safe behavior.
+ *
+ * For unmanaged modules if multiple callers try to finalize
+ * a module, then one of the calls will return
+ * <literal>CKR_CRYPTOKI_NOT_INITIALIZED</literal> according to the
+ * PKCS\#11 specification. In addition there are no guarantees that
+ * thread-safe behavior will occur if multiple callers finalize from
+ * different threads.
+ *
+ * Returns: <literal>CKR_OK</literal> or a failure code
+ */
+CK_RV
+p11_kit_module_finalize (CK_FUNCTION_LIST *module)
+{
+ char *name;
+ CK_RV rv;
+
+ return_val_if_fail (module != NULL, CKR_ARGUMENTS_BAD);
+
+ rv = module->C_Finalize (NULL);
+ if (rv != CKR_OK) {
+ name = p11_kit_module_get_name (module);
+ p11_message ("%s: module failed to finalize: %s",
+ name ? name : "(unknown)", p11_kit_strerror (rv));
+ free (name);
+ }
+
+ return rv;
+
+}
+
+
+/**
+ * p11_kit_module_release:
+ * @module: the module to release
+ *
+ * Release the a loaded PKCS\#11 modules.
+ *
+ * The module may be either managed or unmanaged. The <literal>C_Finalize</literal>
+ * function will be called if no other callers are using this module.
+ */
+void
+p11_kit_module_release (CK_FUNCTION_LIST *module)
+{
+ return_if_fail (module != NULL);
+
+ p11_library_init_once ();
+
+ /* WARNING: This function must be reentrant for the same arguments */
+ p11_debug ("in");
+
+ p11_lock ();
+
+ p11_message_clear ();
+
+ release_module_inlock_rentrant (module, __PRETTY_FUNCTION__);
+
+ p11_unlock ();
+
+ p11_debug ("out");
+}
+
+CK_RV
+p11_module_release_inlock_reentrant (CK_FUNCTION_LIST *module)
+{
+ return release_module_inlock_rentrant (module, __PRETTY_FUNCTION__);
+}
+
+/**
* p11_kit_load_initialize_module:
* @module_path: full file path of module library
* @module: location to place loaded module pointer
@@ -1278,6 +2356,8 @@ p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module)
* If this function fails, then an error message will be available via the
* p11_kit_message() function.
*
+ * Deprecated: Since 0.16: Use p11_kit_module_load() instead.
+ *
* Returns: CKR_OK if the initialization was successful.
*/
CK_RV
@@ -1306,12 +2386,14 @@ p11_kit_load_initialize_module (const char *module_path,
if (rv == CKR_OK) {
/* WARNING: Reentrancy can occur here */
- rv = initialize_module_unlocked_reentrant (mod);
+ rv = initialize_module_inlock_reentrant (mod);
}
}
- if (rv == CKR_OK && module)
+ if (rv == CKR_OK && module) {
+ assert (mod->funcs != NULL);
*module = mod->funcs;
+ }
/*
* If initialization failed, we may need to cleanup.
diff --git a/p11-kit/modules.h b/p11-kit/modules.h
new file mode 100644
index 0000000..ca8dac3
--- /dev/null
+++ b/p11-kit/modules.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+#ifndef __P11_MODULES_H__
+#define __P11_MODULES_H__
+
+#include "pkcs11.h"
+
+CK_RV p11_modules_load_inlock_reentrant (int flags,
+ CK_FUNCTION_LIST_PTR **results);
+
+CK_RV p11_modules_release_inlock_reentrant (CK_FUNCTION_LIST_PTR *modules);
+
+CK_RV p11_module_load_inlock_reentrant (CK_FUNCTION_LIST_PTR module,
+ int flags,
+ CK_FUNCTION_LIST_PTR *result);
+
+CK_RV p11_module_release_inlock_reentrant (CK_FUNCTION_LIST_PTR module);
+
+#endif /* __P11_MODULES_H__ */
diff --git a/p11-kit/p11-kit.h b/p11-kit/p11-kit.h
index f83cbd0..b8edcc2 100644
--- a/p11-kit/p11-kit.h
+++ b/p11-kit/p11-kit.h
@@ -36,6 +36,7 @@
#define __P11_KIT_H__
#include "p11-kit/pkcs11.h"
+#include "deprecated.h"
/*
* If the caller is using the PKCS#11 GNU calling convention, then we cater
@@ -50,45 +51,63 @@ typedef struct ck_function_list* CK_FUNCTION_LIST_PTR;
extern "C" {
#endif
-CK_RV p11_kit_initialize_registered (void);
+enum {
+ P11_KIT_MODULE_UNMANAGED = 1 << 0,
+ P11_KIT_MODULE_CRITICAL = 1 << 1,
+};
-CK_RV p11_kit_finalize_registered (void);
+typedef void (* p11_kit_destroyer) (void *data);
-CK_FUNCTION_LIST_PTR* p11_kit_registered_modules (void);
+CK_FUNCTION_LIST ** p11_kit_modules_load (const char *reserved,
+ int flags);
-char* p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR module);
+CK_RV p11_kit_modules_initialize (CK_FUNCTION_LIST **modules,
+ p11_kit_destroyer failure_callback);
-CK_FUNCTION_LIST_PTR p11_kit_registered_name_to_module (const char *name);
+CK_FUNCTION_LIST ** p11_kit_modules_load_and_initialize (int flags);
-char* p11_kit_registered_option (CK_FUNCTION_LIST_PTR module,
- const char *field);
+CK_RV p11_kit_modules_finalize (CK_FUNCTION_LIST **modules);
-CK_RV p11_kit_initialize_module (CK_FUNCTION_LIST_PTR module);
+void p11_kit_modules_release (CK_FUNCTION_LIST **modules);
-CK_RV p11_kit_finalize_module (CK_FUNCTION_LIST_PTR module);
+void p11_kit_modules_finalize_and_release (CK_FUNCTION_LIST **modules);
-CK_RV p11_kit_load_initialize_module (const char *module_path,
- CK_FUNCTION_LIST_PTR *module);
+CK_FUNCTION_LIST * p11_kit_module_for_name (CK_FUNCTION_LIST **modules,
+ const char *name);
-const char* p11_kit_strerror (CK_RV rv);
+char * p11_kit_module_get_name (CK_FUNCTION_LIST *module);
-size_t p11_kit_space_strlen (const unsigned char *string,
- size_t max_length);
+int p11_kit_module_get_flags (CK_FUNCTION_LIST *module);
-char* p11_kit_space_strdup (const unsigned char *string,
- size_t max_length);
+CK_FUNCTION_LIST * p11_kit_module_load (const char *module_path,
+ int flags);
-#ifdef P11_KIT_FUTURE_UNSTABLE_API
+CK_RV p11_kit_module_initialize (CK_FUNCTION_LIST *module);
+
+CK_RV p11_kit_module_finalize (CK_FUNCTION_LIST *module);
+
+void p11_kit_module_release (CK_FUNCTION_LIST *module);
+
+char * p11_kit_config_option (CK_FUNCTION_LIST *module,
+ const char *option);
-void p11_kit_set_progname (const char *progname);
+const char* p11_kit_strerror (CK_RV rv);
+
+size_t p11_kit_space_strlen (const unsigned char *string,
+ size_t max_length);
+
+char* p11_kit_space_strdup (const unsigned char *string,
+ size_t max_length);
+
+#ifdef P11_KIT_FUTURE_UNSTABLE_API
-void p11_kit_be_quiet (void);
+void p11_kit_set_progname (const char *progname);
-void p11_kit_be_loud (void);
+void p11_kit_be_quiet (void);
-const char* p11_kit_message (void);
+void p11_kit_be_loud (void);
-typedef void (* p11_kit_destroyer) (void *data);
+const char * p11_kit_message (void);
#endif
diff --git a/p11-kit/private.h b/p11-kit/private.h
index f862975..b44ae24 100644
--- a/p11-kit/private.h
+++ b/p11-kit/private.h
@@ -40,12 +40,6 @@
extern CK_FUNCTION_LIST _p11_proxy_function_list;
-CK_FUNCTION_LIST_PTR_PTR _p11_kit_registered_modules_unlocked (void);
-
-CK_RV _p11_kit_initialize_registered_unlocked_reentrant (void);
-
-CK_RV _p11_kit_finalize_registered_unlocked_reentrant (void);
-
void _p11_kit_proxy_after_fork (void);
CK_RV _p11_load_config_files_unlocked (const char *system_conf,
diff --git a/p11-kit/proxy.c b/p11-kit/proxy.c
index 1908d34..8ae6b7f 100644
--- a/p11-kit/proxy.c
+++ b/p11-kit/proxy.c
@@ -36,11 +36,13 @@
#include "config.h"
#define P11_DEBUG_FLAG P11_DEBUG_PROXY
+#define CRYPTOKI_EXPORTS
+
#include "debug.h"
#include "dict.h"
#include "library.h"
#include "message.h"
-#define CRYPTOKI_EXPORTS
+#include "modules.h"
#include "pkcs11.h"
#include "p11-kit.h"
#include "private.h"
@@ -70,17 +72,16 @@ typedef struct _Session {
CK_SLOT_ID wrap_slot;
} Session;
-/*
- * Shared data between threads, protected by the mutex, a structure so
- * we can audit thread safety easier.
- */
-static struct _Shared {
+typedef struct {
+ int refs;
Mapping *mappings;
unsigned int n_mappings;
- int mappings_refs;
p11_dict *sessions;
CK_ULONG last_handle;
-} gl = { NULL, 0, 0, NULL, FIRST_HANDLE };
+ CK_FUNCTION_LIST_PTR *modules;
+} Proxy;
+
+static Proxy *px = NULL;
#define MANUFACTURER_ID "PKCS#11 Kit "
#define LIBRARY_DESCRIPTION "PKCS#11 Kit Proxy Module "
@@ -94,17 +95,18 @@ static struct _Shared {
static CK_RV
map_slot_unlocked (CK_SLOT_ID slot, Mapping *mapping)
{
+ assert (px != NULL);
assert (mapping);
if (slot < MAPPING_OFFSET)
return CKR_SLOT_ID_INVALID;
slot -= MAPPING_OFFSET;
- if (slot > gl.n_mappings) {
+ if (slot > px->n_mappings) {
return CKR_SLOT_ID_INVALID;
} else {
- assert (gl.mappings);
- memcpy (mapping, &gl.mappings[slot], sizeof (Mapping));
+ assert (px->mappings);
+ memcpy (mapping, &px->mappings[slot], sizeof (Mapping));
return CKR_OK;
}
}
@@ -118,7 +120,7 @@ map_slot_to_real (CK_SLOT_ID_PTR slot, Mapping *mapping)
p11_lock ();
- if (!gl.mappings)
+ if (!px)
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
else
rv = map_slot_unlocked (*slot, mapping);
@@ -141,11 +143,11 @@ map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *se
p11_lock ();
- if (!gl.sessions) {
+ if (!px) {
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
} else {
- assert (gl.sessions);
- sess = p11_dict_get (gl.sessions, handle);
+ assert (px->sessions);
+ sess = p11_dict_get (px->sessions, handle);
if (sess != NULL) {
*handle = sess->real_session;
rv = map_slot_unlocked (sess->wrap_slot, mapping);
@@ -162,26 +164,21 @@ map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *se
}
static void
-finalize_mappings_unlocked (void)
+proxy_free (Proxy *py)
{
- assert (gl.mappings_refs);
-
- if (--gl.mappings_refs)
- return;
-
- /* No more mappings */
- free (gl.mappings);
- gl.mappings = NULL;
- gl.n_mappings = 0;
-
- /* no more sessions */
- p11_dict_free (gl.sessions);
- gl.sessions = NULL;
+ if (py) {
+ p11_kit_modules_finalize_and_release (py->modules);
+ p11_dict_free (py->sessions);
+ free (py->mappings);
+ free (py);
+ }
}
void
_p11_kit_proxy_after_fork (void)
{
+ Proxy *py;
+
/*
* After a fork the callers are supposed to call C_Initialize and all.
* In addition the underlying libraries may change their state so free
@@ -190,17 +187,23 @@ _p11_kit_proxy_after_fork (void)
p11_lock ();
- gl.mappings_refs = 1;
- finalize_mappings_unlocked ();
- assert (!gl.mappings);
+ py = px;
+ px = NULL;
p11_unlock ();
+
+ if (py) {
+ p11_kit_modules_release (py->modules);
+ py->modules = NULL;
+ proxy_free (py);
+ }
}
static CK_RV
proxy_C_Finalize (CK_VOID_PTR reserved)
{
- CK_RV rv;
+ Proxy *py = NULL;
+ CK_RV rv = CKR_OK;
p11_debug ("in");
@@ -212,17 +215,16 @@ proxy_C_Finalize (CK_VOID_PTR reserved)
} else {
p11_lock ();
- /* WARNING: Reentrancy can occur here */
- rv = _p11_kit_finalize_registered_unlocked_reentrant ();
-
- /*
- * If modules are all gone, then this was the last
- * finalize, so cleanup our mappings
- */
- if (gl.mappings_refs)
- finalize_mappings_unlocked ();
+ if (!px) {
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+ } else if (px->refs-- == 1) {
+ py = px;
+ px = NULL;
+ }
p11_unlock ();
+
+ proxy_free (py);
}
p11_debug ("out: %lu", rv);
@@ -230,35 +232,50 @@ proxy_C_Finalize (CK_VOID_PTR reserved)
}
static CK_RV
-initialize_mappings_unlocked_reentrant (void)
+proxy_create (Proxy **res)
{
- CK_FUNCTION_LIST_PTR *funcss, *f;
+ CK_FUNCTION_LIST_PTR *f;
CK_FUNCTION_LIST_PTR funcs;
- Mapping *mappings = NULL;
- int n_mappings = 0;
CK_SLOT_ID_PTR slots;
CK_ULONG i, count;
CK_RV rv = CKR_OK;
+ Proxy *py;
- assert (!gl.mappings);
+ py = calloc (1, sizeof (Proxy));
+ return_val_if_fail (py != NULL, CKR_HOST_MEMORY);
- funcss = _p11_kit_registered_modules_unlocked ();
- for (f = funcss; *f; ++f) {
- funcs = *f;
+ p11_lock ();
- assert (funcs);
- slots = NULL;
+ /* WARNING: Reentrancy can occur here */
+ rv = p11_modules_load_inlock_reentrant (0, &py->modules);
- p11_unlock ();
+ p11_unlock ();
- /* Ask module for its slots */
- rv = (funcs->C_GetSlotList) (FALSE, NULL, &count);
- if (rv == CKR_OK && count) {
- slots = calloc (sizeof (CK_SLOT_ID), count);
- rv = (funcs->C_GetSlotList) (FALSE, slots, &count);
- }
+ if (rv != CKR_OK) {
+ proxy_free (py);
+ free (py);
+ return rv;
+ }
- p11_lock ();
+ rv = p11_kit_modules_initialize (py->modules, (p11_destroyer)p11_kit_module_release);
+ if (rv != CKR_OK) {
+ p11_kit_modules_release (py->modules);
+ free (py);
+ return rv;
+ }
+
+ for (f = py->modules; *f; ++f) {
+ funcs = *f;
+
+ assert (funcs != NULL);
+ slots = NULL;
+
+ /* Ask module for its slots */
+ rv = (funcs->C_GetSlotList) (FALSE, NULL, &count);
+ if (rv == CKR_OK && count) {
+ slots = calloc (sizeof (CK_SLOT_ID), count);
+ rv = (funcs->C_GetSlotList) (FALSE, slots, &count);
+ }
if (rv != CKR_OK) {
free (slots);
@@ -267,41 +284,38 @@ initialize_mappings_unlocked_reentrant (void)
return_val_if_fail (count == 0 || slots != NULL, CKR_GENERAL_ERROR);
- mappings = realloc (mappings, sizeof (Mapping) * (n_mappings + count));
- return_val_if_fail (mappings != NULL, CKR_HOST_MEMORY);
+ py->mappings = realloc (py->mappings, sizeof (Mapping) * (py->n_mappings + count));
+ return_val_if_fail (py->mappings != NULL, CKR_HOST_MEMORY);
/* And now add a mapping for each of those slots */
for (i = 0; i < count; ++i) {
- mappings[n_mappings].funcs = funcs;
- mappings[n_mappings].wrap_slot = n_mappings + MAPPING_OFFSET;
- mappings[n_mappings].real_slot = slots[i];
- ++n_mappings;
+ py->mappings[py->n_mappings].funcs = funcs;
+ py->mappings[py->n_mappings].wrap_slot = py->n_mappings + MAPPING_OFFSET;
+ py->mappings[py->n_mappings].real_slot = slots[i];
+ ++py->n_mappings;
}
free (slots);
}
- free (funcss);
-
- /* Another thread raced us here due to above reentrancy */
- if (gl.mappings) {
- free (mappings);
- return CKR_OK;
+ if (rv != CKR_OK) {
+ proxy_free (py);
+ return rv;
}
- assert (!gl.sessions);
- gl.mappings = mappings;
- gl.n_mappings = n_mappings;
- gl.sessions = p11_dict_new (p11_dict_ulongptr_hash, p11_dict_ulongptr_equal, NULL, free);
- ++gl.mappings_refs;
+ py->sessions = p11_dict_new (p11_dict_ulongptr_hash, p11_dict_ulongptr_equal, NULL, free);
+ return_val_if_fail (py->sessions != NULL, CKR_HOST_MEMORY);
+ py->refs = 1;
- /* Any cleanup necessary for failure will happen at caller */
- return rv;
+ *res = py;
+ return CKR_OK;
}
static CK_RV
proxy_C_Initialize (CK_VOID_PTR init_args)
{
+ bool initialize = false;
+ Proxy *py;
CK_RV rv;
p11_library_init_once ();
@@ -312,21 +326,35 @@ proxy_C_Initialize (CK_VOID_PTR init_args)
p11_lock ();
- /* WARNING: Reentrancy can occur here */
- rv = _p11_kit_initialize_registered_unlocked_reentrant ();
-
- /* WARNING: Reentrancy can occur here */
- if (rv == CKR_OK && gl.mappings_refs == 0)
- rv = initialize_mappings_unlocked_reentrant ();
+ if (px == NULL)
+ initialize = true;
+ else
+ px->refs++;
p11_unlock ();
- p11_debug ("here");
+ if (!initialize) {
+ p11_debug ("out: already: %lu", CKR_OK);
+ return CKR_OK;
+ }
- if (rv != CKR_OK)
- proxy_C_Finalize (NULL);
+ rv = proxy_create (&py);
+ if (rv != CKR_OK) {
+ p11_debug ("out: %lu", rv);
+ return rv;
+ }
- p11_debug ("out: %lu", rv);
+ p11_lock ();
+
+ if (px == NULL) {
+ px = py;
+ py = NULL;
+ }
+
+ p11_unlock ();
+
+ proxy_free (py);
+ p11_debug ("out: 0");
return rv;
}
@@ -341,7 +369,7 @@ proxy_C_GetInfo (CK_INFO_PTR info)
p11_lock ();
- if (!gl.mappings)
+ if (!px)
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
p11_unlock ();
@@ -383,14 +411,14 @@ proxy_C_GetSlotList (CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list,
p11_lock ();
- if (!gl.mappings) {
+ if (!px->mappings) {
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
} else {
index = 0;
/* Go through and build up a map */
- for (i = 0; i < gl.n_mappings; ++i) {
- mapping = &gl.mappings[i];
+ for (i = 0; i < px->n_mappings; ++i) {
+ mapping = &px->mappings[i];
/* Skip ones without a token if requested */
if (token_present) {
@@ -506,7 +534,7 @@ proxy_C_OpenSession (CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
if (rv == CKR_OK) {
p11_lock ();
- if (!gl.sessions) {
+ if (!px) {
/*
* The underlying module should have returned an error, so this
* code should never be reached with properly behaving modules.
@@ -519,8 +547,8 @@ proxy_C_OpenSession (CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
sess = calloc (1, sizeof (Session));
sess->wrap_slot = map.wrap_slot;
sess->real_session = *handle;
- sess->wrap_session = ++gl.last_handle; /* TODO: Handle wrapping, and then collisions */
- p11_dict_set (gl.sessions, &sess->wrap_session, sess);
+ sess->wrap_session = ++px->last_handle; /* TODO: Handle wrapping, and then collisions */
+ p11_dict_set (px->sessions, &sess->wrap_session, sess);
*handle = sess->wrap_session;
}
@@ -546,8 +574,8 @@ proxy_C_CloseSession (CK_SESSION_HANDLE handle)
if (rv == CKR_OK) {
p11_lock ();
- if (gl.sessions)
- p11_dict_remove (gl.sessions, &key);
+ if (px)
+ p11_dict_remove (px->sessions, &key);
p11_unlock ();
}
@@ -566,14 +594,15 @@ proxy_C_CloseAllSessions (CK_SLOT_ID id)
p11_lock ();
- if (!gl.sessions) {
+ if (!px) {
rv = CKR_CRYPTOKI_NOT_INITIALIZED;
} else {
- to_close = calloc (sizeof (CK_SESSION_HANDLE), p11_dict_size (gl.sessions));
+ assert (px->sessions);
+ to_close = calloc (sizeof (CK_SESSION_HANDLE), p11_dict_size (px->sessions));
if (!to_close) {
rv = CKR_HOST_MEMORY;
} else {
- p11_dict_iterate (gl.sessions, &iter);
+ p11_dict_iterate (px->sessions, &iter);
count = 0;
while (p11_dict_next (&iter, NULL, (void**)&sess)) {
if (sess->wrap_slot == id && to_close)
diff --git a/p11-kit/tests/Makefile.am b/p11-kit/tests/Makefile.am
index 715fca0..0c5c246 100644
--- a/p11-kit/tests/Makefile.am
+++ b/p11-kit/tests/Makefile.am
@@ -23,13 +23,17 @@ CHECK_PROGS = \
pin-test \
test-init \
test-modules \
+ test-deprecated \
+ test-proxy \
test-iter \
$(NULL)
if WITH_FFI
CHECK_PROGS += \
- test-virtual
+ test-virtual \
+ test-managed \
+ $(NULL)
endif
@@ -75,4 +79,6 @@ mock_four_la_LDFLAGS = $(mock_one_la_LDFLAGS)
mock_four_la_LIBADD = $(mock_one_la_LIBADD)
EXTRA_DIST = \
- files
+ files \
+ test-mock.c \
+ $(NULL)
diff --git a/p11-kit/tests/files/system-pkcs11.conf b/p11-kit/tests/files/system-pkcs11.conf
index 20741e7..a3aa273 100644
--- a/p11-kit/tests/files/system-pkcs11.conf
+++ b/p11-kit/tests/files/system-pkcs11.conf
@@ -1,3 +1,6 @@
# Merge in user config
-user-config: merge \ No newline at end of file
+user-config: merge
+
+# Another option
+new: world \ No newline at end of file
diff --git a/p11-kit/tests/files/user-modules/one.module b/p11-kit/tests/files/user-modules/one.module
index c371e4a..6f1a2e8 100644
--- a/p11-kit/tests/files/user-modules/one.module
+++ b/p11-kit/tests/files/user-modules/one.module
@@ -1,2 +1,3 @@
-setting: user1 \ No newline at end of file
+setting: user1
+managed: yes \ No newline at end of file
diff --git a/p11-kit/tests/test-deprecated.c b/p11-kit/tests/test-deprecated.c
new file mode 100644
index 0000000..4509241
--- /dev/null
+++ b/p11-kit/tests/test-deprecated.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2011, Collabora Ltd.
+ * Copyright (c) 2012 Red Hat Inc
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+#define P11_KIT_NO_DEPRECATIONS
+
+#include "config.h"
+#include "CuTest.h"
+
+#include "dict.h"
+#include "library.h"
+#include "p11-kit.h"
+#include "private.h"
+#include "mock.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+static CK_FUNCTION_LIST_PTR_PTR
+initialize_and_get_modules (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR_PTR modules;
+ CK_RV rv;
+
+ rv = p11_kit_initialize_registered ();
+ CuAssertIntEquals (tc, CKR_OK, rv);
+ modules = p11_kit_registered_modules ();
+ CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
+
+ return modules;
+}
+
+static void
+finalize_and_free_modules (CuTest *tc,
+ CK_FUNCTION_LIST_PTR_PTR modules)
+{
+ CK_RV rv;
+
+ free (modules);
+ rv = p11_kit_finalize_registered ();
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+}
+
+static void
+test_no_duplicates (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR_PTR modules;
+ p11_dict *paths;
+ p11_dict *funcs;
+ char *path;
+ int i;
+
+ modules = initialize_and_get_modules (tc);
+ paths = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL);
+ funcs = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, NULL, NULL);
+
+ /* The loaded modules should not contain duplicates */
+ for (i = 0; modules[i] != NULL; i++) {
+ path = p11_kit_registered_option (modules[i], "module");
+
+ if (p11_dict_get (funcs, modules[i]))
+ CuAssert (tc, "found duplicate function list pointer", 0);
+ if (p11_dict_get (paths, path))
+ CuAssert (tc, "found duplicate path name", 0);
+
+ if (!p11_dict_set (funcs, modules[i], ""))
+ CuAssert (tc, "shouldn't be reached", 0);
+ if (!p11_dict_set (paths, path, ""))
+ CuAssert (tc, "shouldn't be reached", 0);
+
+ free (path);
+ }
+
+ p11_dict_free (paths);
+ p11_dict_free (funcs);
+ finalize_and_free_modules (tc, modules);
+}
+
+static CK_FUNCTION_LIST_PTR
+lookup_module_with_name (CuTest *tc,
+ CK_FUNCTION_LIST_PTR_PTR modules,
+ const char *name)
+{
+ CK_FUNCTION_LIST_PTR match = NULL;
+ CK_FUNCTION_LIST_PTR module;
+ char *module_name;
+ int i;
+
+ for (i = 0; match == NULL && modules[i] != NULL; i++) {
+ module_name = p11_kit_registered_module_to_name (modules[i]);
+ CuAssertPtrNotNull (tc, module_name);
+ if (strcmp (module_name, name) == 0)
+ match = modules[i];
+ free (module_name);
+ }
+
+ /*
+ * As a side effect, we should check that the results of this function
+ * matches the above search.
+ */
+ module = p11_kit_registered_name_to_module (name);
+ CuAssert(tc, "different result from p11_kit_registered_name_to_module()",
+ module == match);
+
+ return match;
+}
+
+static void
+test_disable (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR_PTR modules;
+
+ /*
+ * The module four should be present, as we don't match any prognames
+ * that it has disabled.
+ */
+
+ modules = initialize_and_get_modules (tc);
+ CuAssertTrue (tc, lookup_module_with_name (tc, modules, "four") != NULL);
+ finalize_and_free_modules (tc, modules);
+
+ /*
+ * The module two shouldn't have been loaded, because in its config
+ * file we have:
+ *
+ * disable-in: test-disable
+ */
+
+ p11_kit_set_progname ("test-disable");
+
+ modules = initialize_and_get_modules (tc);
+ CuAssertTrue (tc, lookup_module_with_name (tc, modules, "four") == NULL);
+ finalize_and_free_modules (tc, modules);
+
+ p11_kit_set_progname (NULL);
+}
+
+static void
+test_disable_later (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR_PTR modules;
+ CK_RV rv;
+
+ /*
+ * The module two shouldn't be matched, because in its config
+ * file we have:
+ *
+ * disable-in: test-disable
+ */
+
+ rv = p11_kit_initialize_registered ();
+ CuAssertIntEquals (tc, CKR_OK, rv);
+
+ p11_kit_set_progname ("test-disable");
+
+ modules = p11_kit_registered_modules ();
+ CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
+
+ CuAssertTrue (tc, lookup_module_with_name (tc, modules, "two") == NULL);
+ finalize_and_free_modules (tc, modules);
+
+ p11_kit_set_progname (NULL);
+}
+
+static void
+test_enable (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR_PTR modules;
+
+ /*
+ * The module three should not be present, as we don't match the current
+ * program.
+ */
+
+ modules = initialize_and_get_modules (tc);
+ CuAssertTrue (tc, lookup_module_with_name (tc, modules, "three") == NULL);
+ finalize_and_free_modules (tc, modules);
+
+ /*
+ * The module three should be loaded here , because in its config
+ * file we have:
+ *
+ * enable-in: test-enable
+ */
+
+ p11_kit_set_progname ("test-enable");
+
+ modules = initialize_and_get_modules (tc);
+ CuAssertTrue (tc, lookup_module_with_name (tc, modules, "three") != NULL);
+ finalize_and_free_modules (tc, modules);
+
+ p11_kit_set_progname (NULL);
+}
+
+CK_FUNCTION_LIST module;
+
+#ifdef OS_UNIX
+
+#include <sys/wait.h>
+
+static CK_RV
+mock_C_Initialize__with_fork (CK_VOID_PTR init_args)
+{
+ struct timespec ts = { 0, 100 * 1000 * 1000 };
+ CK_RV rv;
+ pid_t child;
+ pid_t ret;
+ int status;
+
+ rv = mock_C_Initialize (init_args);
+ assert (rv == CKR_OK);
+
+ /* Fork during the initialization */
+ child = fork ();
+ if (child == 0) {
+ nanosleep (&ts, NULL);
+ exit (66);
+ }
+
+ ret = waitpid (child, &status, 0);
+ assert (ret == child);
+ assert (WIFEXITED (status));
+ assert (WEXITSTATUS (status) == 66);
+
+ return CKR_OK;
+}
+
+static void
+test_fork_initialization (CuTest *tc)
+{
+ CK_RV rv;
+
+ CuAssertTrue (tc, !mock_module_initialized ());
+
+ /* Build up our own function list */
+ memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
+ module.C_Initialize = mock_C_Initialize__with_fork;
+
+ rv = p11_kit_initialize_module (&module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = p11_kit_finalize_module (&module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertTrue (tc, !mock_module_initialized ());
+}
+
+#endif /* OS_UNIX */
+
+static CK_RV
+mock_C_Initialize__with_recursive (CK_VOID_PTR init_args)
+{
+ /* Recursively initialize, this is broken */
+ return p11_kit_initialize_module (&module);
+}
+
+static void
+test_recursive_initialization (CuTest *tc)
+{
+ CK_RV rv;
+
+ CuAssertTrue (tc, !mock_module_initialized ());
+
+ /* Build up our own function list */
+ memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
+ module.C_Initialize = mock_C_Initialize__with_recursive;
+
+ rv = p11_kit_initialize_module (&module);
+ CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED);
+
+ CuAssertTrue (tc, !mock_module_initialized ());
+}
+
+static p11_mutex_t race_mutex;
+static int initialization_count = 0;
+static int finalization_count = 0;
+
+static CK_RV
+mock_C_Initialize__threaded_race (CK_VOID_PTR init_args)
+{
+ /* Atomically increment value */
+ p11_mutex_lock (&race_mutex);
+ initialization_count += 1;
+ p11_mutex_unlock (&race_mutex);
+
+ p11_sleep_ms (100);
+ return CKR_OK;
+}
+
+static CK_RV
+mock_C_Finalize__threaded_race (CK_VOID_PTR reserved)
+{
+ /* Atomically increment value */
+ p11_mutex_lock (&race_mutex);
+ finalization_count += 1;
+ p11_mutex_unlock (&race_mutex);
+
+ p11_sleep_ms (100);
+ return CKR_OK;
+}
+
+static void *
+initialization_thread (void *data)
+{
+ CuTest *tc = data;
+ CK_RV rv;
+
+ rv = p11_kit_initialize_module (&module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ return tc;
+}
+
+static void *
+finalization_thread (void *data)
+{
+ CuTest *tc = data;
+ CK_RV rv;
+
+ rv = p11_kit_finalize_module (&module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ return tc;
+}
+
+static void
+test_threaded_initialization (CuTest *tc)
+{
+ static const int num_threads = 2;
+ p11_thread_t threads[num_threads];
+ int ret;
+ int i;
+
+ CuAssertTrue (tc, !mock_module_initialized ());
+
+ /* Build up our own function list */
+ memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
+ module.C_Initialize = mock_C_Initialize__threaded_race;
+ module.C_Finalize = mock_C_Finalize__threaded_race;
+
+ initialization_count = 0;
+ finalization_count = 0;
+
+ for (i = 0; i < num_threads; i++) {
+ ret = p11_thread_create (&threads[i], initialization_thread, tc);
+ CuAssertIntEquals (tc, 0, ret);
+ CuAssertTrue (tc, threads[i] != 0);
+ }
+
+ for (i = 0; i < num_threads; i++) {
+ ret = p11_thread_join (threads[i]);
+ CuAssertIntEquals (tc, 0, ret);
+ threads[i] = 0;
+ }
+
+ for (i = 0; i < num_threads; i++) {
+ ret = p11_thread_create (&threads[i], finalization_thread, tc);
+ CuAssertIntEquals (tc, 0, ret);
+ CuAssertTrue (tc, threads[i] != 0);
+ }
+
+ for (i = 0; i < num_threads; i++) {
+ ret = p11_thread_join (threads[i]);
+ CuAssertIntEquals (tc, 0, ret);
+ threads[i] = 0;
+ }
+
+ /* C_Initialize should have been called exactly once */
+ CuAssertIntEquals (tc, 1, initialization_count);
+ CuAssertIntEquals (tc, 1, finalization_count);
+
+ CuAssertTrue (tc, !mock_module_initialized ());
+}
+
+static CK_RV
+mock_C_Initialize__test_mutexes (CK_VOID_PTR args)
+{
+ CK_C_INITIALIZE_ARGS_PTR init_args;
+ void *mutex = NULL;
+ CK_RV rv;
+
+ rv = mock_C_Initialize (NULL);
+ if (rv != CKR_OK)
+ return rv;
+
+ assert (args != NULL);
+ init_args = args;
+
+ rv = (init_args->CreateMutex) (&mutex);
+ assert (rv == CKR_OK);
+
+ rv = (init_args->LockMutex) (mutex);
+ assert (rv == CKR_OK);
+
+ rv = (init_args->UnlockMutex) (mutex);
+ assert (rv == CKR_OK);
+
+ rv = (init_args->DestroyMutex) (mutex);
+ assert (rv == CKR_OK);
+
+ return CKR_OK;
+}
+
+static void
+test_mutexes (CuTest *tc)
+{
+ CK_RV rv;
+
+ CuAssertTrue (tc, !mock_module_initialized ());
+
+ /* Build up our own function list */
+ memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
+ module.C_Initialize = mock_C_Initialize__test_mutexes;
+
+ rv = p11_kit_initialize_module (&module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = p11_kit_finalize_module (&module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertTrue (tc, !mock_module_initialized ());
+}
+
+static void
+test_load_and_initialize (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_INFO info;
+ CK_RV rv;
+ int ret;
+
+ rv = p11_kit_load_initialize_module (BUILDDIR "/.libs/mock-one" SHLEXT, &module);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertTrue (tc, module != NULL);
+
+ rv = (module->C_GetInfo) (&info);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ ret = memcmp (info.manufacturerID, "MOCK MANUFACTURER ", 32);
+ CuAssertTrue (tc, ret == 0);
+
+ rv = p11_kit_finalize_module (module);
+ CuAssertTrue (tc, ret == CKR_OK);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ putenv ("P11_KIT_STRICT=1");
+ p11_mutex_init (&race_mutex);
+ mock_module_init ();
+ p11_library_init ();
+
+ SUITE_ADD_TEST (suite, test_no_duplicates);
+ SUITE_ADD_TEST (suite, test_disable);
+ SUITE_ADD_TEST (suite, test_disable_later);
+ SUITE_ADD_TEST (suite, test_enable);
+
+#ifdef OS_UNIX
+ SUITE_ADD_TEST (suite, test_fork_initialization);
+#endif
+
+ SUITE_ADD_TEST (suite, test_recursive_initialization);
+ SUITE_ADD_TEST (suite, test_threaded_initialization);
+ SUITE_ADD_TEST (suite, test_mutexes);
+ SUITE_ADD_TEST (suite, test_load_and_initialize);
+
+ p11_kit_be_quiet ();
+
+ CuSuiteRun (suite);
+ CuSuiteSummary (suite, output);
+ CuSuiteDetails (suite, output);
+ printf ("%s\n", output->buffer);
+ ret = suite->failCount;
+ CuSuiteDelete (suite);
+ CuStringDelete (output);
+ return ret;
+}
diff --git a/p11-kit/tests/test-init.c b/p11-kit/tests/test-init.c
index 7df4be9..f2347c8 100644
--- a/p11-kit/tests/test-init.c
+++ b/p11-kit/tests/test-init.c
@@ -38,6 +38,11 @@
#include <sys/types.h>
#include "library.h"
+#include "mock.h"
+#include "modules.h"
+#include "p11-kit.h"
+#include "private.h"
+#include "virtual.h"
#include <assert.h>
#include <stdio.h>
@@ -46,11 +51,8 @@
#include <time.h>
#include <unistd.h>
-#include "p11-kit/p11-kit.h"
-
-#include "mock.h"
-
-CK_FUNCTION_LIST module;
+static CK_FUNCTION_LIST module;
+static p11_mutex_t race_mutex;
#ifdef OS_UNIX
@@ -86,21 +88,40 @@ mock_C_Initialize__with_fork (CK_VOID_PTR init_args)
static void
test_fork_initialization (CuTest *tc)
{
+ CK_FUNCTION_LIST_PTR result;
CK_RV rv;
+ mock_module_reset ();
+
/* Build up our own function list */
memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
module.C_Initialize = mock_C_Initialize__with_fork;
- rv = p11_kit_initialize_module (&module);
+ p11_lock ();
+
+ rv = p11_module_load_inlock_reentrant (&module, 0, &result);
CuAssertTrue (tc, rv == CKR_OK);
- rv = p11_kit_finalize_module (&module);
+ p11_unlock ();
+
+ rv = p11_kit_module_initialize (result);
CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = p11_kit_module_finalize (result);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ p11_lock ();
+
+ rv = p11_module_release_inlock_reentrant (result);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ p11_unlock ();
}
#endif /* OS_UNIX */
+static CK_FUNCTION_LIST *recursive_managed;
+
static CK_RV
mock_C_Initialize__with_recursive (CK_VOID_PTR init_args)
{
@@ -109,8 +130,7 @@ mock_C_Initialize__with_recursive (CK_VOID_PTR init_args)
rv = mock_C_Initialize (init_args);
assert (rv == CKR_OK);
- /* Recursively initialize, this is broken */
- return p11_kit_initialize_module (&module);
+ return p11_kit_module_initialize (recursive_managed);
}
static void
@@ -122,16 +142,24 @@ test_recursive_initialization (CuTest *tc)
memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
module.C_Initialize = mock_C_Initialize__with_recursive;
- rv = p11_kit_initialize_module (&module);
+ p11_kit_be_quiet ();
+
+ p11_lock ();
+
+ rv = p11_module_load_inlock_reentrant (&module, 0, &recursive_managed);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ p11_unlock ();
+
+ rv = p11_kit_module_initialize (recursive_managed);
CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED);
+
+ p11_kit_be_loud ();
}
-static p11_mutex_t race_mutex;
static int initialization_count = 0;
static int finalization_count = 0;
-#include "private.h"
-
static CK_RV
mock_C_Initialize__threaded_race (CK_VOID_PTR init_args)
{
@@ -156,35 +184,44 @@ mock_C_Finalize__threaded_race (CK_VOID_PTR reserved)
return CKR_OK;
}
+typedef struct {
+ CuTest *cu;
+ CK_FUNCTION_LIST_PTR module;
+} ThreadData;
+
static void *
initialization_thread (void *data)
{
- CuTest *tc = data;
+ ThreadData *td = data;
CK_RV rv;
- rv = p11_kit_initialize_module (&module);
- CuAssertTrue (tc, rv == CKR_OK);
+ assert (td->module != NULL);
+ rv = p11_kit_module_initialize (td->module);
+ CuAssertTrue (td->cu, rv == CKR_OK);
- return tc;
+ return td->cu;
}
static void *
finalization_thread (void *data)
{
- CuTest *tc = data;
+ ThreadData *td = data;
CK_RV rv;
- rv = p11_kit_finalize_module (&module);
- CuAssertTrue (tc, rv == CKR_OK);
+ assert (td->module != NULL);
+ rv = p11_kit_module_finalize (td->module);
+ CuAssertTrue (td->cu, rv == CKR_OK);
- return tc;
+ return td->cu;
}
static void
test_threaded_initialization (CuTest *tc)
{
- static const int num_threads = 2;
+ static const int num_threads = 1;
+ ThreadData data[num_threads];
p11_thread_t threads[num_threads];
+ CK_RV rv;
int ret;
int i;
@@ -193,11 +230,23 @@ test_threaded_initialization (CuTest *tc)
module.C_Initialize = mock_C_Initialize__threaded_race;
module.C_Finalize = mock_C_Finalize__threaded_race;
+ memset (&data, 0, sizeof (data));
initialization_count = 0;
finalization_count = 0;
+ p11_lock ();
+
for (i = 0; i < num_threads; i++) {
- ret = p11_thread_create (&threads[i], initialization_thread, tc);
+ assert (data[i].module == NULL);
+ rv = p11_module_load_inlock_reentrant (&module, 0, &data[i].module);
+ CuAssertTrue (tc, rv == CKR_OK);
+ }
+
+ p11_unlock ();
+
+ for (i = 0; i < num_threads; i++) {
+ data[i].cu = tc;
+ ret = p11_thread_create (&threads[i], initialization_thread, data + i);
CuAssertIntEquals (tc, 0, ret);
CuAssertTrue (tc, threads[i] != 0);
}
@@ -209,7 +258,7 @@ test_threaded_initialization (CuTest *tc)
}
for (i = 0; i < num_threads; i++) {
- ret = p11_thread_create (&threads[i], finalization_thread, tc);
+ ret = p11_thread_create (&threads[i], finalization_thread, data + i);
CuAssertIntEquals (tc, 0, ret);
CuAssertTrue (tc, threads[i] != 0);
}
@@ -220,6 +269,16 @@ test_threaded_initialization (CuTest *tc)
threads[i] = 0;
}
+ p11_lock ();
+
+ for (i = 0; i < num_threads; i++) {
+ assert (data[i].module != NULL);
+ rv = p11_module_release_inlock_reentrant (data[i].module);
+ CuAssertTrue (tc, rv == CKR_OK);
+ }
+
+ p11_unlock ();
+
/* C_Initialize should have been called exactly once */
CuAssertIntEquals (tc, 1, initialization_count);
CuAssertIntEquals (tc, 1, finalization_count);
@@ -253,17 +312,22 @@ mock_C_Initialize__test_mutexes (CK_VOID_PTR args)
static void
test_mutexes (CuTest *tc)
{
+ CK_FUNCTION_LIST_PTR result;
CK_RV rv;
/* Build up our own function list */
memcpy (&module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST));
module.C_Initialize = mock_C_Initialize__test_mutexes;
- rv = p11_kit_initialize_module (&module);
+ p11_lock ();
+
+ rv = p11_module_load_inlock_reentrant (&module, 0, &result);
CuAssertTrue (tc, rv == CKR_OK);
- rv = p11_kit_finalize_module (&module);
+ rv = p11_module_release_inlock_reentrant (result);
CuAssertTrue (tc, rv == CKR_OK);
+
+ p11_unlock ();
}
static void
@@ -274,18 +338,54 @@ test_load_and_initialize (CuTest *tc)
CK_RV rv;
int ret;
- rv = p11_kit_load_initialize_module (BUILDDIR "/.libs/mock-one" SHLEXT, &module);
- CuAssertTrue (tc, rv == CKR_OK);
+ module = p11_kit_module_load (BUILDDIR "/.libs/mock-one" SHLEXT, 0);
CuAssertTrue (tc, module != NULL);
+ rv = p11_kit_module_initialize (module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
rv = (module->C_GetInfo) (&info);
CuAssertTrue (tc, rv == CKR_OK);
ret = memcmp (info.manufacturerID, "MOCK MANUFACTURER ", 32);
CuAssertTrue (tc, ret == 0);
- rv = p11_kit_finalize_module (module);
- CuAssertTrue (tc, ret == CKR_OK);
+ rv = p11_kit_module_finalize (module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ p11_kit_module_release (module);
+}
+
+static void
+test_initalize_fail (CuTest *tc)
+{
+ CK_FUNCTION_LIST failer;
+ CK_FUNCTION_LIST *modules[3] = { &mock_module_no_slots, &failer, NULL };
+ CK_RV rv;
+
+ memcpy (&failer, &mock_module, sizeof (CK_FUNCTION_LIST));
+ failer.C_Initialize = mock_C_Initialize__fails;
+
+ mock_module_reset ();
+ p11_kit_be_quiet ();
+
+ rv = p11_kit_modules_initialize (modules, NULL);
+ CuAssertIntEquals (tc, CKR_FUNCTION_FAILED, rv);
+
+ p11_kit_be_loud ();
+
+ /* Failed modules get removed from the list */
+ CuAssertPtrEquals (tc, &mock_module_no_slots, modules[0]);
+ CuAssertPtrEquals (tc, NULL, modules[1]);
+ CuAssertPtrEquals (tc, NULL, modules[2]);
+
+ p11_kit_modules_finalize (modules);
+}
+
+static void
+test_finalize_fail (CuTest *tc)
+{
+
}
int
@@ -300,14 +400,20 @@ main (void)
mock_module_init ();
p11_library_init ();
+ /* These only work when managed */
+ if (p11_virtual_can_wrap ()) {
+ SUITE_ADD_TEST (suite, test_recursive_initialization);
+ SUITE_ADD_TEST (suite, test_threaded_initialization);
+ SUITE_ADD_TEST (suite, test_mutexes);
+ SUITE_ADD_TEST (suite, test_load_and_initialize);
+
#ifdef OS_UNIX
- SUITE_ADD_TEST (suite, test_fork_initialization);
+ SUITE_ADD_TEST (suite, test_fork_initialization);
#endif
+ }
- SUITE_ADD_TEST (suite, test_recursive_initialization);
- SUITE_ADD_TEST (suite, test_threaded_initialization);
- SUITE_ADD_TEST (suite, test_mutexes);
- SUITE_ADD_TEST (suite, test_load_and_initialize);
+ SUITE_ADD_TEST (suite, test_initalize_fail);
+ SUITE_ADD_TEST (suite, test_finalize_fail);
CuSuiteRun (suite);
CuSuiteSummary (suite, output);
diff --git a/p11-kit/tests/test-iter.c b/p11-kit/tests/test-iter.c
index 08e43b3..451f4be 100644
--- a/p11-kit/tests/test-iter.c
+++ b/p11-kit/tests/test-iter.c
@@ -52,13 +52,10 @@ static CK_FUNCTION_LIST_PTR_PTR
initialize_and_get_modules (CuTest *tc)
{
CK_FUNCTION_LIST_PTR_PTR modules;
- CK_RV rv;
p11_message_quiet ();
- rv = p11_kit_initialize_registered ();
- CuAssertIntEquals (tc, CKR_OK, rv);
- modules = p11_kit_registered_modules ();
+ modules = p11_kit_modules_load_and_initialize (0);
CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
p11_message_loud ();
@@ -70,11 +67,8 @@ static void
finalize_and_free_modules (CuTest *tc,
CK_FUNCTION_LIST_PTR_PTR modules)
{
- CK_RV rv;
-
- free (modules);
- rv = p11_kit_finalize_registered ();
- CuAssertIntEquals (tc, CKR_OK, rv);
+ p11_kit_modules_finalize (modules);
+ p11_kit_modules_release (modules);
}
static int
@@ -282,7 +276,8 @@ test_with_session (CuTest *tc)
CK_RV rv;
int at;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
rv = mock_C_OpenSession (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
@@ -323,7 +318,7 @@ test_with_session (CuTest *tc)
rv = mock_module.C_CloseSession (session);
CuAssertTrue (tc, rv == CKR_OK);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -337,7 +332,8 @@ test_with_slot (CuTest *tc)
CK_RV rv;
int at;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
iter = p11_kit_iter_new (NULL);
@@ -369,7 +365,7 @@ test_with_slot (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = (mock_module.C_Finalize) (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -382,7 +378,8 @@ test_with_module (CuTest *tc)
CK_RV rv;
int at;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
iter = p11_kit_iter_new (NULL);
@@ -411,7 +408,7 @@ test_with_module (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -422,7 +419,8 @@ test_keep_session (CuTest *tc)
P11KitIter *iter;
CK_RV rv;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
iter = p11_kit_iter_new (NULL);
@@ -438,7 +436,7 @@ test_keep_session (CuTest *tc)
rv = mock_module.C_CloseSession (session);
CuAssertTrue (tc, rv == CKR_OK);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -750,7 +748,8 @@ test_getslotlist_fail_first (CuTest *tc)
CK_RV rv;
int at;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -770,7 +769,7 @@ test_getslotlist_fail_first (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -782,7 +781,8 @@ test_getslotlist_fail_late (CuTest *tc)
CK_RV rv;
int at;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -802,7 +802,7 @@ test_getslotlist_fail_late (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -814,7 +814,8 @@ test_open_session_fail (CuTest *tc)
CK_RV rv;
int at;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -834,7 +835,7 @@ test_open_session_fail (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -846,7 +847,8 @@ test_find_init_fail (CuTest *tc)
CK_RV rv;
int at;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -866,7 +868,7 @@ test_find_init_fail (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -878,7 +880,8 @@ test_find_objects_fail (CuTest *tc)
CK_RV rv;
int at;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -898,7 +901,7 @@ test_find_objects_fail (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -972,7 +975,8 @@ test_load_attributes_none (CuTest *tc)
CK_ATTRIBUTE *attrs;
CK_RV rv;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -991,7 +995,7 @@ test_load_attributes_none (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -1004,7 +1008,8 @@ test_load_attributes_fail_first (CuTest *tc)
CK_ATTRIBUTE *attrs;
CK_RV rv;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -1024,7 +1029,7 @@ test_load_attributes_fail_first (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
@@ -1037,7 +1042,8 @@ test_load_attributes_fail_late (CuTest *tc)
CK_ATTRIBUTE *attrs;
CK_RV rv;
- rv = p11_kit_initialize_module (&mock_module);
+ mock_module_reset ();
+ rv = mock_module.C_Initialize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST));
@@ -1057,7 +1063,7 @@ test_load_attributes_fail_late (CuTest *tc)
p11_kit_iter_free (iter);
- rv = p11_kit_finalize_module (&mock_module);
+ rv = mock_module.C_Finalize (NULL);
CuAssertTrue (tc, rv == CKR_OK);
}
diff --git a/p11-kit/tests/test-managed.c b/p11-kit/tests/test-managed.c
new file mode 100644
index 0000000..8a6a1e8
--- /dev/null
+++ b/p11-kit/tests/test-managed.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2012 Red Hat Inc
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include "dict.h"
+#include "library.h"
+#include "mock.h"
+#include "modules.h"
+#include "p11-kit.h"
+#include "virtual.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static CK_FUNCTION_LIST_PTR
+setup_mock_module (CuTest *tc,
+ CK_SESSION_HANDLE *session)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_RV rv;
+
+ p11_lock ();
+
+ rv = p11_module_load_inlock_reentrant (&mock_module, 0, &module);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertPtrNotNull (tc, module);
+ CuAssertTrue (tc, p11_virtual_is_wrapper (module));
+
+ p11_unlock ();
+
+ rv = p11_kit_module_initialize (module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ if (session) {
+ rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID,
+ CKF_RW_SESSION | CKF_SERIAL_SESSION,
+ NULL, NULL, session);
+ CuAssertTrue (tc, rv == CKR_OK);
+ }
+
+ return module;
+}
+
+static void
+teardown_mock_module (CuTest *tc,
+ CK_FUNCTION_LIST_PTR module)
+{
+ CK_RV rv;
+
+ rv = p11_kit_module_finalize (module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ p11_lock ();
+
+ rv = p11_module_release_inlock_reentrant (module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ p11_unlock ();
+}
+
+static CK_RV
+fail_C_Initialize (void *init_reserved)
+{
+ return CKR_FUNCTION_FAILED;
+}
+
+static void
+test_initialize_finalize (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = module->C_Initialize (NULL);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = module->C_Finalize (NULL);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_initialize_fail (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_FUNCTION_LIST base;
+ CK_RV rv;
+
+ memcpy (&base, &mock_module, sizeof (CK_FUNCTION_LIST));
+ base.C_Initialize = fail_C_Initialize;
+
+ p11_lock ();
+
+ rv = p11_module_load_inlock_reentrant (&base, 0, &module);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ p11_unlock ();
+
+ rv = p11_kit_module_initialize (module);
+ CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED);
+}
+
+/* Bring in all the mock module tests */
+#include "test-mock.c"
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ putenv ("P11_KIT_STRICT=1");
+ mock_module_init ();
+ p11_library_init ();
+
+ SUITE_ADD_TEST (suite, test_initialize_finalize);
+ SUITE_ADD_TEST (suite, test_initialize_fail);
+ test_mock_add_tests (suite);
+
+ p11_kit_be_quiet ();
+
+ CuSuiteRun (suite);
+ CuSuiteSummary (suite, output);
+ CuSuiteDetails (suite, output);
+ printf ("%s\n", output->buffer);
+ ret = suite->failCount;
+ CuSuiteDelete (suite);
+ CuStringDelete (output);
+ return ret;
+}
diff --git a/p11-kit/tests/test-mock.c b/p11-kit/tests/test-mock.c
new file mode 100644
index 0000000..955174f
--- /dev/null
+++ b/p11-kit/tests/test-mock.c
@@ -0,0 +1,1687 @@
+/*
+ * Copyright (c) 2012 Stefan Walter
+ * Copyright (c) 2012-2013 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stef@thewalter.net>
+ */
+
+#include "CuTest.h"
+
+#include "library.h"
+#include "mock.h"
+#include "p11-kit.h"
+
+#include <sys/types.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void
+test_get_info (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_INFO info;
+ CK_RV rv;
+ char *string;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_GetInfo) (&info);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, CRYPTOKI_VERSION_MAJOR, info.cryptokiVersion.major);
+ CuAssertIntEquals (tc, CRYPTOKI_VERSION_MINOR, info.cryptokiVersion.minor);
+ string = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID));
+ CuAssertStrEquals (tc, "MOCK MANUFACTURER", string);
+ free (string);
+ string = p11_kit_space_strdup (info.libraryDescription, sizeof (info.libraryDescription));
+ CuAssertStrEquals (tc, "MOCK LIBRARY", string);
+ free (string);
+ CuAssertIntEquals (tc, 0, info.flags);
+ CuAssertIntEquals (tc, 45, info.libraryVersion.major);
+ CuAssertIntEquals (tc, 145, info.libraryVersion.minor);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_slot_list (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SLOT_ID slot_list[8];
+ CK_ULONG count;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ /* Normal module has 2 slots, one with token present */
+ rv = (module->C_GetSlotList) (CK_TRUE, NULL, &count);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, 1, count);
+ rv = (module->C_GetSlotList) (CK_FALSE, NULL, &count);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, 2, count);
+
+ count = 8;
+ rv = (module->C_GetSlotList) (CK_TRUE, slot_list, &count);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, 1, count);
+ CuAssertIntEquals (tc, MOCK_SLOT_ONE_ID, slot_list[0]);
+
+ count = 8;
+ rv = (module->C_GetSlotList) (CK_FALSE, slot_list, &count);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, 2, count);
+ CuAssertIntEquals (tc, MOCK_SLOT_ONE_ID, slot_list[0]);
+ CuAssertIntEquals (tc, MOCK_SLOT_TWO_ID, slot_list[1]);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_slot_info (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SLOT_INFO info;
+ char *string;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_GetSlotInfo) (MOCK_SLOT_ONE_ID, &info);
+ CuAssertTrue (tc, rv == CKR_OK);
+ string = p11_kit_space_strdup (info.slotDescription, sizeof (info.slotDescription));
+ CuAssertStrEquals (tc, "TEST SLOT", string);
+ free (string);
+ string = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID));
+ CuAssertStrEquals (tc, "TEST MANUFACTURER", string);
+ free (string);
+ CuAssertIntEquals (tc, CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE, info.flags);
+ CuAssertIntEquals (tc, 55, info.hardwareVersion.major);
+ CuAssertIntEquals (tc, 155, info.hardwareVersion.minor);
+ CuAssertIntEquals (tc, 65, info.firmwareVersion.major);
+ CuAssertIntEquals (tc, 165, info.firmwareVersion.minor);
+
+ rv = (module->C_GetSlotInfo) (MOCK_SLOT_TWO_ID, &info);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, CKF_REMOVABLE_DEVICE, info.flags);
+
+ rv = (module->C_GetSlotInfo) (0, &info);
+ CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_token_info (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_TOKEN_INFO info;
+ char *string;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_GetTokenInfo) (MOCK_SLOT_ONE_ID, &info);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ string = p11_kit_space_strdup (info.label, sizeof (info.label));
+ CuAssertStrEquals (tc, "TEST LABEL", string);
+ free (string);
+ string = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID));
+ CuAssertStrEquals (tc, "TEST MANUFACTURER", string);
+ free (string);
+ string = p11_kit_space_strdup (info.model, sizeof (info.model));
+ CuAssertStrEquals (tc, "TEST MODEL", string);
+ free (string);
+ string = p11_kit_space_strdup (info.serialNumber, sizeof (info.serialNumber));
+ CuAssertStrEquals (tc, "TEST SERIAL", string);
+ free (string);
+ CuAssertIntEquals (tc, CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_CLOCK_ON_TOKEN | CKF_TOKEN_INITIALIZED, info.flags);
+ CuAssertIntEquals (tc, 1, info.ulMaxSessionCount);
+ CuAssertIntEquals (tc, 2, info.ulSessionCount);
+ CuAssertIntEquals (tc, 3, info.ulMaxRwSessionCount);
+ CuAssertIntEquals (tc, 4, info.ulRwSessionCount);
+ CuAssertIntEquals (tc, 5, info.ulMaxPinLen);
+ CuAssertIntEquals (tc, 6, info.ulMinPinLen);
+ CuAssertIntEquals (tc, 7, info.ulTotalPublicMemory);
+ CuAssertIntEquals (tc, 8, info.ulFreePublicMemory);
+ CuAssertIntEquals (tc, 9, info.ulTotalPrivateMemory);
+ CuAssertIntEquals (tc, 10, info.ulFreePrivateMemory);
+ CuAssertIntEquals (tc, 75, info.hardwareVersion.major);
+ CuAssertIntEquals (tc, 175, info.hardwareVersion.minor);
+ CuAssertIntEquals (tc, 85, info.firmwareVersion.major);
+ CuAssertIntEquals (tc, 185, info.firmwareVersion.minor);
+ CuAssertTrue (tc, memcmp (info.utcTime, "1999052509195900", sizeof (info.utcTime)) == 0);
+
+ rv = (module->C_GetTokenInfo) (MOCK_SLOT_TWO_ID, &info);
+ CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+
+ rv = (module->C_GetTokenInfo) (0, &info);
+ CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_mechanism_list (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_MECHANISM_TYPE mechs[8];
+ CK_ULONG count;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_GetMechanismList) (MOCK_SLOT_ONE_ID, NULL, &count);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, 2, count);
+ rv = (module->C_GetMechanismList) (MOCK_SLOT_TWO_ID, NULL, &count);
+ CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+ rv = (module->C_GetMechanismList) (0, NULL, &count);
+ CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+ count = 8;
+ rv = (module->C_GetMechanismList) (MOCK_SLOT_ONE_ID, mechs, &count);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, 2, count);
+ CuAssertIntEquals (tc, mechs[0], CKM_MOCK_CAPITALIZE);
+ CuAssertIntEquals (tc, mechs[1], CKM_MOCK_PREFIX);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_mechanism_info (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_MECHANISM_INFO info;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_GetMechanismInfo) (MOCK_SLOT_ONE_ID, CKM_MOCK_CAPITALIZE, &info);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, 512, info.ulMinKeySize);
+ CuAssertIntEquals (tc, 4096, info.ulMaxKeySize);
+ CuAssertIntEquals (tc, CKF_ENCRYPT | CKF_DECRYPT, info.flags);
+
+ rv = (module->C_GetMechanismInfo) (MOCK_SLOT_ONE_ID, CKM_MOCK_PREFIX, &info);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, 2048, info.ulMinKeySize);
+ CuAssertIntEquals (tc, 2048, info.ulMaxKeySize);
+ CuAssertIntEquals (tc, CKF_SIGN | CKF_VERIFY, info.flags);
+
+ rv = (module->C_GetMechanismInfo) (MOCK_SLOT_TWO_ID, CKM_MOCK_PREFIX, &info);
+ CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+ rv = (module->C_GetMechanismInfo) (MOCK_SLOT_ONE_ID, 0, &info);
+ CuAssertTrue (tc, rv == CKR_MECHANISM_INVALID);
+ rv = (module->C_GetMechanismInfo) (0, CKM_MOCK_PREFIX, &info);
+ CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_init_token (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_InitToken) (MOCK_SLOT_ONE_ID, (CK_UTF8CHAR_PTR)"TEST PIN", 8, (CK_UTF8CHAR_PTR)"TEST LABEL");
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_InitToken) (MOCK_SLOT_ONE_ID, (CK_UTF8CHAR_PTR)"OTHER", 5, (CK_UTF8CHAR_PTR)"TEST LABEL");
+ CuAssertTrue (tc, rv == CKR_PIN_INVALID);
+ rv = (module->C_InitToken) (MOCK_SLOT_TWO_ID, (CK_UTF8CHAR_PTR)"TEST PIN", 8, (CK_UTF8CHAR_PTR)"TEST LABEL");
+ CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+ rv = (module->C_InitToken) (0, (CK_UTF8CHAR_PTR)"TEST PIN", 8, (CK_UTF8CHAR_PTR)"TEST LABEL");
+ CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_wait_for_slot_event (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SLOT_ID slot;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_WaitForSlotEvent) (0, &slot, NULL);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, slot, MOCK_SLOT_TWO_ID);
+
+ rv = (module->C_WaitForSlotEvent) (CKF_DONT_BLOCK, &slot, NULL);
+ CuAssertTrue (tc, rv == CKR_NO_EVENT);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_open_close_session (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_OpenSession) (MOCK_SLOT_TWO_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
+ CuAssertTrue (tc, rv == CKR_TOKEN_NOT_PRESENT);
+ rv = (module->C_OpenSession) (0, CKF_SERIAL_SESSION, NULL, NULL, &session);
+ CuAssertTrue (tc, rv == CKR_SLOT_ID_INVALID);
+
+ rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertTrue (tc, session != 0);
+
+ rv = (module->C_CloseSession) (session);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_CloseSession) (session);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_close_all_sessions (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertTrue (tc, session != 0);
+
+ rv = (module->C_CloseAllSessions) (MOCK_SLOT_ONE_ID);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_CloseSession) (session);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_function_status (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_GetFunctionStatus) (session);
+ CuAssertTrue (tc, rv == CKR_FUNCTION_NOT_PARALLEL);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_cancel_function (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_CancelFunction) (session);
+ CuAssertTrue (tc, rv == CKR_FUNCTION_NOT_PARALLEL);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_session_info (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_SESSION_INFO info;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, NULL);
+
+ rv = (module->C_GetSessionInfo) (0, &info);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertTrue (tc, session != 0);
+
+ rv = (module->C_GetSessionInfo) (session, &info);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, MOCK_SLOT_ONE_ID, info.slotID);
+ CuAssertIntEquals (tc, CKS_RO_PUBLIC_SESSION, info.state);
+ CuAssertIntEquals (tc, CKF_SERIAL_SESSION, info.flags);
+ CuAssertIntEquals (tc, 1414, info.ulDeviceError);
+
+ rv = (module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL, NULL, &session);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertTrue (tc, session != 0);
+
+ rv = (module->C_GetSessionInfo) (session, &info);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, MOCK_SLOT_ONE_ID, info.slotID);
+ CuAssertIntEquals (tc, CKS_RW_PUBLIC_SESSION, info.state);
+ CuAssertIntEquals (tc, CKF_SERIAL_SESSION | CKF_RW_SESSION, info.flags);
+ CuAssertIntEquals (tc, 1414, info.ulDeviceError);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_init_pin (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_InitPIN) (0, (CK_UTF8CHAR_PTR)"TEST PIN", 8);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_InitPIN) (session, (CK_UTF8CHAR_PTR)"TEST PIN", 8);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_InitPIN) (session, (CK_UTF8CHAR_PTR)"OTHER", 5);
+ CuAssertTrue (tc, rv == CKR_PIN_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_set_pin (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_SetPIN) (0, (CK_UTF8CHAR_PTR)"booo", 4, (CK_UTF8CHAR_PTR)"TEST PIN", 8);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_SetPIN) (session, (CK_UTF8CHAR_PTR)"booo", 4, (CK_UTF8CHAR_PTR)"TEST PIN", 8);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_SetPIN) (session, (CK_UTF8CHAR_PTR)"other", 5, (CK_UTF8CHAR_PTR)"OTHER", 5);
+ CuAssertTrue (tc, rv == CKR_PIN_INCORRECT);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_operation_state (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_BYTE state[128];
+ CK_ULONG state_len;
+ CK_SESSION_HANDLE session = 0;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ state_len = sizeof (state);
+ rv = (module->C_GetOperationState) (0, state, &state_len);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ state_len = sizeof (state);
+ rv = (module->C_GetOperationState) (session, state, &state_len);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_SetOperationState) (session, state, state_len, 355, 455);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_SetOperationState) (0, state, state_len, 355, 455);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_login_logout (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_Login) (0, CKU_USER, (CK_UTF8CHAR_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_Login) (session, CKU_USER, (CK_UTF8CHAR_PTR)"bo", 2);
+ CuAssertTrue (tc, rv == CKR_PIN_INCORRECT);
+
+ rv = (module->C_Login) (session, CKU_USER, (CK_UTF8CHAR_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_Logout) (session);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_Logout) (session);
+ CuAssertTrue (tc, rv == CKR_USER_NOT_LOGGED_IN);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_attribute_value (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_ATTRIBUTE attrs[8];
+ char label[32];
+ CK_OBJECT_CLASS klass;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ attrs[0].type = CKA_CLASS;
+ attrs[0].pValue = &klass;
+ attrs[0].ulValueLen = sizeof (klass);
+ attrs[1].type = CKA_LABEL;
+ attrs[1].pValue = label;
+ attrs[1].ulValueLen = 2; /* too small */
+ attrs[2].type = CKA_BITS_PER_PIXEL;
+ attrs[2].pValue = NULL;
+ attrs[2].ulValueLen = 0;
+
+ rv = (module->C_GetAttributeValue) (session, MOCK_PRIVATE_KEY_CAPITALIZE, attrs, 3);
+ CuAssertTrue (tc, rv == CKR_USER_NOT_LOGGED_IN);
+
+ rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 2);
+ CuAssertTrue (tc, rv == CKR_BUFFER_TOO_SMALL);
+
+ /* Get right size */
+ attrs[1].pValue = NULL;
+ attrs[1].ulValueLen = 0;
+
+ rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 2);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 3);
+ CuAssertTrue (tc, rv == CKR_ATTRIBUTE_TYPE_INVALID);
+
+ CuAssertIntEquals (tc, CKO_PUBLIC_KEY, klass);
+ CuAssertIntEquals (tc, 21, attrs[1].ulValueLen);
+ CuAssertPtrEquals (tc, NULL, attrs[1].pValue);
+ attrs[1].pValue = label;
+ attrs[1].ulValueLen = sizeof (label);
+ CuAssertTrue (tc, (CK_ULONG)-1 == attrs[2].ulValueLen);
+ CuAssertPtrEquals (tc, NULL, attrs[2].pValue);
+
+ rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 3);
+ CuAssertTrue (tc, rv == CKR_ATTRIBUTE_TYPE_INVALID);
+
+ CuAssertIntEquals (tc, CKO_PUBLIC_KEY, klass);
+ CuAssertIntEquals (tc, 21, attrs[1].ulValueLen);
+ CuAssertPtrEquals (tc, label, attrs[1].pValue);
+ CuAssertTrue (tc, memcmp (label, "Public Capitalize Key", attrs[1].ulValueLen) == 0);
+ CuAssertTrue (tc, (CK_ULONG)-1 == attrs[2].ulValueLen);
+ CuAssertPtrEquals (tc, NULL, attrs[2].pValue);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_set_attribute_value (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_ATTRIBUTE attrs[8];
+ char label[32];
+ CK_ULONG bits;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ strcpy (label, "Blahooo");
+ bits = 1555;
+
+ attrs[0].type = CKA_LABEL;
+ attrs[0].pValue = label;
+ attrs[0].ulValueLen = strlen (label);
+ attrs[1].type = CKA_BITS_PER_PIXEL;
+ attrs[1].pValue = &bits;
+ attrs[1].ulValueLen = sizeof (bits);
+
+ rv = (module->C_SetAttributeValue) (session, MOCK_PRIVATE_KEY_CAPITALIZE, attrs, 2);
+ CuAssertTrue (tc, rv == CKR_USER_NOT_LOGGED_IN);
+
+ rv = (module->C_SetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 2);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ memset (label, 0, sizeof (label));
+ bits = 0;
+
+ rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 2);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, bits, 1555);
+ CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+ CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_create_object (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE attrs[8];
+ char label[32];
+ CK_ULONG bits;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ strcpy (label, "Blahooo");
+ bits = 1555;
+
+ attrs[0].type = CKA_LABEL;
+ attrs[0].pValue = label;
+ attrs[0].ulValueLen = strlen (label);
+ attrs[1].type = CKA_BITS_PER_PIXEL;
+ attrs[1].pValue = &bits;
+ attrs[1].ulValueLen = sizeof (bits);
+
+ rv = (module->C_CreateObject) (0, attrs, 2, &object);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_CreateObject) (session, attrs, 2, &object);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ attrs[0].ulValueLen = sizeof (label);
+ memset (label, 0, sizeof (label));
+ bits = 0;
+
+ rv = (module->C_GetAttributeValue) (session, object, attrs, 2);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, bits, 1555);
+ CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+ CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_copy_object (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE attrs[8];
+ char label[32];
+ CK_ULONG bits;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ bits = 1555;
+
+ attrs[0].type = CKA_BITS_PER_PIXEL;
+ attrs[0].pValue = &bits;
+ attrs[0].ulValueLen = sizeof (bits);
+
+ rv = (module->C_CopyObject) (session, 1333, attrs, 1, &object);
+ CuAssertTrue (tc, rv == CKR_OBJECT_HANDLE_INVALID);
+
+ rv = (module->C_CopyObject) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 1, &object);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ attrs[1].type = CKA_LABEL;
+ attrs[1].pValue = label;
+ attrs[1].ulValueLen = sizeof (label);
+ bits = 0;
+
+ rv = (module->C_GetAttributeValue) (session, object, attrs, 2);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, bits, 1555);
+ CuAssertIntEquals (tc, 21, attrs[1].ulValueLen);
+ CuAssertTrue (tc, memcmp (label, "Public Capitalize Key", attrs[1].ulValueLen) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_destroy_object (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_ATTRIBUTE attrs[8];
+ char label[32];
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ attrs[0].type = CKA_LABEL;
+ attrs[0].pValue = label;
+ attrs[0].ulValueLen = sizeof (label);
+
+ rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 1);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_DestroyObject) (0, MOCK_PUBLIC_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_DestroyObject) (session, MOCK_PUBLIC_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_GetAttributeValue) (session, MOCK_PUBLIC_KEY_CAPITALIZE, attrs, 1);
+ CuAssertTrue (tc, rv == CKR_OBJECT_HANDLE_INVALID);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_get_object_size (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_ULONG size;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_GetObjectSize) (session, 1333, &size);
+ CuAssertTrue (tc, rv == CKR_OBJECT_HANDLE_INVALID);
+
+ rv = (module->C_GetObjectSize) (session, MOCK_PUBLIC_KEY_CAPITALIZE, &size);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ /* The number here is the length of all attributes added up */
+ CuAssertIntEquals (tc, sizeof (CK_ULONG) == 8 ? 44 : 36, size);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_find_objects (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_OBJECT_CLASS klass = CKO_PUBLIC_KEY;
+ CK_ATTRIBUTE attr = { CKA_CLASS, &klass, sizeof (klass) };
+ CK_OBJECT_HANDLE objects[16];
+ CK_ULONG count;
+ CK_ULONG i;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_FindObjectsInit) (0, &attr, 1);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_FindObjectsInit) (session, &attr, 1);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_FindObjects) (0, objects, 16, &count);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_FindObjects) (session, objects, 16, &count);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertTrue (tc, count < 16);
+
+ /* Make sure we get the capitalize public key */
+ for (i = 0; i < count; i++) {
+ if (objects[i] == MOCK_PUBLIC_KEY_CAPITALIZE)
+ break;
+ }
+ CuAssertTrue (tc, i != count);
+
+ /* Make sure we get the prefix public key */
+ for (i = 0; i < count; i++) {
+ if (objects[i] == MOCK_PUBLIC_KEY_PREFIX)
+ break;
+ }
+ CuAssertTrue (tc, i != count);
+
+ /* Make sure all public keys */
+ for (i = 0; i < count; i++) {
+ klass = (CK_ULONG)-1;
+ rv = (module->C_GetAttributeValue) (session, objects[i], &attr, 1);
+ CuAssertTrue (tc, rv == CKR_OK);
+ CuAssertIntEquals (tc, CKO_PUBLIC_KEY, klass);
+ }
+
+ rv = (module->C_FindObjectsFinal) (session);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_FindObjectsFinal) (session);
+ CuAssertTrue (tc, rv == CKR_OPERATION_NOT_INITIALIZED);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_encrypt (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+ CK_BYTE data[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_KEY_HANDLE_INVALID);
+
+ rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_Encrypt) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_Encrypt) (session, (CK_BYTE_PTR)"blah", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 4, length);
+ CuAssertTrue (tc, memcmp (data, "BLAH", 4) == 0);
+
+ rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_EncryptUpdate) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_EncryptUpdate) (session, (CK_BYTE_PTR)"sLurm", 5, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 5, length);
+ CuAssertTrue (tc, memcmp (data, "SLURM", 5) == 0);
+
+ length = sizeof (data);
+ rv = (module->C_EncryptFinal) (0, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_EncryptFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_decrypt (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+ CK_BYTE data[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_KEY_HANDLE_INVALID);
+
+ rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_Decrypt) (0, (CK_BYTE_PTR)"bLAH", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_Decrypt) (session, (CK_BYTE_PTR)"BLAh", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 4, length);
+ CuAssertTrue (tc, memcmp (data, "blah", 4) == 0);
+
+ rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptUpdate) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptUpdate) (session, (CK_BYTE_PTR)"sLuRM", 5, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 5, length);
+ CuAssertTrue (tc, memcmp (data, "slurm", 5) == 0);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptFinal) (0, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_digest (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_COUNT, NULL, 0 };
+ CK_BYTE digest[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_DigestInit) (0, &mech);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_DigestInit) (session, &mech);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (digest);
+ rv = (module->C_Digest) (0, (CK_BYTE_PTR)"bLAH", 4, digest, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (digest);
+ rv = (module->C_Digest) (session, (CK_BYTE_PTR)"BLAh", 4, digest, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 1, length);
+ CuAssertTrue (tc, memcmp (digest, "4", 1) == 0);
+
+ rv = (module->C_DigestInit) (session, &mech);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_DigestUpdate) (0, (CK_BYTE_PTR)"blah", 4);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_DigestUpdate) (session, (CK_BYTE_PTR)"sLuRM", 5);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ /* Adds the the value of object handle to hash: 6 */
+ CuAssertIntEquals (tc, 6, MOCK_PUBLIC_KEY_PREFIX);
+ rv = (module->C_DigestKey) (session, MOCK_PUBLIC_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_DigestUpdate) (session, (CK_BYTE_PTR)"Other", 5);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (digest);
+ rv = (module->C_DigestFinal) (0, digest, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (digest);
+ rv = (module->C_DigestFinal) (session, digest, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 2, length);
+ CuAssertTrue (tc, memcmp (digest, "16", 2) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_sign (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_PREFIX, "prefix:", 7 };
+ CK_BYTE signature[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_SignInit) (0, &mech, MOCK_PRIVATE_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_SignInit) (session, &mech, MOCK_PRIVATE_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_Login) (session, CKU_CONTEXT_SPECIFIC, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (signature);
+ rv = (module->C_Sign) (0, (CK_BYTE_PTR)"bLAH", 4, signature, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (signature);
+ rv = (module->C_Sign) (session, (CK_BYTE_PTR)"BLAh", 4, signature, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 13, length);
+ CuAssertTrue (tc, memcmp (signature, "prefix:value4", 13) == 0);
+
+ rv = (module->C_SignInit) (session, &mech, MOCK_PRIVATE_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_Login) (session, CKU_CONTEXT_SPECIFIC, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_SignUpdate) (0, (CK_BYTE_PTR)"blah", 4);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_SignUpdate) (session, (CK_BYTE_PTR)"sLuRM", 5);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_SignUpdate) (session, (CK_BYTE_PTR)"Other", 5);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (signature);
+ rv = (module->C_SignFinal) (0, signature, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (signature);
+ rv = (module->C_SignFinal) (session, signature, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 14, length);
+ CuAssertTrue (tc, memcmp (signature, "prefix:value10", 2) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_sign_recover (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_PREFIX, "prefix:", 7 };
+ CK_BYTE signature[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_SignRecoverInit) (0, &mech, MOCK_PRIVATE_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_SignRecoverInit) (session, &mech, MOCK_PRIVATE_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_Login) (session, CKU_CONTEXT_SPECIFIC, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (signature);
+ rv = (module->C_SignRecover) (0, (CK_BYTE_PTR)"bLAH", 4, signature, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (signature);
+ rv = (module->C_SignRecover) (session, (CK_BYTE_PTR)"BLAh", 4, signature, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 16, length);
+ CuAssertTrue (tc, memcmp (signature, "prefix:valueBLAh", 16) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_verify (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_PREFIX, "prefix:", 7 };
+ CK_BYTE signature[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_VerifyInit) (0, &mech, MOCK_PUBLIC_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_VerifyInit) (session, &mech, MOCK_PUBLIC_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = 13;
+ memcpy (signature, "prefix:value4", length);
+ rv = (module->C_Verify) (0, (CK_BYTE_PTR)"bLAH", 4, signature, 5);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_Verify) (session, (CK_BYTE_PTR)"BLAh", 4, signature, length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_VerifyInit) (session, &mech, MOCK_PUBLIC_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_VerifyUpdate) (0, (CK_BYTE_PTR)"blah", 4);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_VerifyUpdate) (session, (CK_BYTE_PTR)"sLuRM", 5);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_VerifyUpdate) (session, (CK_BYTE_PTR)"Other", 5);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = 14;
+ memcpy (signature, "prefix:value10", length);
+
+ rv = (module->C_VerifyFinal) (session, signature, 5);
+ CuAssertTrue (tc, rv == CKR_SIGNATURE_LEN_RANGE);
+
+ rv = (module->C_VerifyFinal) (session, signature, length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_verify_recover (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_PREFIX, "prefix:", 7 };
+ CK_BYTE data[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_VerifyRecoverInit) (0, &mech, MOCK_PUBLIC_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_VerifyRecoverInit) (session, &mech, MOCK_PUBLIC_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_VerifyRecover) (0, (CK_BYTE_PTR)"prefix:valueBLah", 16, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_VerifyRecover) (session, (CK_BYTE_PTR)"prefix:valueBLah", 16, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 4, length);
+ CuAssertTrue (tc, memcmp (data, "BLah", 4) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_digest_encrypt (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+ CK_MECHANISM dmech = { CKM_MOCK_COUNT, NULL, 0 };
+ CK_BYTE data[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_DigestInit) (session, &dmech);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_DigestEncryptUpdate) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_DigestEncryptUpdate) (session, (CK_BYTE_PTR)"blah", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 4, length);
+ CuAssertTrue (tc, memcmp (data, "BLAH", 4) == 0);
+
+ length = sizeof (data);
+ rv = (module->C_EncryptFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_DigestFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 1, length);
+ CuAssertTrue (tc, memcmp (data, "4", 1) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_decrypt_digest (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+ CK_MECHANISM dmech = { CKM_MOCK_COUNT, NULL, 0 };
+ CK_BYTE data[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_DigestInit) (session, &dmech);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptDigestUpdate) (0, (CK_BYTE_PTR)"BLAH", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptDigestUpdate) (session, (CK_BYTE_PTR)"BLAH", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 4, length);
+ CuAssertTrue (tc, memcmp (data, "blah", 4) == 0);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_DigestFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 1, length);
+ CuAssertTrue (tc, memcmp (data, "4", 1) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_sign_encrypt (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+ CK_MECHANISM smech = { CKM_MOCK_PREFIX, "p:", 2 };
+ CK_BYTE data[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_EncryptInit) (session, &mech, MOCK_PUBLIC_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_SignInit) (session, &smech, MOCK_PRIVATE_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_Login) (session, CKU_CONTEXT_SPECIFIC, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_SignEncryptUpdate) (0, (CK_BYTE_PTR)"blah", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_SignEncryptUpdate) (session, (CK_BYTE_PTR)"blah", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 4, length);
+ CuAssertTrue (tc, memcmp (data, "BLAH", 4) == 0);
+
+ length = sizeof (data);
+ rv = (module->C_EncryptFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_SignFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 8, length);
+ CuAssertTrue (tc, memcmp (data, "p:value4", 1) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_decrypt_verify (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_CAPITALIZE, NULL, 0 };
+ CK_MECHANISM vmech = { CKM_MOCK_PREFIX, "p:", 2 };
+ CK_BYTE data[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_Login) (session, CKU_USER, (CK_BYTE_PTR)"booo", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_DecryptInit) (session, &mech, MOCK_PRIVATE_KEY_CAPITALIZE);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_VerifyInit) (session, &vmech, MOCK_PUBLIC_KEY_PREFIX);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptVerifyUpdate) (0, (CK_BYTE_PTR)"BLAH", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptVerifyUpdate) (session, (CK_BYTE_PTR)"BLAH", 4, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 4, length);
+ CuAssertTrue (tc, memcmp (data, "blah", 4) == 0);
+
+ length = sizeof (data);
+ rv = (module->C_DecryptFinal) (session, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_VerifyFinal) (session, (CK_BYTE_PTR)"p:value4", 8);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_generate_key (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_OBJECT_HANDLE object;
+ CK_MECHANISM mech = { CKM_MOCK_GENERATE, NULL, 0 };
+ CK_ATTRIBUTE attrs[8];
+ char label[32];
+ char value[64];
+ CK_ULONG bits;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ strcpy (label, "Blahooo");
+ bits = 1555;
+
+ attrs[0].type = CKA_LABEL;
+ attrs[0].pValue = label;
+ attrs[0].ulValueLen = strlen (label);
+ attrs[1].type = CKA_BITS_PER_PIXEL;
+ attrs[1].pValue = &bits;
+ attrs[1].ulValueLen = sizeof (bits);
+
+ rv = (module->C_GenerateKey) (session, &mech, attrs, 2, &object);
+ CuAssertTrue (tc, rv == CKR_MECHANISM_PARAM_INVALID);
+
+ mech.pParameter = "generate";
+ mech.ulParameterLen = 9;
+
+ rv = (module->C_GenerateKey) (session, &mech, attrs, 2, &object);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ attrs[0].ulValueLen = sizeof (label);
+ memset (label, 0, sizeof (label));
+ bits = 0;
+ attrs[2].type = CKA_VALUE;
+ attrs[2].pValue = value;
+ attrs[2].ulValueLen = sizeof (value);
+
+ rv = (module->C_GetAttributeValue) (session, object, attrs, 3);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, bits, 1555);
+ CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+ CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+ CuAssertIntEquals (tc, 9, attrs[2].ulValueLen);
+ CuAssertTrue (tc, memcmp (value, "generated", attrs[2].ulValueLen) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_generate_key_pair (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_OBJECT_HANDLE pub_object;
+ CK_OBJECT_HANDLE priv_object;
+ CK_MECHANISM mech = { CKM_MOCK_GENERATE, "generated", 9 };
+ CK_ATTRIBUTE pub_attrs[8];
+ CK_ATTRIBUTE priv_attrs[8];
+ char pub_label[32];
+ char pub_value[64];
+ char priv_label[32];
+ char priv_value[64];
+ CK_ULONG pub_bits;
+ CK_ULONG priv_bits;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ strcpy (pub_label, "Blahooo");
+ pub_bits = 1555;
+ pub_attrs[0].type = CKA_LABEL;
+ pub_attrs[0].pValue = pub_label;
+ pub_attrs[0].ulValueLen = strlen (pub_label);
+ pub_attrs[1].type = CKA_BITS_PER_PIXEL;
+ pub_attrs[1].pValue = &pub_bits;
+ pub_attrs[1].ulValueLen = sizeof (pub_bits);
+
+ strcpy (priv_label, "Private");
+ priv_bits = 1666;
+ priv_attrs[0].type = CKA_LABEL;
+ priv_attrs[0].pValue = priv_label;
+ priv_attrs[0].ulValueLen = strlen (priv_label);
+ priv_attrs[1].type = CKA_BITS_PER_PIXEL;
+ priv_attrs[1].pValue = &priv_bits;
+ priv_attrs[1].ulValueLen = sizeof (priv_bits);
+
+ rv = (module->C_GenerateKeyPair) (0, &mech, pub_attrs, 2, priv_attrs, 2,
+ &pub_object, &priv_object);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ mech.pParameter = "generate";
+ mech.ulParameterLen = 9;
+
+ rv = (module->C_GenerateKeyPair) (session, &mech, pub_attrs, 2, priv_attrs, 2,
+ &pub_object, &priv_object);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ pub_bits = 0;
+ pub_attrs[0].ulValueLen = sizeof (pub_label);
+ memset (pub_label, 0, sizeof (pub_label));
+ pub_attrs[2].type = CKA_VALUE;
+ pub_attrs[2].pValue = pub_value;
+ pub_attrs[2].ulValueLen = sizeof (pub_value);
+
+ rv = (module->C_GetAttributeValue) (session, pub_object, pub_attrs, 3);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 1555, pub_bits);
+ CuAssertIntEquals (tc, 7, pub_attrs[0].ulValueLen);
+ CuAssertTrue (tc, memcmp (pub_label, "Blahooo", pub_attrs[0].ulValueLen) == 0);
+ CuAssertIntEquals (tc, 9, pub_attrs[2].ulValueLen);
+ CuAssertTrue (tc, memcmp (pub_value, "generated", pub_attrs[2].ulValueLen) == 0);
+
+ priv_bits = 0;
+ priv_attrs[0].ulValueLen = sizeof (priv_label);
+ memset (priv_label, 0, sizeof (priv_label));
+ priv_attrs[2].type = CKA_VALUE;
+ priv_attrs[2].pValue = priv_value;
+ priv_attrs[2].ulValueLen = sizeof (priv_value);
+
+ rv = (module->C_GetAttributeValue) (session, priv_object, priv_attrs, 3);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 1666, priv_bits);
+ CuAssertIntEquals (tc, 7, priv_attrs[0].ulValueLen);
+ CuAssertTrue (tc, memcmp (priv_label, "Private", priv_attrs[0].ulValueLen) == 0);
+ CuAssertIntEquals (tc, 9, priv_attrs[2].ulValueLen);
+ CuAssertTrue (tc, memcmp (priv_value, "generated", priv_attrs[2].ulValueLen) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_wrap_key (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_MECHANISM mech = { CKM_MOCK_WRAP, NULL, 0 };
+ CK_BYTE data[128];
+ CK_ULONG length;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ length = sizeof (data);
+ rv = (module->C_WrapKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX, MOCK_PUBLIC_KEY_PREFIX, data, &length);
+ CuAssertTrue (tc, rv == CKR_MECHANISM_PARAM_INVALID);
+
+ mech.pParameter = "wrap";
+ mech.ulParameterLen = 4;
+
+ rv = (module->C_WrapKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX, MOCK_PUBLIC_KEY_PREFIX, data, &length);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, 5, length);
+ CuAssertTrue (tc, memcmp (data, "value", 5) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_unwrap_key (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_OBJECT_HANDLE object;
+ CK_MECHANISM mech = { CKM_MOCK_WRAP, NULL, 0 };
+ CK_ATTRIBUTE attrs[8];
+ char label[32];
+ char value[64];
+ CK_ULONG bits;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ strcpy (label, "Blahooo");
+ bits = 1555;
+
+ attrs[0].type = CKA_LABEL;
+ attrs[0].pValue = label;
+ attrs[0].ulValueLen = strlen (label);
+ attrs[1].type = CKA_BITS_PER_PIXEL;
+ attrs[1].pValue = &bits;
+ attrs[1].ulValueLen = sizeof (bits);
+
+ rv = (module->C_UnwrapKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX,
+ (CK_BYTE_PTR)"wheee", 5, attrs, 2, &object);
+ CuAssertTrue (tc, rv == CKR_MECHANISM_PARAM_INVALID);
+
+ mech.pParameter = "wrap";
+ mech.ulParameterLen = 4;
+
+ rv = (module->C_UnwrapKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX,
+ (CK_BYTE_PTR)"wheee", 5, attrs, 2, &object);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ attrs[0].ulValueLen = sizeof (label);
+ memset (label, 0, sizeof (label));
+ bits = 0;
+ attrs[2].type = CKA_VALUE;
+ attrs[2].pValue = value;
+ attrs[2].ulValueLen = sizeof (value);
+
+ rv = (module->C_GetAttributeValue) (session, object, attrs, 3);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, bits, 1555);
+ CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+ CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+ CuAssertIntEquals (tc, 5, attrs[2].ulValueLen);
+ CuAssertTrue (tc, memcmp (value, "wheee", attrs[2].ulValueLen) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_derive_key (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_OBJECT_HANDLE object;
+ CK_MECHANISM mech = { CKM_MOCK_DERIVE, NULL, 0 };
+ CK_ATTRIBUTE attrs[8];
+ char label[32];
+ char value[64];
+ CK_ULONG bits;
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ strcpy (label, "Blahooo");
+ bits = 1555;
+
+ attrs[0].type = CKA_LABEL;
+ attrs[0].pValue = label;
+ attrs[0].ulValueLen = strlen (label);
+ attrs[1].type = CKA_BITS_PER_PIXEL;
+ attrs[1].pValue = &bits;
+ attrs[1].ulValueLen = sizeof (bits);
+
+ rv = (module->C_DeriveKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX,
+ attrs, 2, &object);
+ CuAssertTrue (tc, rv == CKR_MECHANISM_PARAM_INVALID);
+
+ mech.pParameter = "derive";
+ mech.ulParameterLen = 6;
+
+ rv = (module->C_DeriveKey) (session, &mech, MOCK_PUBLIC_KEY_PREFIX,
+ attrs, 2, &object);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ attrs[0].ulValueLen = sizeof (label);
+ memset (label, 0, sizeof (label));
+ bits = 0;
+ attrs[2].type = CKA_VALUE;
+ attrs[2].pValue = value;
+ attrs[2].ulValueLen = sizeof (value);
+
+ rv = (module->C_GetAttributeValue) (session, object, attrs, 3);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertIntEquals (tc, bits, 1555);
+ CuAssertIntEquals (tc, 7, attrs[0].ulValueLen);
+ CuAssertTrue (tc, memcmp (label, "Blahooo", attrs[0].ulValueLen) == 0);
+ CuAssertIntEquals (tc, 7, attrs[2].ulValueLen);
+ CuAssertTrue (tc, memcmp (value, "derived", attrs[2].ulValueLen) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_random (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR module;
+ CK_SESSION_HANDLE session = 0;
+ CK_BYTE data[10];
+ CK_RV rv;
+
+ module = setup_mock_module (tc, &session);
+
+ rv = (module->C_SeedRandom) (0, (CK_BYTE_PTR)"seed", 4);
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_SeedRandom) (session, (CK_BYTE_PTR)"seed", 4);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = (module->C_GenerateRandom) (0, data, sizeof (data));
+ CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+ rv = (module->C_GenerateRandom) (session, data, sizeof (data));
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ CuAssertTrue (tc, memcmp (data, "seedseedse", sizeof (data)) == 0);
+
+ teardown_mock_module (tc, module);
+}
+
+static void
+test_mock_add_tests (CuSuite *suite)
+{
+ SUITE_ADD_TEST (suite, test_get_info);
+ SUITE_ADD_TEST (suite, test_get_slot_list);
+ SUITE_ADD_TEST (suite, test_get_slot_info);
+ SUITE_ADD_TEST (suite, test_get_token_info);
+ SUITE_ADD_TEST (suite, test_get_mechanism_list);
+ SUITE_ADD_TEST (suite, test_get_mechanism_info);
+ SUITE_ADD_TEST (suite, test_init_token);
+ SUITE_ADD_TEST (suite, test_wait_for_slot_event);
+ SUITE_ADD_TEST (suite, test_open_close_session);
+ SUITE_ADD_TEST (suite, test_close_all_sessions);
+ SUITE_ADD_TEST (suite, test_get_function_status);
+ SUITE_ADD_TEST (suite, test_cancel_function);
+ SUITE_ADD_TEST (suite, test_get_session_info);
+ SUITE_ADD_TEST (suite, test_init_pin);
+ SUITE_ADD_TEST (suite, test_set_pin);
+ SUITE_ADD_TEST (suite, test_operation_state);
+ SUITE_ADD_TEST (suite, test_login_logout);
+ SUITE_ADD_TEST (suite, test_get_attribute_value);
+ SUITE_ADD_TEST (suite, test_set_attribute_value);
+ SUITE_ADD_TEST (suite, test_create_object);
+ SUITE_ADD_TEST (suite, test_copy_object);
+ SUITE_ADD_TEST (suite, test_destroy_object);
+ SUITE_ADD_TEST (suite, test_get_object_size);
+ SUITE_ADD_TEST (suite, test_find_objects);
+ SUITE_ADD_TEST (suite, test_encrypt);
+ SUITE_ADD_TEST (suite, test_decrypt);
+ SUITE_ADD_TEST (suite, test_digest);
+ SUITE_ADD_TEST (suite, test_sign);
+ SUITE_ADD_TEST (suite, test_sign_recover);
+ SUITE_ADD_TEST (suite, test_verify);
+ SUITE_ADD_TEST (suite, test_verify_recover);
+ SUITE_ADD_TEST (suite, test_digest_encrypt);
+ SUITE_ADD_TEST (suite, test_decrypt_digest);
+ SUITE_ADD_TEST (suite, test_sign_encrypt);
+ SUITE_ADD_TEST (suite, test_decrypt_verify);
+ SUITE_ADD_TEST (suite, test_generate_key);
+ SUITE_ADD_TEST (suite, test_generate_key_pair);
+ SUITE_ADD_TEST (suite, test_wrap_key);
+ SUITE_ADD_TEST (suite, test_unwrap_key);
+ SUITE_ADD_TEST (suite, test_derive_key);
+ SUITE_ADD_TEST (suite, test_random);
+}
diff --git a/p11-kit/tests/test-modules.c b/p11-kit/tests/test-modules.c
index 3a6e968..d6b4753 100644
--- a/p11-kit/tests/test-modules.c
+++ b/p11-kit/tests/test-modules.c
@@ -50,11 +50,8 @@ static CK_FUNCTION_LIST_PTR_PTR
initialize_and_get_modules (CuTest *tc)
{
CK_FUNCTION_LIST_PTR_PTR modules;
- CK_RV rv;
- rv = p11_kit_initialize_registered ();
- CuAssertIntEquals (tc, CKR_OK, rv);
- modules = p11_kit_registered_modules ();
+ modules = p11_kit_modules_load_and_initialize (0);
CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
return modules;
@@ -64,11 +61,7 @@ static void
finalize_and_free_modules (CuTest *tc,
CK_FUNCTION_LIST_PTR_PTR modules)
{
- CK_RV rv;
-
- free (modules);
- rv = p11_kit_finalize_registered ();
- CuAssertIntEquals (tc, CKR_OK, rv);
+ p11_kit_modules_finalize_and_release (modules);
}
static void
@@ -86,7 +79,7 @@ test_no_duplicates (CuTest *tc)
/* The loaded modules should not contain duplicates */
for (i = 0; modules[i] != NULL; i++) {
- path = p11_kit_registered_option (modules[i], "module");
+ path = p11_kit_config_option (modules[i], "module");
if (p11_dict_get (funcs, modules[i]))
CuAssert (tc, "found duplicate function list pointer", 0);
@@ -117,7 +110,7 @@ lookup_module_with_name (CuTest *tc,
int i;
for (i = 0; match == NULL && modules[i] != NULL; i++) {
- module_name = p11_kit_registered_module_to_name (modules[i]);
+ module_name = p11_kit_module_get_name (modules[i]);
CuAssertPtrNotNull (tc, module_name);
if (strcmp (module_name, name) == 0)
match = modules[i];
@@ -128,8 +121,8 @@ lookup_module_with_name (CuTest *tc,
* As a side effect, we should check that the results of this function
* matches the above search.
*/
- module = p11_kit_registered_name_to_module (name);
- CuAssert(tc, "different result from p11_kit_registered_name_to_module()",
+ module = p11_kit_module_for_name (modules, name);
+ CuAssert(tc, "different result from p11_kit_module_for_name ()",
module == match);
return match;
@@ -169,7 +162,6 @@ static void
test_disable_later (CuTest *tc)
{
CK_FUNCTION_LIST_PTR_PTR modules;
- CK_RV rv;
/*
* The module two shouldn't be matched, because in its config
@@ -178,12 +170,9 @@ test_disable_later (CuTest *tc)
* disable-in: test-disable
*/
- rv = p11_kit_initialize_registered ();
- CuAssertIntEquals (tc, CKR_OK, rv);
-
p11_kit_set_progname ("test-disable");
- modules = p11_kit_registered_modules ();
+ modules = p11_kit_modules_load_and_initialize (0);
CuAssertTrue (tc, modules != NULL && modules[0] != NULL);
CuAssertTrue (tc, lookup_module_with_name (tc, modules, "two") == NULL);
@@ -246,7 +235,7 @@ test_priority (CuTest *tc)
/* The loaded modules should not contain duplicates */
for (i = 0; modules[i] != NULL; i++) {
- name = p11_kit_registered_module_to_name (modules[i]);
+ name = p11_kit_module_get_name (modules[i]);
CuAssertPtrNotNull (tc, name);
/* Either one of these can be loaded, as this is a duplicate module */
@@ -263,6 +252,100 @@ test_priority (CuTest *tc)
finalize_and_free_modules (tc, modules);
}
+static void
+test_module_name (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR_PTR modules;
+ CK_FUNCTION_LIST_PTR module;
+ char *name;
+
+ /*
+ * The module three should not be present, as we don't match the current
+ * program.
+ */
+
+ modules = initialize_and_get_modules (tc);
+
+ module = p11_kit_module_for_name (modules, "one");
+ CuAssertPtrNotNull (tc, module);
+ name = p11_kit_module_get_name (module);
+ CuAssertStrEquals (tc, "one", name);
+ free (name);
+
+ module = p11_kit_module_for_name (modules, "invalid");
+ CuAssertPtrEquals (tc, NULL, module);
+
+ module = p11_kit_module_for_name (NULL, "one");
+ CuAssertPtrEquals (tc, NULL, module);
+
+ finalize_and_free_modules (tc, modules);
+}
+
+static void
+test_module_flags (CuTest *tc)
+{
+ CK_FUNCTION_LIST **modules;
+ CK_FUNCTION_LIST **unmanaged;
+ int flags;
+
+ /*
+ * The module three should not be present, as we don't match the current
+ * program.
+ */
+
+ modules = initialize_and_get_modules (tc);
+
+ flags = p11_kit_module_get_flags (modules[0]);
+ CuAssertIntEquals (tc, 0, flags);
+
+ unmanaged = p11_kit_modules_load (NULL, P11_KIT_MODULE_UNMANAGED);
+ CuAssertTrue (tc, unmanaged != NULL && unmanaged[0] != NULL);
+
+ flags = p11_kit_module_get_flags (unmanaged[0]);
+ CuAssertIntEquals (tc, P11_KIT_MODULE_UNMANAGED, flags);
+
+ finalize_and_free_modules (tc, modules);
+ p11_kit_modules_release (unmanaged);
+}
+
+static void
+test_config_option (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR_PTR modules;
+ CK_FUNCTION_LIST_PTR module;
+ char *value;
+
+ /*
+ * The module three should not be present, as we don't match the current
+ * program.
+ */
+
+ modules = initialize_and_get_modules (tc);
+
+ value = p11_kit_config_option (NULL, "new");
+ CuAssertStrEquals (tc, "world", value);
+ free (value);
+
+ module = p11_kit_module_for_name (modules, "one");
+ CuAssertPtrNotNull (tc, module);
+
+ value = p11_kit_config_option (module, "setting");
+ CuAssertStrEquals (tc, "user1", value);
+ free (value);
+
+ value = p11_kit_config_option (NULL, "invalid");
+ CuAssertPtrEquals (tc, NULL, value);
+
+ value = p11_kit_config_option (module, "invalid");
+ CuAssertPtrEquals (tc, NULL, value);
+
+ /* Invalid but non-NULL module pointer */
+ value = p11_kit_config_option (module + 1, "setting");
+ CuAssertPtrEquals (tc, NULL, value);
+
+ finalize_and_free_modules (tc, modules);
+}
+
int
main (void)
{
@@ -278,6 +361,9 @@ main (void)
SUITE_ADD_TEST (suite, test_disable_later);
SUITE_ADD_TEST (suite, test_enable);
SUITE_ADD_TEST (suite, test_priority);
+ SUITE_ADD_TEST (suite, test_module_name);
+ SUITE_ADD_TEST (suite, test_module_flags);
+ SUITE_ADD_TEST (suite, test_config_option);
p11_kit_be_quiet ();
diff --git a/p11-kit/tests/test-proxy.c b/p11-kit/tests/test-proxy.c
new file mode 100644
index 0000000..99b2431
--- /dev/null
+++ b/p11-kit/tests/test-proxy.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2013 Red Hat Inc
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@redhat.com>
+ */
+
+#define CRYPTOKI_EXPORTS
+
+#include "config.h"
+#include "CuTest.h"
+
+#include "library.h"
+#include "pkcs11.h"
+#include "p11-kit.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+/* This is the proxy module entry point in proxy.c, and linked to this test */
+CK_RV C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list);
+
+static void
+test_initialize_finalize (CuTest *tc)
+{
+ CK_FUNCTION_LIST_PTR proxy;
+ CK_RV rv;
+
+ rv = C_GetFunctionList (&proxy);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = proxy->C_Initialize (NULL);
+ CuAssertTrue (tc, rv == CKR_OK);
+
+ rv = proxy->C_Finalize (NULL);
+ CuAssertTrue (tc, rv == CKR_OK);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ putenv ("P11_KIT_STRICT=1");
+ p11_library_init ();
+ p11_kit_be_quiet ();
+
+ SUITE_ADD_TEST (suite, test_initialize_finalize);
+
+ CuSuiteRun (suite);
+ CuSuiteSummary (suite, output);
+ CuSuiteDetails (suite, output);
+ printf ("%s\n", output->buffer);
+ ret = suite->failCount;
+ CuSuiteDelete (suite);
+ CuStringDelete (output);
+ return ret;
+}