diff options
author | Stef Walter <stefw@gnome.org> | 2013-02-06 21:57:45 +0100 |
---|---|---|
committer | Stef Walter <stefw@gnome.org> | 2013-05-21 10:47:51 +0200 |
commit | 5c19f0cf66495f00ccf69eba1d0915f862a88c8d (patch) | |
tree | e8ae733062507a0a4cc5c134d1fdd62cf055cddd | |
parent | ff853bd7902e271256cada4a1b20a3d46b519b69 (diff) |
p11-kit: Managed PKCS#11 module loading
Support a new managed style module loading for PKCS#11 modules. This
allows us to better coordinate between multiple callers of the same
PKCS#11 modules and provide hooks into their behavior.
This meant redoing the public facing API. The old methods are now
deprecated, marked and documented as such.
36 files changed, 4594 insertions, 486 deletions
diff --git a/common/compat.c b/common/compat.c index b8ed2ad..400e10b 100644 --- a/common/compat.c +++ b/common/compat.c @@ -245,6 +245,12 @@ p11_dl_error (void) return msg_buf; } +void +p11_dl_close (void *dl) +{ + FreeLibrary (dl); +} + int p11_thread_create (p11_thread_t *thread, p11_thread_routine routine, diff --git a/common/compat.h b/common/compat.h index 7435e07..0f9677b 100644 --- a/common/compat.h +++ b/common/compat.h @@ -135,13 +135,13 @@ typedef HMODULE dl_module_t; #define p11_dl_open(f) \ (LoadLibrary (f)) -#define p11_dl_close(d) \ - (FreeLibrary (d)) #define p11_dl_symbol(d, s) \ ((void *)GetProcAddress ((d), (s))) char * p11_dl_error (void); +void p11_dl_close (void * dl); + #define p11_sleep_ms(ms) \ (Sleep (ms)) diff --git a/common/mock.c b/common/mock.c index 6176fa9..4dbd674 100644 --- a/common/mock.c +++ b/common/mock.c @@ -183,8 +183,8 @@ mock_module_take_object (CK_SLOT_ID slot_id, return_if_reached (); } -void -mock_module_reset_objects (CK_SLOT_ID slot_id) +static void +module_reset_objects (CK_SLOT_ID slot_id) { return_if_fail (slot_id == MOCK_SLOT_ONE_ID); @@ -291,6 +291,44 @@ mock_module_reset_objects (CK_SLOT_ID slot_id) p11_dict_set (the_objects, handle_to_pointer (MOCK_PUBLIC_KEY_PREFIX), p11_attrs_dup (attrs)); } +} + +static void +module_finalize (void) +{ + p11_mutex_lock (&init_mutex); + + /* This should stop all other calls in */ + pkcs11_initialized = false; + pkcs11_initialized_pid = 0; + + if (the_objects) + p11_dict_free (the_objects); + the_objects = NULL; + + if (the_sessions) + p11_dict_free (the_sessions); + the_sessions = NULL; + logged_in = false; + the_user_type = 0; + + free (the_pin); + the_pin = NULL; + n_the_pin = 0; + + p11_mutex_unlock (&init_mutex); +} + +bool +mock_module_initialized (void) +{ + return pkcs11_initialized; +} +void +mock_module_reset (void) +{ + module_finalize (); + module_reset_objects (MOCK_SLOT_ONE_ID); } @@ -389,7 +427,7 @@ mock_C_Initialize (CK_VOID_PTR init_args) p11_dict_direct_equal, NULL, free_session); - mock_module_reset_objects (MOCK_SLOT_ONE_ID); + module_reset_objects (MOCK_SLOT_ONE_ID); done: /* Mark us as officially initialized */ @@ -425,24 +463,7 @@ mock_C_Finalize (CK_VOID_PTR reserved) return_val_if_fail (pkcs11_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); return_val_if_fail (reserved == NULL, CKR_ARGUMENTS_BAD); - p11_mutex_lock (&init_mutex); - - /* This should stop all other calls in */ - pkcs11_initialized = false; - pkcs11_initialized_pid = 0; - - p11_dict_free (the_objects); - the_objects = NULL; - - p11_dict_free (the_sessions); - the_sessions = NULL; - logged_in = false; - the_user_type = 0; - - free (the_pin); - - p11_mutex_unlock (&init_mutex); - + module_finalize (); return CKR_OK; } diff --git a/common/mock.h b/common/mock.h index d9ded00..5691fe0 100644 --- a/common/mock.h +++ b/common/mock.h @@ -108,11 +108,13 @@ void mock_module_enumerate_objects (CK_SESSION_HANDLE sess void mock_module_add_object (CK_SLOT_ID slot_id, const CK_ATTRIBUTE *attrs); +void mock_module_reset (void); + +bool mock_module_initialized (void); + void mock_module_take_object (CK_SLOT_ID slot_id, CK_ATTRIBUTE *attrs); -void mock_module_reset_objects (CK_SLOT_ID slot_id); - CK_RV mock_C_Initialize (CK_VOID_PTR init_args); CK_RV mock_C_Initialize__fails (CK_VOID_PTR init_args); diff --git a/doc/manual/Makefile.am b/doc/manual/Makefile.am index c10375a..b5b80f1 100644 --- a/doc/manual/Makefile.am +++ b/doc/manual/Makefile.am @@ -53,6 +53,7 @@ IGNORE_HFILES= \ debug.h \ dict.h \ mock.h \ + modules.h \ pkcs11.h \ pkcs11x.h \ private.h \ @@ -70,6 +71,7 @@ HTML_IMAGES= # e.g. content_files=running.sgml building.sgml changes-2.0.sgml content_files=p11-kit-config.xml p11-kit-sharing.xml \ p11-kit-devel.xml \ + p11-kit-proxy.xml \ p11-kit-trust.xml \ p11-kit.xml \ pkcs11.conf.xml \ diff --git a/doc/manual/p11-kit-docs.xml b/doc/manual/p11-kit-docs.xml index 0397169..5acfb97 100644 --- a/doc/manual/p11-kit-docs.xml +++ b/doc/manual/p11-kit-docs.xml @@ -13,6 +13,7 @@ <xi:include href="p11-kit-config.xml"/> <xi:include href="p11-kit-sharing.xml"/> + <xi:include href="p11-kit-proxy.xml"/> <xi:include href="p11-kit-trust.xml"/> <chapter xml:id="tools"> @@ -28,6 +29,7 @@ <xi:include href="xml/p11-kit-pin.xml"/> <xi:include href="xml/p11-kit-util.xml"/> <xi:include href="xml/p11-kit-future.xml"/> + <xi:include href="xml/p11-kit-deprecated.xml"/> <index id="api-index-full"> <title>API Index</title> diff --git a/doc/manual/p11-kit-proxy.xml b/doc/manual/p11-kit-proxy.xml new file mode 100644 index 0000000..7cc3615 --- /dev/null +++ b/doc/manual/p11-kit-proxy.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ +]> +<chapter xml:id="sharing"> + <title>Proxy Module</title> + + <para>When an application is aware of the fact that coordination + is necessary between multiple consumers of a PKCS#11 module, and wants + to load standard configured PKCS#11 modules, it can link to + <literal>p11-kit</literal> and use the functions there to provide this + functionality.</para> + + <para>However most current consumers of PKCS#11 are ignorant of + this problem, and do not link to p11-kit. In order to solve this + multiple initialization problem for all applications, + <literal>p11-kit</literal> provides a proxy compatibility + module.</para> + + <para>This proxy module acts like a normal PKCS#11 module, but + internally loads a preconfigured set of PKCS#11 modules and + manages their features as described earlier. Each slot in the configured modules + is exposed as a slot of the <literal>p11-kit</literal> proxy module. The proxy + module is then used as a normal PKCS#11 module would be. It can be loaded by + crypto libraries like NSS and behaves as expected.</para> + + <para>The <literal>C_GetFunctionList</literal> exported entry point of the + proxy module returns a new managed PKCS#11 module each time it is called. These + managed instances are released when the proxy module is unloaded.</para> +</chapter> diff --git a/doc/manual/p11-kit-sections.txt b/doc/manual/p11-kit-sections.txt index dc85f2d..84f084d 100644 --- a/doc/manual/p11-kit-sections.txt +++ b/doc/manual/p11-kit-sections.txt @@ -52,15 +52,22 @@ p11_kit_pin_file_callback <SECTION> <FILE>p11-kit</FILE> -p11_kit_initialize_registered -p11_kit_finalize_registered -p11_kit_registered_modules -p11_kit_registered_module_to_name -p11_kit_registered_name_to_module -p11_kit_registered_option -p11_kit_initialize_module -p11_kit_load_initialize_module -p11_kit_finalize_module +P11_KIT_MODULE_CRITICAL +P11_KIT_MODULE_UNMANAGED +p11_kit_modules_load_and_initialize +p11_kit_modules_finalize_and_release +p11_kit_modules_load +p11_kit_modules_initialize +p11_kit_modules_finalize +p11_kit_modules_release +p11_kit_module_load +p11_kit_module_initialize +p11_kit_module_finalize +p11_kit_module_release +p11_kit_module_for_name +p11_kit_module_get_name +p11_kit_module_get_flags +p11_kit_config_option </SECTION> <SECTION> @@ -104,3 +111,17 @@ p11_kit_iter_get_object p11_kit_iter_load_attributes p11_kit_iter_free </SECTION> + +<SECTION> +<FILE>p11-kit-deprecated</FILE> +p11_kit_initialize_registered +p11_kit_finalize_registered +p11_kit_registered_modules +p11_kit_registered_module_to_name +p11_kit_registered_name_to_module +p11_kit_registered_option +p11_kit_initialize_module +p11_kit_load_initialize_module +p11_kit_finalize_module +P11_KIT_DEPRECATED_FOR +</SECTION> diff --git a/doc/manual/p11-kit-sharing.xml b/doc/manual/p11-kit-sharing.xml index e692e3d..01b3c8b 100644 --- a/doc/manual/p11-kit-sharing.xml +++ b/doc/manual/p11-kit-sharing.xml @@ -42,52 +42,52 @@ loosely coupled, backwards compatible, and flexible way.</para> </section> - <section xml:id="sharing-initialize"> - <title>Solution: p11-kit</title> - - <para><literal>p11-kit</literal> provides functions to - coordinate initialization and finalization of any PKCS#11 - module. A module may be initialized any number of times using - the p11_kit_initialize_module() function. The first time that - p11_kit_initialize_module() is called for a module, that module's - C_Initialize function is used. Later invocations for the same - module cause p11-kit to increment an internal initialization - count, rather than calling C_Initialize again.</para> - - <para>The p11_kit_finalize_module() is used to finalize a module. - Each time it is called it decrements the internal initialization - count for that module. When the internal initialization count - reaches zero, the module's C_Finalize function is called.</para> - - <para>This is done in a thread-safe manner. These functions can - be used on modules that the consumer loads themselves.</para> - </section> - - <section xml:id="sharing-module"> - <title>Solution: proxy module</title> - - <para>When an application is aware of the fact that coordination - is necessary between multiple consumers of a PKCS#11 module, it - can link to p11-kit and use the functions there to provide - this coordination.</para> - - <para>However most current consumers of PKCS#11 are ignorant of - this problem, and do not link to p11-kit. In order to solve this - multiple initialization problem for all applications, - <literal>p11-kit</literal> provides a proxy compatibility - module.</para> - - <para>This proxy module acts like a normal PKCS#11 module, but - internally loads a preconfigured set of PKCS#11 modules and - coordinates their initialization and finalization. Each slot - in the configured modules is exposed as a slot of the - <literal>p11-kit</literal> proxy module. The proxy module is - then used as a normal PKCS#11 module would be. It can be loaded by - crypto libraries like NSS and behaves as expected.</para> - - <para>The proxy module bends the PKCS#11 rules slightly. It does - not return the <literal>CKR_CRYPTOKI_ALREADY_INITIALIZED</literal> - error code as specified in PKCS#11. However this is a small - price to pay for this compatibility.</para> + <section xml:id="sharing-managed"> + <title>Managed modules</title> + + <para><literal>p11-kit</literal> wraps PKCS#11 modules to manage + them and customize their functionality so that they are able + to be shared between multiple callers in the same process.</para> + + <para>Each caller that uses the + <link linkend="p11-kit-modules-load"><function>p11_kit_modules_load()</function></link> + or <link linkend="p11-kit-module-load"><function>p11_kit_module_load()</function></link> + function gets independent wrapped PKCS#11 module(s). This is unless a caller + or module configuration specifies that a module should be used in an + unmanaged fashion.</para> + + <para>When modules are managed, the following aspects are wrapped and + coordinated:</para> + + <itemizedlist> + <listitem> + <para>Calls to <literal>C_Initialize</literal> and + <literal>C_Finalize</literal> can be called by multiple + callers.</para> + + <para>The first time that the managed module + <literal>C_Initialize</literal> is called, the PKCS#11 module's actual + <literal>C_Initialize</literal> function is called. Subsequent calls by + other callers will cause <literal>p11-kit</literal> to increment an + internal initialization count, rather than calling + <literal>C_Initialize</literal> again.</para> + + <para>Multiple callers can call the managed + <literal>C_Initialize</literal> function concurrently from different + threads and <literal>p11-kit</literal> will guarantee that this managed + in a thread-safe manner.</para> + </listitem> + <listitem> + <para>When the managed module <literal>C_Finalize</literal> is used + to finalize a module, each time it is called it decrements the internal + initialization count for that module. When the internal initialization + count reaches zero, the module's actual <literal>C_Finalize</literal> + function is called.</para> + + <para>Multiple callers can call the managed <literal>C_Finalize</literal> + function concurrently from different threads and <literal>p11-kit</literal> + will guarantee that this managed in a thread-safe manner.</para> + </listitem> + </itemizedlist> </section> </chapter> diff --git a/doc/manual/pkcs11.conf.xml b/doc/manual/pkcs11.conf.xml index 1814377..1051ee1 100644 --- a/doc/manual/pkcs11.conf.xml +++ b/doc/manual/pkcs11.conf.xml @@ -128,6 +128,16 @@ x-custom : text </listitem> </varlistentry> <varlistentry> + <term><option>managed:</option></term> + <listitem> + <para>Set to <literal>no</literal> if the module is not to be managed by + p11-kit. Making a module unmanaged is not recommended, and will cause + problems if multiple callers in a single process share a PKCS#11 module.</para> + + <para>This argument is optonal and defaults to <literal>yes</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> <term><option>priority:</option></term> <listitem> <para>The value should be an integer. When lists of modules are @@ -172,6 +182,20 @@ x-custom : text <literal>none</literal>, <literal>merge</literal>, <literal>only</literal>.</para></listitem> </varlistentry> + <varlistentry> + <term><option>managed:</option></term> + <listitem> + <para>Set to <literal>yes</literal> or <literal>no</literal> to + force all modules to be managed or unmanaged by p11-kit. Setting this + setting in a global configuration file will override the + <literal>managed</literal> setting in the individual module configuration + files. Making modules unmanaged is not recommended, and will cause + problems if multiple callers in a single process share a PKCS#11 + module.</para> + + <para>This argument is optonal.</para> + </listitem> + </varlistentry> </variablelist> <para>Other fields may be present, but it is recommended that field names diff --git a/gtk-doc.make b/gtk-doc.make index cbef74b..824d8d6 100644 --- a/gtk-doc.make +++ b/gtk-doc.make @@ -116,7 +116,7 @@ scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB) fi @touch scan-build.stamp -$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp +$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES): scan-build.stamp @true #### xml #### 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; +} diff --git a/tools/extract.c b/tools/extract.c index cd0f369..3d1fee7 100644 --- a/tools/extract.c +++ b/tools/extract.c @@ -231,7 +231,7 @@ limit_modules_if_necessary (CK_FUNCTION_LIST_PTR *modules, /* TODO: This logic will move once we merge our p11-kit managed code */ for (i = 0, out = 0; modules[i] != NULL; i++) { - string = p11_kit_registered_option (modules[i], "trust-policy"); + string = p11_kit_config_option (modules[i], "trust-policy"); if (string && strcmp (string, "yes") == 0) modules[out++] = modules[i]; else if (string && strcmp (string, "no") != 0) @@ -305,7 +305,6 @@ p11_tool_extract (int argc, CK_ATTRIBUTE *match; P11KitUri *uri; int opt = 0; - CK_RV rv; int ret; enum { @@ -435,13 +434,10 @@ p11_tool_extract (int argc, if (uri && p11_kit_uri_any_unrecognized (uri)) p11_message ("uri contained unrecognized components, nothing will be extracted"); - rv = p11_kit_initialize_registered (); - if (rv != CKR_OK) { - p11_message ("couldn't initialize registered modules: %s", p11_kit_strerror (rv)); + modules = p11_kit_modules_load_and_initialize (0); + if (!modules) return 1; - } - modules = p11_kit_registered_modules (); limit_modules_if_necessary (modules, ex.flags); iter = p11_kit_iter_new (uri); @@ -456,8 +452,9 @@ p11_tool_extract (int argc, p11_extract_info_cleanup (&ex); p11_kit_iter_free (iter); p11_kit_uri_free (uri); - free (modules); - p11_kit_finalize_registered (); + p11_kit_modules_finalize (modules); + p11_kit_modules_release (modules); + return ret; } diff --git a/tools/list.c b/tools/list.c index da99940..fe028ae 100644 --- a/tools/list.c +++ b/tools/list.c @@ -203,20 +203,15 @@ print_modules (void) CK_FUNCTION_LIST_PTR *module_list; char *name; char *path; - CK_RV rv; int i; - rv = p11_kit_initialize_registered (); - if (rv != CKR_OK) { - p11_message ("couldn't initialize registered modules: %s", - p11_kit_strerror (rv)); + module_list = p11_kit_modules_load_and_initialize (0); + if (!module_list) return 1; - } - module_list = p11_kit_registered_modules (); for (i = 0; module_list[i]; i++) { - name = p11_kit_registered_module_to_name (module_list[i]); - path = p11_kit_registered_option (module_list[i], "module"); + name = p11_kit_module_get_name (module_list[i]); + path = p11_kit_config_option (module_list[i], "module"); printf ("%s: %s\n", name ? name : "(null)", @@ -226,9 +221,8 @@ print_modules (void) free (name); free (path); } - free (module_list); - p11_kit_finalize_registered (); + p11_kit_modules_finalize_and_release (module_list); return 0; } diff --git a/tools/tests/test-extract.c b/tools/tests/test-extract.c index 74e3c9c..a3db8d8 100644 --- a/tools/tests/test-extract.c +++ b/tools/tests/test-extract.c @@ -32,6 +32,8 @@ * Author: Stef Walter <stefw@collabora.co.uk> */ +#define P11_KIT_DISABLE_DEPRECATED + #include "config.h" #include "CuTest.h" @@ -145,9 +147,10 @@ setup (CuTest *tc) { CK_RV rv; + mock_module_reset (); memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST)); - rv = p11_kit_initialize_module (&test.module); + rv = test.module.C_Initialize (NULL); CuAssertIntEquals (tc, CKR_OK, rv); test.iter = p11_kit_iter_new (NULL); @@ -164,7 +167,7 @@ teardown (CuTest *tc) p11_kit_iter_free (test.iter); - rv = p11_kit_finalize_module (&test.module); + rv = test.module.C_Finalize (NULL); CuAssertIntEquals (tc, CKR_OK, rv); } diff --git a/tools/tests/test-openssl.c b/tools/tests/test-openssl.c index 215e0da..c778aa7 100644 --- a/tools/tests/test-openssl.c +++ b/tools/tests/test-openssl.c @@ -32,6 +32,8 @@ * Author: Stef Walter <stefw@collabora.co.uk> */ +#define P11_KIT_DISABLE_DEPRECATED + #include "config.h" #include "CuTest.h" @@ -69,12 +71,11 @@ setup (CuTest *tc) { CK_RV rv; + mock_module_reset (); memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST)); - rv = p11_kit_initialize_module (&test.module); + rv = test.module.C_Initialize (NULL); CuAssertIntEquals (tc, CKR_OK, rv); - mock_module_reset_objects (MOCK_SLOT_ONE_ID); - test.iter = p11_kit_iter_new (NULL); p11_extract_info_init (&test.ex); @@ -96,7 +97,7 @@ teardown (CuTest *tc) p11_extract_info_cleanup (&test.ex); p11_kit_iter_free (test.iter); - rv = p11_kit_finalize_module (&test.module); + rv = test.module.C_Finalize (NULL); CuAssertIntEquals (tc, CKR_OK, rv); } diff --git a/tools/tests/test-pem.c b/tools/tests/test-pem.c index dc1cb08..4024bac 100644 --- a/tools/tests/test-pem.c +++ b/tools/tests/test-pem.c @@ -32,6 +32,8 @@ * Author: Stef Walter <stefw@collabora.co.uk> */ +#define P11_KIT_DISABLE_DEPRECATED + #include "config.h" #include "CuTest.h" @@ -66,12 +68,11 @@ setup (CuTest *tc) { CK_RV rv; + mock_module_reset (); memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST)); - rv = p11_kit_initialize_module (&test.module); + rv = test.module.C_Initialize (NULL); CuAssertIntEquals (tc, CKR_OK, rv); - mock_module_reset_objects (MOCK_SLOT_ONE_ID); - test.iter = p11_kit_iter_new (NULL); p11_extract_info_init (&test.ex); @@ -93,7 +94,7 @@ teardown (CuTest *tc) p11_extract_info_cleanup (&test.ex); p11_kit_iter_free (test.iter); - rv = p11_kit_finalize_module (&test.module); + rv = test.module.C_Finalize (NULL); CuAssertIntEquals (tc, CKR_OK, rv); } diff --git a/tools/tests/test-x509.c b/tools/tests/test-x509.c index e952e53..5093743 100644 --- a/tools/tests/test-x509.c +++ b/tools/tests/test-x509.c @@ -32,6 +32,8 @@ * Author: Stef Walter <stefw@collabora.co.uk> */ +#define P11_KIT_DISABLE_DEPRECATED + #include "config.h" #include "CuTest.h" @@ -66,12 +68,11 @@ setup (CuTest *tc) { CK_RV rv; + mock_module_reset (); memcpy (&test.module, &mock_module, sizeof (CK_FUNCTION_LIST)); - rv = p11_kit_initialize_module (&test.module); + rv = test.module.C_Initialize (NULL); CuAssertIntEquals (tc, CKR_OK, rv); - mock_module_reset_objects (MOCK_SLOT_ONE_ID); - test.iter = p11_kit_iter_new (NULL); p11_extract_info_init (&test.ex); @@ -93,7 +94,7 @@ teardown (CuTest *tc) p11_extract_info_cleanup (&test.ex); p11_kit_iter_free (test.iter); - rv = p11_kit_finalize_module (&test.module); + rv = test.module.C_Finalize (NULL); CuAssertIntEquals (tc, CKR_OK, rv); } diff --git a/trust/tests/frob-nss-trust.c b/trust/tests/frob-nss-trust.c index da76795..a81b5e2 100644 --- a/trust/tests/frob-nss-trust.c +++ b/trust/tests/frob-nss-trust.c @@ -102,7 +102,10 @@ dump_trust_module (const char *path) CK_ULONG count = p11_attrs_count (template); - rv = p11_kit_load_initialize_module (path, &module); + module = p11_kit_module_load (path, 0); + return_val_if_fail (module != NULL, 1); + + rv = p11_kit_module_initialize (module); return_val_if_fail (rv == CKR_OK, 1); iter = p11_kit_iter_new (NULL); @@ -120,7 +123,8 @@ dump_trust_module (const char *path) return_val_if_fail (rv == CKR_CANCEL, 1); - p11_kit_finalize_module (module); + p11_kit_module_finalize (module); + p11_kit_module_release (module); return 0; } @@ -152,10 +156,16 @@ compare_trust_modules (const char *path1, { CKA_INVALID, } }; - rv = p11_kit_load_initialize_module (path1, &module1); + module1 = p11_kit_module_load (path1, 0); + return_val_if_fail (module1 != NULL, 1); + + rv = p11_kit_module_initialize (module1); return_val_if_fail (rv == CKR_OK, 1); - rv = p11_kit_load_initialize_module (path2, &module2); + module2 = p11_kit_module_load (path2, 0); + return_val_if_fail (module2 != NULL, 1); + + rv = p11_kit_module_initialize (module2); return_val_if_fail (rv == CKR_OK, 1); iter = p11_kit_iter_new (NULL); @@ -185,8 +195,11 @@ compare_trust_modules (const char *path1, } return_val_if_fail (rv == CKR_CANCEL, 1); - p11_kit_finalize_module (module1); - p11_kit_finalize_module (module2); + p11_kit_module_finalize (module1); + p11_kit_module_release (module1); + + p11_kit_module_finalize (module2); + p11_kit_module_release (module2); return 0; } |