diff options
Diffstat (limited to 'p11-kit')
-rw-r--r-- | p11-kit/Makefile.am | 7 | ||||
-rw-r--r-- | p11-kit/deprecated.h | 97 | ||||
-rw-r--r-- | p11-kit/docs.h | 38 | ||||
-rw-r--r-- | p11-kit/modules.c | 1366 | ||||
-rw-r--r-- | p11-kit/modules.h | 51 | ||||
-rw-r--r-- | p11-kit/p11-kit.h | 63 | ||||
-rw-r--r-- | p11-kit/private.h | 6 | ||||
-rw-r--r-- | p11-kit/proxy.c | 231 | ||||
-rw-r--r-- | p11-kit/tests/Makefile.am | 10 | ||||
-rw-r--r-- | p11-kit/tests/files/system-pkcs11.conf | 5 | ||||
-rw-r--r-- | p11-kit/tests/files/user-modules/one.module | 3 | ||||
-rw-r--r-- | p11-kit/tests/test-deprecated.c | 521 | ||||
-rw-r--r-- | p11-kit/tests/test-init.c | 176 | ||||
-rw-r--r-- | p11-kit/tests/test-iter.c | 72 | ||||
-rw-r--r-- | p11-kit/tests/test-managed.c | 168 | ||||
-rw-r--r-- | p11-kit/tests/test-mock.c | 1687 | ||||
-rw-r--r-- | p11-kit/tests/test-modules.c | 124 | ||||
-rw-r--r-- | p11-kit/tests/test-proxy.c | 94 |
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; +} |