diff options
author | Stef Walter <stefw@gnome.org> | 2013-01-21 11:06:41 +0100 |
---|---|---|
committer | Stef Walter <stefw@gnome.org> | 2013-02-05 14:54:53 +0100 |
commit | 3e70ecbab850bcc08ee89e1256d82cca70d80ee7 (patch) | |
tree | fadca8bd00fb750cbbedf51c09c2bf65e2689a1c | |
parent | e5816187231ce27e5f634995e62c1d3ae5c5b2f1 (diff) |
Add public iterator API to p11-kit
-rw-r--r-- | common/mock.c | 113 | ||||
-rw-r--r-- | common/mock.h | 37 | ||||
-rw-r--r-- | doc/Makefile.am | 1 | ||||
-rw-r--r-- | doc/annotation-glossary.xml | 67 | ||||
-rw-r--r-- | doc/p11-kit-docs.sgml | 3 | ||||
-rw-r--r-- | doc/p11-kit-sections.txt | 17 | ||||
-rw-r--r-- | p11-kit/Makefile.am | 2 | ||||
-rw-r--r-- | p11-kit/iter.c | 829 | ||||
-rw-r--r-- | p11-kit/iter.h | 101 | ||||
-rw-r--r-- | p11-kit/p11-kit.h | 2 | ||||
-rw-r--r-- | p11-kit/tests/Makefile.am | 4 | ||||
-rw-r--r-- | p11-kit/tests/mock-module-ep.c | 2 | ||||
-rw-r--r-- | p11-kit/tests/test-iter.c | 1140 |
13 files changed, 2308 insertions, 10 deletions
diff --git a/common/mock.c b/common/mock.c index 14fd3ec..411c6eb 100644 --- a/common/mock.c +++ b/common/mock.c @@ -34,6 +34,7 @@ #include "config.h" +#include "debug.h" #include "library.h" #define CRYPTOKI_EXPORTS #include "pkcs11.h" @@ -220,7 +221,7 @@ mock_module_reset_objects (CK_SLOT_ID slot_id) { CKA_LABEL, label, strlen (label) }, { CKA_INVALID, NULL, 0 }, }; - p11_dict_set (the_objects, handle_to_pointer (2), p11_attrs_dup (attrs)); + p11_dict_set (the_objects, handle_to_pointer (MOCK_DATA_OBJECT), p11_attrs_dup (attrs)); } /* Private capitalize key */ @@ -353,8 +354,6 @@ mock_C_Initialize (CK_VOID_PTR init_args) CK_RV ret = CKR_OK; pid_t pid; - p11_debug ("C_Initialize: enter"); - p11_mutex_lock (&init_mutex); if (init_args != NULL) { @@ -369,7 +368,7 @@ mock_C_Initialize (CK_VOID_PTR init_args) (args->CreateMutex != NULL && args->DestroyMutex != NULL && args->LockMutex != NULL && args->UnlockMutex != NULL); if (!supplied_ok) { - p11_debug_precond ("p11-kit: invalid set of mutex calls supplied"); + p11_debug_precond ("invalid set of mutex calls supplied\n"); ret = CKR_ARGUMENTS_BAD; goto done; } @@ -379,7 +378,7 @@ mock_C_Initialize (CK_VOID_PTR init_args) * We must be able to use our pthread functionality. */ if (!(args->flags & CKF_OS_LOCKING_OK)) { - p11_debug_precond ("p11-kit: can't do without os locking"); + p11_debug_precond ("can't do without os locking\n"); ret = CKR_CANT_LOCK; goto done; } @@ -390,7 +389,7 @@ mock_C_Initialize (CK_VOID_PTR init_args) /* This process has called C_Initialize already */ if (pid == pkcs11_initialized_pid) { - p11_debug_precond ("p11-kit: C_Initialize called twice for same process"); + p11_debug_precond ("p11-kit: C_Initialize called twice for same process\n"); ret = CKR_CRYPTOKI_ALREADY_INITIALIZED; goto done; } @@ -560,7 +559,25 @@ mock_C_GetSlotInfo (CK_SLOT_ID slot_id, } CK_RV -mock_C_GetSlotInfo__invalid_slotid (CK_SLOT_ID slot_id, +mock_C_GetSlotList__fail_first (CK_BBOOL token_present, + CK_SLOT_ID_PTR slot_list, + CK_ULONG_PTR count) +{ + return CKR_VENDOR_DEFINED; +} + +CK_RV +mock_C_GetSlotList__fail_late (CK_BBOOL token_present, + CK_SLOT_ID_PTR slot_list, + CK_ULONG_PTR count) +{ + if (!slot_list) + return mock_C_GetSlotList (token_present, slot_list, count); + return CKR_VENDOR_DEFINED; +} + +CK_RV +mock_C_GetSlotInfo__invalid_slotid (CK_SLOT_ID id, CK_SLOT_INFO_PTR info) { return_val_if_fail (info, CKR_ARGUMENTS_BAD); @@ -650,7 +667,26 @@ mock_C_GetMechanismList (CK_SLOT_ID slot_id, } CK_RV -mock_C_GetMechanismList__invalid_slotid (CK_SLOT_ID slot_id, +mock_C_GetTokenInfo_not_initialized (CK_SLOT_ID slot_id, + CK_TOKEN_INFO_PTR info) +{ + CK_RV rv; + + rv = mock_C_GetTokenInfo (slot_id, info); + if (rv == CKR_OK) + info->flags &= ~ CKF_TOKEN_INITIALIZED; + + return rv; +} + +/* + * TWO mechanisms: + * CKM_MOCK_CAPITALIZE + * CKM_MOCK_PREFIX + */ + +CK_RV +mock_C_GetMechanismList__invalid_slotid (CK_SLOT_ID id, CK_MECHANISM_TYPE_PTR mechanism_list, CK_ULONG_PTR count) { @@ -808,6 +844,18 @@ mock_C_OpenSession__invalid_slotid (CK_SLOT_ID slot_id, } CK_RV +mock_C_OpenSession__fails (CK_SLOT_ID slot_id, + CK_FLAGS flags, + CK_VOID_PTR user_data, + CK_NOTIFY callback, + CK_SESSION_HANDLE_PTR session) +{ + return_val_if_fail (session, CKR_ARGUMENTS_BAD); + + return CKR_DEVICE_ERROR; +} + +CK_RV mock_C_CloseSession (CK_SESSION_HANDLE session) { Session *sess; @@ -1339,6 +1387,30 @@ mock_C_GetAttributeValue__invalid_handle (CK_SESSION_HANDLE session, } CK_RV +mock_C_GetAttributeValue__fail_first (CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR template, + CK_ULONG count) +{ + return CKR_FUNCTION_REJECTED; +} + +CK_RV +mock_C_GetAttributeValue__fail_late (CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR template, + CK_ULONG count) +{ + CK_ULONG i; + + for (i = 0; i < count; i++) { + if (template[i].pValue) + return CKR_FUNCTION_FAILED; + } + return mock_C_GetAttributeValue (session, object, template, count); +} + +CK_RV mock_C_SetAttributeValue (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR template, @@ -1386,8 +1458,14 @@ enumerate_and_find_objects (CK_OBJECT_HANDLE object, FindObjects *ctx = user_data; CK_ATTRIBUTE *match; CK_ATTRIBUTE *attr; + CK_BBOOL private; CK_ULONG i; + if (!logged_in) { + if (p11_attrs_find_bool (attrs, CKA_PRIVATE, &private) && private) + return 1; /* Continue */ + } + for (i = 0; i < ctx->count; ++i) { match = ctx->template + i; attr = p11_attrs_find (attrs, match->type); @@ -1450,6 +1528,14 @@ mock_C_FindObjectsInit__invalid_handle (CK_SESSION_HANDLE session, } CK_RV +mock_C_FindObjectsInit__fails (CK_SESSION_HANDLE session, + CK_ATTRIBUTE_PTR template, + CK_ULONG count) +{ + return CKR_DEVICE_MEMORY; +} + +CK_RV mock_C_FindObjects (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects, CK_ULONG max_object_count, @@ -1493,6 +1579,17 @@ mock_C_FindObjects__invalid_handle (CK_SESSION_HANDLE session, } CK_RV +mock_C_FindObjects__fails (CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE_PTR objects, + CK_ULONG max_count, + CK_ULONG_PTR count) +{ + return_val_if_fail (count, CKR_ARGUMENTS_BAD); + + return CKR_DEVICE_REMOVED; +} + +CK_RV mock_C_FindObjectsFinal (CK_SESSION_HANDLE session) { diff --git a/common/mock.h b/common/mock.h index 5beebe6..daac1c8 100644 --- a/common/mock.h +++ b/common/mock.h @@ -67,6 +67,7 @@ enum { MOCK_SLOT_ONE_ID = 52, MOCK_SLOT_TWO_ID = 134, + MOCK_DATA_OBJECT = 2, MOCK_PRIVATE_KEY_CAPITALIZE = 3, MOCK_PUBLIC_KEY_CAPITALIZE = 4, MOCK_PRIVATE_KEY_PREFIX = 5, @@ -109,6 +110,14 @@ CK_RV mock_C_GetSlotList__no_tokens (CK_BBOOL token_presen CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count); +CK_RV mock_C_GetSlotList__fail_first (CK_BBOOL token_present, + CK_SLOT_ID_PTR slot_list, + CK_ULONG_PTR count); + +CK_RV mock_C_GetSlotList__fail_late (CK_BBOOL token_present, + CK_SLOT_ID_PTR slot_list, + CK_ULONG_PTR count); + CK_RV mock_C_GetSlotInfo (CK_SLOT_ID slot_id, CK_SLOT_INFO_PTR info); @@ -121,6 +130,9 @@ CK_RV mock_C_GetTokenInfo (CK_SLOT_ID slot_id, CK_RV mock_C_GetTokenInfo__invalid_slotid (CK_SLOT_ID slot_id, CK_TOKEN_INFO_PTR info); +CK_RV mock_C_GetTokenInfo_not_initialized (CK_SLOT_ID slot_id, + CK_TOKEN_INFO_PTR info); + CK_RV mock_C_GetMechanismList (CK_SLOT_ID slot_id, CK_MECHANISM_TYPE_PTR mechanism_list, CK_ULONG_PTR count); @@ -161,6 +173,12 @@ CK_RV mock_C_OpenSession__invalid_slotid (CK_SLOT_ID slot_id, CK_NOTIFY callback, CK_SESSION_HANDLE_PTR session); +CK_RV mock_C_OpenSession__fails (CK_SLOT_ID slot_id, + CK_FLAGS flags, + CK_VOID_PTR user_data, + CK_NOTIFY callback, + CK_SESSION_HANDLE_PTR session); + CK_RV mock_C_OpenSession (CK_SLOT_ID slot_id, CK_FLAGS flags, CK_VOID_PTR user_data, @@ -289,6 +307,16 @@ CK_RV mock_C_GetAttributeValue__invalid_handle (CK_SESSION_HANDLE ses CK_ATTRIBUTE_PTR template, CK_ULONG count); +CK_RV mock_C_GetAttributeValue__fail_first (CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR template, + CK_ULONG count); + +CK_RV mock_C_GetAttributeValue__fail_late (CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE object, + CK_ATTRIBUTE_PTR template, + CK_ULONG count); + CK_RV mock_C_SetAttributeValue (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_ATTRIBUTE_PTR template, @@ -307,6 +335,10 @@ CK_RV mock_C_FindObjectsInit__invalid_handle (CK_SESSION_HANDLE ses CK_ATTRIBUTE_PTR template, CK_ULONG count); +CK_RV mock_C_FindObjectsInit__fails (CK_SESSION_HANDLE session, + CK_ATTRIBUTE_PTR template, + CK_ULONG count); + CK_RV mock_C_FindObjects (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE_PTR objects, CK_ULONG max_object_count, @@ -317,6 +349,11 @@ CK_RV mock_C_FindObjects__invalid_handle (CK_SESSION_HANDLE ses CK_ULONG max_count, CK_ULONG_PTR count); +CK_RV mock_C_FindObjects__fails (CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE_PTR objects, + CK_ULONG max_count, + CK_ULONG_PTR count); + CK_RV mock_C_FindObjectsFinal (CK_SESSION_HANDLE session); CK_RV mock_C_FindObjectsFinal__invalid_handle (CK_SESSION_HANDLE session); diff --git a/doc/Makefile.am b/doc/Makefile.am index 3154215..e5befe7 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -69,6 +69,7 @@ content_files=p11-kit-config.xml p11-kit-sharing.xml \ p11-kit-devel.xml \ p11-kit-trust.xml \ p11-kit.xml \ + annotation-glossary.xml \ $(NULL) # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded diff --git a/doc/annotation-glossary.xml b/doc/annotation-glossary.xml new file mode 100644 index 0000000..4a0f8a6 --- /dev/null +++ b/doc/annotation-glossary.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!DOCTYPE glossary PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ +<!ENTITY version SYSTEM "version.xml"> +]> + +<glossary id="annotation-glossary"> +<title>Annotation Glossary</title> +<glossdiv><title>A</title> + <glossentry> + <glossterm><anchor id="annotation-glossterm-allow-none"/>allow-none</glossterm> + <glossdef> + <para>NULL is ok, both for passing and for returning.</para> + </glossdef> + </glossentry> + <glossentry> + <glossterm><anchor id="annotation-glossterm-array"/>array</glossterm> + <glossdef> + <para>Parameter points to an array of items.</para> + </glossdef> + </glossentry> +</glossdiv> +<glossdiv><title>E</title> + <glossentry> + <glossterm><anchor id="annotation-glossterm-element-type"/>element-type</glossterm> + <glossdef> + <para>Generics and defining elements of containers and arrays.</para> + </glossdef> + </glossentry> +</glossdiv> +<glossdiv><title>I</title> + <glossentry> + <glossterm><anchor id="annotation-glossterm-inout"/>inout</glossterm> + <glossdef> + <para>Parameter for input and for returning results. Default is <acronym>transfer full</acronym>.</para> + </glossdef> + </glossentry> +</glossdiv> +<glossdiv><title>O</title> + <glossentry> + <glossterm><anchor id="annotation-glossterm-out"/>out</glossterm> + <glossdef> + <para>Parameter for returning results. Default is <acronym>transfer full</acronym>.</para> + </glossdef> + </glossentry> +</glossdiv> +<glossdiv><title>T</title> + <glossentry> + <glossterm><anchor id="annotation-glossterm-transfer full"/>transfer full</glossterm> + <glossdef> + <para>Free data after the code is done.</para> + </glossdef> + </glossentry> + <glossentry> + <glossterm><anchor id="annotation-glossterm-type"/>type</glossterm> + <glossdef> + <para>Override the parsed C type with given type</para> + </glossdef> + </glossentry> + <glossentry> + <glossterm><anchor id="annotation-glossterm-transfer none"/>transfer none</glossterm> + <glossdef> + <para>Don't free data after the code is done.</para> + </glossdef> + </glossentry> +</glossdiv> +</glossary>
\ No newline at end of file diff --git a/doc/p11-kit-docs.sgml b/doc/p11-kit-docs.sgml index 5627f6f..7138690 100644 --- a/doc/p11-kit-docs.sgml +++ b/doc/p11-kit-docs.sgml @@ -27,10 +27,13 @@ <xi:include href="xml/p11-kit-pin.xml"/> <xi:include href="xml/p11-kit-util.xml"/> <xi:include href="xml/p11-kit-future.xml"/> + <index id="api-index-full"> <title>API Index</title> <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include> </index> + + <xi:include href="annotation-glossary.xml"/> </chapter> <xi:include href="p11-kit-devel.xml"/> diff --git a/doc/p11-kit-sections.txt b/doc/p11-kit-sections.txt index c6a4686..dc85f2d 100644 --- a/doc/p11-kit-sections.txt +++ b/doc/p11-kit-sections.txt @@ -86,4 +86,21 @@ p11_kit_set_progname p11_kit_be_quiet p11_kit_be_loud p11_kit_message +p11_kit_destroyer +P11KitIter +p11_kit_iter_new +p11_kit_iter_set_session_flags +p11_kit_iter_add_callback +p11_kit_iter_callback +p11_kit_iter_add_filter +p11_kit_iter_begin +p11_kit_iter_begin_with +p11_kit_iter_next +p11_kit_iter_get_module +p11_kit_iter_get_slot +p11_kit_iter_get_session +p11_kit_iter_keep_session +p11_kit_iter_get_object +p11_kit_iter_load_attributes +p11_kit_iter_free </SECTION> diff --git a/p11-kit/Makefile.am b/p11-kit/Makefile.am index 650fe44..776d337 100644 --- a/p11-kit/Makefile.am +++ b/p11-kit/Makefile.am @@ -13,6 +13,7 @@ INCLUDES = \ incdir = $(includedir)/p11-kit-1/p11-kit inc_HEADERS = \ + iter.h \ p11-kit.h \ pin.h \ uri.h \ @@ -21,6 +22,7 @@ inc_HEADERS = \ MODULE_SRCS = \ util.c \ conf.c conf.h \ + iter.c \ modules.c \ pkcs11.h \ pin.c \ diff --git a/p11-kit/iter.c b/p11-kit/iter.c new file mode 100644 index 0000000..4a4dbd3 --- /dev/null +++ b/p11-kit/iter.c @@ -0,0 +1,829 @@ +/* + * 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> + */ + +#include "config.h" + +#include "array.h" +#include "attrs.h" +#include "debug.h" +#include "iter.h" +#include "pin.h" +#include "private.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +typedef struct _Callback { + p11_kit_iter_callback func; + void *callback_data; + p11_kit_destroyer destroyer; + struct _Callback *next; +} Callback; + +#define MAX_OBJECTS 64 + +/** + * P11KitIter: + * + * Used to iterate over PKCS\#11 objects. + */ +typedef struct p11_kit_iter { + + /* Iterator matching data */ + CK_INFO match_module; + CK_TOKEN_INFO match_token; + CK_ATTRIBUTE *match_attrs; + Callback *callbacks; + CK_FLAGS session_flags; + + /* The input modules */ + p11_array *modules; + + /* The results of C_GetSlotList */ + CK_SLOT_ID *slots; + CK_ULONG num_slots; + CK_ULONG saw_slots; + + /* The results of C_FindObjects */ + CK_OBJECT_HANDLE objects[MAX_OBJECTS]; + CK_ULONG num_objects; + CK_ULONG saw_objects; + + /* The current iteration */ + CK_FUNCTION_LIST_PTR module; + CK_SLOT_ID slot; + CK_SESSION_HANDLE session; + CK_OBJECT_HANDLE object; + + /* And various flags */ + int searching : 1; + int searched : 1; + int iterating : 1; + int match_nothing : 1; + int keep_session : 1; +} P11KitIter; + +/** + * p11_kit_iter_new: + * @uri: (allow-none): a PKCS\#11 URI to filter on, or %NULL + * + * Create a new PKCS\#11 iterator for iterating over objects. Only + * objects that match the @uri will be returned by the iterator. + * Relevant information in @uri is copied, and you need not keep + * @uri around. + * + * If no @uri is specified then the iterator will iterate over all + * objects, unless otherwise filtered. + * + * Returns: (transfer full): a new iterator, which should be freed + * with p11_kit_iter_free() + */ +P11KitIter * +p11_kit_iter_new (P11KitUri *uri) +{ + P11KitIter *iter; + CK_ATTRIBUTE *attrs; + CK_TOKEN_INFO *tinfo; + CK_INFO *minfo; + CK_ULONG count; + + iter = calloc (1, sizeof (P11KitIter)); + return_val_if_fail (iter != NULL, NULL); + + iter->modules = p11_array_new (NULL); + return_val_if_fail (iter->modules != NULL, NULL); + + if (uri != NULL) { + + if (p11_kit_uri_any_unrecognized (uri)) { + iter->match_nothing = 1; + + } else { + attrs = p11_kit_uri_get_attributes (uri, &count); + iter->match_attrs = p11_attrs_buildn (NULL, attrs, count); + + minfo = p11_kit_uri_get_module_info (uri); + if (minfo != NULL) + memcpy (&iter->match_module, minfo, sizeof (CK_INFO)); + + tinfo = p11_kit_uri_get_token_info (uri); + if (tinfo != NULL) + memcpy (&iter->match_token, tinfo, sizeof (CK_TOKEN_INFO)); + } + } else { + /* Match any module version number*/ + iter->match_module.libraryVersion.major = (CK_BYTE)-1; + iter->match_module.libraryVersion.minor = (CK_BYTE)-1; + } + + iter->session_flags = CKF_SERIAL_SESSION; + + return iter; +} + +/** + * p11_kit_iter_set_session_flags: + * @iter: the iterator + * @flags: set of session flags + * + * Set the PKCS\#11 session flags to be used when the iterator opens + * new sessions. + */ +void +p11_kit_iter_set_session_flags (P11KitIter *iter, + CK_FLAGS flags) +{ + return_if_fail (iter != NULL); + return_if_fail (!iter->iterating); + iter->session_flags = flags | CKF_SERIAL_SESSION; +} + +/** + * p11_kit_destroyer: + * @data: data to destroy + * + * A callback called to free a resource. + */ + +/** + * p11_kit_iter_callback: + * @iter: the iterator + * @matches: (out): whether to match the current object + * @data: callback data + * + * A callback setup with p11_kit_iter_add_callback(). This callback is + * called for each object iterated. + * + * If the callback sets @matches to CK_FALSE, then this object is + * skipped and not matched by p11_kit_iter_next(). If you return + * anything but CKR_OK, then the iteration is stopped, and + * p11_kit_iter_next() returns the result code. + * + * Returns: CKR_OK to continue iterating, CKR_CANCEL to stop, or + * anything else to fail + */ + +/** + * p11_kit_iter_add_callback: + * @iter: the iterator + * @callback: a function to call for each iteration + * @callback_data: (allow-none): data to pass to the function + * @callback_destroy: (allow-none): used to cleanup the data + * + * Adds a callback to the iterator which will be called each time + * that an object is iterated. + * + * These callbacks can also perform filtering. If any callback + * indicates through it's <literal>matches</literal> argument that + * the object should not match, then that object will not be iterated + * as far as p11_kit_iter_next() is concerned. + */ +void +p11_kit_iter_add_callback (P11KitIter *iter, + p11_kit_iter_callback callback, + void *callback_data, + p11_kit_destroyer callback_destroy) +{ + Callback *cb; + + return_if_fail (iter != NULL); + return_if_fail (callback != NULL); + + cb = calloc (1, sizeof (Callback)); + return_if_fail (cb != NULL); + + cb->func = callback; + cb->destroyer = callback_destroy; + cb->callback_data = callback_data; + cb->next = iter->callbacks; + iter->callbacks = cb; +} + +/** + * p11_kit_iter_add_filter: + * @iter: the iterator + * @matching: (array length=count): the attributes that the objects should match + * @count: the number of attributes + * + * Add a filter to limit the objects that the iterator iterates over. + * + * Only objects matching the passed in attributes will be iterated. + * This function can be called multiple times. + * + * The @matching attributes are copied. + */ +void +p11_kit_iter_add_filter (P11KitIter *iter, + CK_ATTRIBUTE *matching, + CK_ULONG count) +{ + return_if_fail (iter != NULL); + return_if_fail (!iter->iterating); + + iter->match_attrs = p11_attrs_buildn (iter->match_attrs, matching, count); + return_if_fail (iter->match_attrs != NULL); +} + +static void +finish_object (P11KitIter *iter) +{ + iter->object = 0; +} + +static void +finish_slot (P11KitIter *iter) +{ + if (iter->session && !iter->keep_session) { + assert (iter->module != NULL); + (iter->module->C_CloseSession) (iter->session); + } + + iter->keep_session = 0; + iter->session = 0; + iter->searched = 0; + iter->searching = 0; + iter->slot = 0; +} + +static void +finish_module (P11KitIter *iter) +{ + iter->num_slots = 0; + iter->saw_slots = 0; + iter->module = NULL; +} + +static CK_RV +finish_iterating (P11KitIter *iter, + CK_RV rv) +{ + finish_object (iter); + finish_slot (iter); + finish_module (iter); + p11_array_clear (iter->modules); + + iter->iterating = 0; + return rv; +} + +/** + * p11_kit_iter_begin: + * @iter: the iterator + * @modules: (array zero-terminated=1): null-terminated list of + * modules to iterate over + * + * Begin iterating PKCS\#11 objects in the given @modules. + * + * The @modules arguments should be a null-terminated list of + * pointers to the modules' PKCS\#11 function pointers. + * + * For each module, all initialized slots will be iterated over, + * having sessions opened for each of them in turn, and searched + * for objects matching the search criteria. + */ +void +p11_kit_iter_begin (P11KitIter *iter, + CK_FUNCTION_LIST_PTR *modules) +{ + int i; + + return_if_fail (modules != NULL); + + finish_iterating (iter, CKR_OK); + + /* Use this module */ + for (i = 0; modules[i] != NULL; i++) { + if (!p11_array_push (iter->modules, modules[i])) + return_if_reached (); + } + + iter->iterating = 1; + iter->searched = 1; +} + +/** + * p11_kit_iter_begin_with: + * @iter: the iterator + * @module: the module to iterate over + * @slot: (allow-none): the slot to iterate objects in, or zero + * @session: (allow-none): the session to search for objects on, or zero + * + * Begin iterating PKCS\#11 objects in the given @module. + * + * If @slot is non-zero then the iteration will be limited to that + * slot. + * + * If @session is non-zero then the iteration will be limited to + * objects visible through that session, which implies that they + * are also limited to the slot which the session was opened for. + */ +void +p11_kit_iter_begin_with (P11KitIter *iter, + CK_FUNCTION_LIST_PTR module, + CK_SLOT_ID slot, + CK_SESSION_HANDLE session) +{ + CK_SESSION_INFO info; + CK_RV rv; + + finish_iterating (iter, CKR_OK); + + return_if_fail (module != NULL); + + if (session != 0) { + /* + * A currently active session. Initialize as if we're ready + * to search using this session. + */ + + /* If we have a session, but no slot, then look it up */ + if (slot == 0) { + assert (module != NULL); + rv = (module->C_GetSessionInfo) (session, &info); + if (rv == CKR_OK) + slot = info.slotID; + } + + /* So initialize as if we're ready to search */ + iter->session = session; + iter->slot = slot; + iter->module = module; + iter->keep_session = 1; + + } else if (slot != 0) { + + /* + * Limit to this slot. Initialize as if we're ready to use the + * slot from the slots list. + */ + + iter->module = module; + iter->slots = realloc (iter->slots, sizeof (CK_SLOT_ID)); + return_if_fail (iter->slots != NULL); + iter->slots[0] = slot; + iter->num_slots = 1; + iter->searched = 1; + + } else { + + /* + * Limit to this module. Initialize as if we're ready to use + * the module from the modules array. + */ + + assert (module != NULL); + p11_array_push (iter->modules, module); + iter->session = 0; + iter->slot = 0; + iter->searched = 1; + } + + iter->iterating = 1; +} + +static CK_RV +call_all_filters (P11KitIter *iter, + CK_BBOOL *matches) +{ + Callback *cb; + CK_RV rv; + + *matches = CK_TRUE; + + for (cb = iter->callbacks; cb != NULL; cb = cb->next) { + rv = (cb->func) (iter, matches, cb->callback_data); + if (rv != CKR_OK || !*matches) + return rv; + } + + return CKR_OK; +} + +static CK_RV +move_next_session (P11KitIter *iter) +{ + CK_TOKEN_INFO tinfo; + CK_ULONG num_slots; + CK_INFO minfo; + CK_RV rv; + + finish_slot (iter); + + /* If we have no more slots, then move to next module */ + while (iter->saw_slots >= iter->num_slots) { + finish_module (iter); + + /* Iter is finished */ + if (iter->modules->num == 0) + return finish_iterating (iter, CKR_CANCEL); + + iter->module = iter->modules->elem[0]; + p11_array_remove (iter->modules, 0); + + /* Skip module if it doesn't match uri */ + assert (iter->module != NULL); + rv = (iter->module->C_GetInfo) (&minfo); + if (rv != CKR_OK || !p11_match_uri_module_info (&iter->match_module, &minfo)) + continue; + + rv = (iter->module->C_GetSlotList) (CK_TRUE, NULL, &num_slots); + if (rv != CKR_OK) + return finish_iterating (iter, rv); + + iter->slots = realloc (iter->slots, sizeof (CK_SLOT_ID) * (num_slots + 1)); + return_val_if_fail (iter->slots != NULL, CKR_HOST_MEMORY); + + rv = (iter->module->C_GetSlotList) (CK_TRUE, iter->slots, &num_slots); + if (rv != CKR_OK) + return finish_iterating (iter, rv); + + iter->num_slots = num_slots; + assert (iter->saw_slots == 0); + } + + /* Move to the next slot, and open a session on it */ + while (iter->saw_slots < iter->num_slots) { + iter->slot = iter->slots[iter->saw_slots++]; + + assert (iter->module != NULL); + rv = (iter->module->C_GetTokenInfo) (iter->slot, &tinfo); + if (rv != CKR_OK || !p11_match_uri_token_info (&iter->match_token, &tinfo)) + continue; + + /* Token is not initialized, we're not going to get further, so skip */ + if (!(tinfo.flags & CKF_TOKEN_INITIALIZED)) + continue; + + rv = (iter->module->C_OpenSession) (iter->slot, iter->session_flags, + NULL, NULL, &iter->session); + if (rv != CKR_OK) + return finish_iterating (iter, rv); + + if (iter->session != 0) + return CKR_OK; + } + + /* Otherwise try again */ + return move_next_session (iter); +} + +/** + * p11_kit_iter_next: + * @iter: the iterator + * + * Iterate to the next matching object. + * + * To access the object, session and so on, use the p11_kit_iter_get_object(), + * p11_kit_iter_get_session(), and p11_kit_iter_get_module() functions. + * + * This call must only be called after either p11_kit_iter_begin() + * or p11_kit_iter_begin_with() have been called. + * + * Objects which are skipped by callbacks will not be returned here + * as matching objects. + * + * Returns: CKR_OK if an object matched, CKR_CANCEL if no more objects, or another error + */ +CK_RV +p11_kit_iter_next (P11KitIter *iter) +{ + CK_ULONG count; + CK_BBOOL matches; + CK_RV rv; + + return_val_if_fail (iter->iterating, CKR_OPERATION_NOT_INITIALIZED); + + iter->object = 0; + + if (iter->match_nothing) + return finish_iterating (iter, CKR_CANCEL); + + /* + * If we have outstanding objects, then iterate one through those + * Note that we pass each object through the filters, and only + * assume it's iterated if it matches + */ + while (iter->saw_objects < iter->num_objects) { + iter->object = iter->objects[iter->saw_objects++]; + + rv = call_all_filters (iter, &matches); + if (rv != CKR_OK) + return finish_iterating (iter, rv); + + if (matches) + return CKR_OK; + } + + /* If we have finished searching then move to next session */ + if (iter->searched) { + rv = move_next_session (iter); + if (rv != CKR_OK) + return finish_iterating (iter, rv); + } + + /* Ready to start searching */ + if (!iter->searching && !iter->searched) { + count = p11_attrs_count (iter->match_attrs); + rv = (iter->module->C_FindObjectsInit) (iter->session, iter->match_attrs, count); + if (rv != CKR_OK) + return finish_iterating (iter, rv); + iter->searching = 1; + iter->searched = 0; + } + + /* If we have searched on this session then try to continue */ + if (iter->searching) { + assert (iter->module != NULL); + assert (iter->session != 0); + iter->num_objects = 0; + iter->saw_objects = 0; + + rv = (iter->module->C_FindObjects) (iter->session, iter->objects, + MAX_OBJECTS, &iter->num_objects); + if (rv != CKR_OK) + return finish_iterating (iter, rv); + + /* + * Done searching on this session, although there are still + * objects outstanding, which will be returned on next + * iterations. + */ + if (iter->num_objects != MAX_OBJECTS) { + iter->searching = 0; + iter->searched = 1; + (iter->module->C_FindObjectsFinal) (iter->session); + } + } + + /* Try again */ + return p11_kit_iter_next (iter); +} + +/** + * p11_kit_iter_get_module: + * @iter: the iterator + * + * Get the module function pointers for the current matching object. + * + * This can only be called after p11_kit_iter_next() succeeds. + * + * Returns: the module which the current matching object is in + */ +CK_FUNCTION_LIST_PTR +p11_kit_iter_get_module (P11KitIter *iter) +{ + return_val_if_fail (iter != NULL, NULL); + return_val_if_fail (iter->iterating, 0); + return iter->module; +} + +/** + * p11_kit_iter_get_slot: + * @iter: the iterator + * + * Get the slot which the current matching object is on. + * + * This can only be called after p11_kit_iter_next() succeeds. + * + * Returns: the slot of the current matching object + */ +CK_SLOT_ID +p11_kit_iter_get_slot (P11KitIter *iter) +{ + return_val_if_fail (iter != NULL, 0); + return_val_if_fail (iter->iterating, 0); + return iter->slot; +} + +/** + * p11_kit_iter_get_session: + * @iter: the iterator + * + * Get the session which the current matching object is acessible + * through. + * + * This can only be called after p11_kit_iter_next() succeeds. + * + * The session may be closed after the next p11_kit_iter_next() call + * unless p11_kit_iter_keep_session() is called. + * + * Returns: the slot of the current matching object + */ +CK_SESSION_HANDLE +p11_kit_iter_get_session (P11KitIter *iter) +{ + return_val_if_fail (iter != NULL, 0); + return_val_if_fail (iter->iterating, 0); + return iter->session; +} + +/** + * p11_kit_iter_get_object: + * @iter: the iterator + * + * Get the current matching object. + * + * This can only be called after p11_kit_iter_next() succeeds. + * + * Returns: the current matching object + */ +CK_OBJECT_HANDLE +p11_kit_iter_get_object (P11KitIter *iter) +{ + return_val_if_fail (iter != NULL, 0); + return iter->object; +} + +/** + * p11_kit_iter_load_attributes: + * @iter: the iterator + * @template: (array length=count) (inout): the attributes to load + * @count: the number of attributes + * + * Retrieve attributes for the current matching object. + * + * Each attribute in the array will be filled in with the value + * of that attribute retrieved from the object. After use the + * attribute value memory pointed to by the <literal>pValue</literal> + * of each attribute should be freed with the <literal>free<!-- -->()</literal> + * function. + * + * If the <literal>pValue</literal> of an attribute is not %NULL passed + * to this function, then it will be passed to + * <literal>realloc<!-- -->()</literal> to allocate the correct amount + * of space for the attribute value. + * + * If any attribute is not present on the object, or is sensitive and + * cannot be retrieved, then the <literal>pValue</literal> will be NULL. + * If <literal>pValue</literal> was not %NULL when passed to this function + * then it will be freed with <literal>free<!-- -->()</literal>. In these + * cases <literal>CKR_OK</literal> is returned. + * + * This can only be called after p11_kit_iter_next() succeeds. + * + * Returns: CKR_OK or a failure code + */ +CK_RV +p11_kit_iter_load_attributes (P11KitIter *iter, + CK_ATTRIBUTE *template, + CK_ULONG count) +{ + CK_ATTRIBUTE *original = NULL; + CK_ULONG i; + CK_RV rv; + + return_val_if_fail (iter != NULL, CKR_GENERAL_ERROR); + return_val_if_fail (iter->iterating, CKR_GENERAL_ERROR); + return_val_if_fail (iter->module != NULL, CKR_GENERAL_ERROR); + return_val_if_fail (iter->session != 0, CKR_GENERAL_ERROR); + return_val_if_fail (iter->object != 0, CKR_GENERAL_ERROR); + + if (count == 0) + return CKR_OK; + + original = memdup (template, count * sizeof (CK_ATTRIBUTE)); + return_val_if_fail (original != NULL, CKR_HOST_MEMORY); + + for (i = 0; i < count; i++) + template[i].pValue = NULL; + + rv = (iter->module->C_GetAttributeValue) (iter->session, iter->object, template, count); + + switch (rv) { + case CKR_OK: + case CKR_ATTRIBUTE_TYPE_INVALID: + case CKR_ATTRIBUTE_SENSITIVE: + case CKR_BUFFER_TOO_SMALL: + break; + default: + free (original); + return rv; + } + + for (i = 0; i < count; i++) { + if (template[i].ulValueLen == (CK_ULONG)-1 || + template[i].ulValueLen == 0) { + free (original[i].pValue); + + } else if (original[i].pValue != NULL && + template[i].ulValueLen == original[i].ulValueLen) { + template[i].pValue = original[i].pValue; + + } else { + template[i].pValue = realloc (original[i].pValue, template[i].ulValueLen); + return_val_if_fail (template[i].pValue != NULL, 0); + } + } + + free (original); + + rv = (iter->module->C_GetAttributeValue) (iter->session, iter->object, template, count); + + switch (rv) { + case CKR_OK: + case CKR_ATTRIBUTE_TYPE_INVALID: + case CKR_ATTRIBUTE_SENSITIVE: + rv = CKR_OK; + break; + default: + return_val_if_fail (rv != CKR_BUFFER_TOO_SMALL, rv); + return rv; + } + + for (i = 0; i < count; i++) { + if (template[i].ulValueLen == (CK_ULONG)-1 || + template[i].ulValueLen == 0) { + free (template[i].pValue); + template[i].pValue = NULL; + } + } + + return rv; +} + +/** + * p11_kit_iter_keep_session: + * @iter: the iterator + * + * After calling this function the session open for iterating + * the current object will not be automatically closed by + * the iterator after later calls to p11_kit_iter_next() or + * p11_kit_iter_free(). + * + * It is the callers responsibility to close this session, + * after the iterator has been freed. The session may still be + * used by the iterator if further iterations are performed. + * + * This can only be called after p11_kit_iter_next() succeeds. + * + * Returns: the current session + */ +CK_SESSION_HANDLE +p11_kit_iter_keep_session (P11KitIter *iter) +{ + return_val_if_fail (iter != NULL, 0); + return_val_if_fail (iter->iterating, 0); + return_val_if_fail (iter->session != 0, 0); + + iter->keep_session = 1; + return iter->session; +} + +/** + * p11_kit_iter_free: + * @iter: the iterator + * + * Frees the iterator and all resources, such as sessions + * or callbacks held by the iterator. + */ +void +p11_kit_iter_free (P11KitIter *iter) +{ + Callback *cb, *next; + + if (iter == NULL) + return; + + finish_iterating (iter, CKR_OK); + p11_array_free (iter->modules); + p11_attrs_free (iter->match_attrs); + + for (cb = iter->callbacks; cb != NULL; cb = next) { + next = cb->next; + if (cb->destroyer) + (cb->destroyer) (cb->callback_data); + free (cb); + } +} diff --git a/p11-kit/iter.h b/p11-kit/iter.h new file mode 100644 index 0000000..2b87273 --- /dev/null +++ b/p11-kit/iter.h @@ -0,0 +1,101 @@ +/* + * 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_ITER_H +#define P11_KIT_ITER_H + +#include "p11-kit/p11-kit.h" +#include "p11-kit/pkcs11.h" +#include "p11-kit/uri.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef P11_KIT_FUTURE_UNSTABLE_API + +typedef struct p11_kit_iter P11KitIter; + +typedef CK_RV (* p11_kit_iter_callback) (P11KitIter *iter, + CK_BBOOL *matches, + void *data); + +P11KitIter * p11_kit_iter_new (P11KitUri *uri); + +void p11_kit_iter_free (P11KitIter *iter); + +void p11_kit_iter_set_session_flags (P11KitIter *iter, + CK_FLAGS flags); + +void p11_kit_iter_add_callback (P11KitIter *iter, + p11_kit_iter_callback callback, + void *callback_data, + p11_kit_destroyer callback_destroy); + +void p11_kit_iter_add_filter (P11KitIter *iter, + CK_ATTRIBUTE *matching, + CK_ULONG count); + +void p11_kit_iter_begin (P11KitIter *iter, + CK_FUNCTION_LIST_PTR *modules); + +void p11_kit_iter_begin_with (P11KitIter *iter, + CK_FUNCTION_LIST_PTR module, + CK_SLOT_ID slot, + CK_SESSION_HANDLE session); + +CK_RV p11_kit_iter_next (P11KitIter *iter); + +CK_FUNCTION_LIST_PTR p11_kit_iter_get_module (P11KitIter *iter); + +CK_SLOT_ID p11_kit_iter_get_slot (P11KitIter *iter); + +CK_SESSION_HANDLE p11_kit_iter_get_session (P11KitIter *iter); + +CK_OBJECT_HANDLE p11_kit_iter_get_object (P11KitIter *iter); + +CK_RV p11_kit_iter_load_attributes (P11KitIter *iter, + CK_ATTRIBUTE *template, + CK_ULONG count); + +CK_SESSION_HANDLE p11_kit_iter_keep_session (P11KitIter *iter); + + +#endif /* P11_KIT_FUTURE_UNSTABLE_API */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* P11_KIT_ITER_H */ diff --git a/p11-kit/p11-kit.h b/p11-kit/p11-kit.h index 042ed44..f83cbd0 100644 --- a/p11-kit/p11-kit.h +++ b/p11-kit/p11-kit.h @@ -88,6 +88,8 @@ void p11_kit_be_loud (void); const char* p11_kit_message (void); +typedef void (* p11_kit_destroyer) (void *data); + #endif #ifdef __cplusplus diff --git a/p11-kit/tests/Makefile.am b/p11-kit/tests/Makefile.am index e39ac8f..a6c9fac 100644 --- a/p11-kit/tests/Makefile.am +++ b/p11-kit/tests/Makefile.am @@ -23,7 +23,9 @@ CHECK_PROGS = \ uri-test \ pin-test \ test-init \ - test-modules + test-modules \ + test-iter \ + $(NULL) noinst_PROGRAMS = \ print-messages \ diff --git a/p11-kit/tests/mock-module-ep.c b/p11-kit/tests/mock-module-ep.c index 89b31f6..9ba739a 100644 --- a/p11-kit/tests/mock-module-ep.c +++ b/p11-kit/tests/mock-module-ep.c @@ -49,6 +49,6 @@ C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list) mock_module_no_slots.C_GetFunctionList = C_GetFunctionList; if (list == NULL) return CKR_ARGUMENTS_BAD; - *list = &mock_module_no_slots; + *list = &mock_module; return CKR_OK; } diff --git a/p11-kit/tests/test-iter.c b/p11-kit/tests/test-iter.c new file mode 100644 index 0000000..31f25e4 --- /dev/null +++ b/p11-kit/tests/test-iter.c @@ -0,0 +1,1140 @@ +/* + * 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@collabora.co.uk> + */ + +#include "config.h" +#include "CuTest.h" + +#define P11_KIT_FUTURE_UNSTABLE_API 1 + +#include "attrs.h" +#include "iter.h" +#include "library.h" +#include "mock.h" + +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +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 (); + CuAssertTrue (tc, modules != NULL && modules[0] != NULL); + + p11_message_loud (); + + 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 int +has_handle (CK_ULONG *objects, + int count, + CK_ULONG handle) +{ + int i; + for (i = 0; i < count; i++) { + if (objects[i] == handle) + return 1; + } + + return 0; +} + + +static void +test_all (CuTest *tc) +{ + CK_OBJECT_HANDLE objects[128]; + CK_FUNCTION_LIST_PTR *modules; + CK_FUNCTION_LIST_PTR module; + CK_SESSION_HANDLE session; + CK_ULONG size; + P11KitIter *iter; + CK_RV rv; + int at; + + modules = initialize_and_get_modules (tc); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin (iter, modules); + + at = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + CuAssertTrue (tc, at < 128); + objects[at] = p11_kit_iter_get_object (iter); + + module = p11_kit_iter_get_module (iter); + CuAssertPtrNotNull (tc, module); + + session = p11_kit_iter_get_session (iter); + CuAssertTrue (tc, session != 0); + + /* Do something with the object */ + size = 0; + rv = (module->C_GetObjectSize) (session, objects[at], &size); + CuAssertTrue (tc, rv == CKR_OK); + CuAssertTrue (tc, size > 0); + + at++; + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Three modules, each with 1 slot, and 3 public objects */ + CuAssertIntEquals (tc, 9, at); + + CuAssertTrue (tc, has_handle (objects, at, MOCK_DATA_OBJECT)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_CAPITALIZE)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_CAPITALIZE)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_PREFIX)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_PREFIX)); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static CK_RV +on_iter_callback (P11KitIter *iter, + CK_BBOOL *matches, + void *data) +{ + CuTest *tc = data; + CK_OBJECT_HANDLE object; + CK_FUNCTION_LIST_PTR module; + CK_SESSION_HANDLE session; + CK_ULONG size; + CK_RV rv; + + object = p11_kit_iter_get_object (iter); + if (object != MOCK_PUBLIC_KEY_CAPITALIZE && object != MOCK_PUBLIC_KEY_PREFIX) { + *matches = CK_FALSE; + return CKR_OK; + } + + module = p11_kit_iter_get_module (iter); + CuAssertPtrNotNull (tc, module); + + session = p11_kit_iter_get_session (iter); + CuAssertTrue (tc, session != 0); + + /* Do something with the object */ + size = 0; + rv = (module->C_GetObjectSize) (session, object, &size); + CuAssertTrue (tc, rv == CKR_OK); + CuAssertTrue (tc, size > 0); + + return CKR_OK; +} + +static void +test_callback (CuTest *tc) +{ + CK_OBJECT_HANDLE objects[128]; + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + CK_RV rv; + int at; + + modules = initialize_and_get_modules (tc); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_add_callback (iter, on_iter_callback, tc, NULL); + p11_kit_iter_begin (iter, modules); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + CuAssertTrue (tc, at < 128); + objects[at] = p11_kit_iter_get_object (iter); + at++; + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Three modules, each with 1 slot, and 2 public keys */ + CuAssertIntEquals (tc, 6, at); + + CuAssertTrue (tc, !has_handle (objects, at, MOCK_DATA_OBJECT)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_CAPITALIZE)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_CAPITALIZE)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_PREFIX)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_PREFIX)); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static CK_RV +on_callback_fail (P11KitIter *iter, + CK_BBOOL *matches, + void *data) +{ + return CKR_DATA_INVALID; +} + +static void +test_callback_fails (CuTest *tc) +{ + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + CK_RV rv; + int at; + + modules = initialize_and_get_modules (tc); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_add_callback (iter, on_callback_fail, tc, NULL); + p11_kit_iter_begin (iter, modules); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + at++; + + CuAssertTrue (tc, rv == CKR_DATA_INVALID); + + /* Shouldn't have succeeded at all */ + CuAssertIntEquals (tc, 0, at); + + p11_kit_iter_free (iter); + finalize_and_free_modules (tc, modules); +} + +static void +on_destroy_increment (void *data) +{ + int *value = data; + (*value)++; +} + +static void +test_callback_destroyer (CuTest *tc) +{ + P11KitIter *iter; + int value = 1; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_add_callback (iter, on_callback_fail, &value, on_destroy_increment); + p11_kit_iter_free (iter); + + CuAssertIntEquals (tc, 2, value); +} + +static void +test_with_session (CuTest *tc) +{ + CK_OBJECT_HANDLE objects[128]; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST_PTR module; + CK_SLOT_ID slot; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + rv = mock_C_OpenSession (MOCK_SLOT_ONE_ID, CKF_SERIAL_SESSION, NULL, NULL, &session); + CuAssertTrue (tc, rv == CKR_OK); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &mock_module, 0, session); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + CuAssertTrue (tc, at < 128); + objects[at] = p11_kit_iter_get_object (iter); + + slot = p11_kit_iter_get_slot (iter); + CuAssertTrue (tc, slot == MOCK_SLOT_ONE_ID); + + module = p11_kit_iter_get_module (iter); + CuAssertPtrEquals (tc, module, &mock_module); + + CuAssertTrue (tc, session == p11_kit_iter_get_session (iter)); + at++; + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* 1 modules, each with 1 slot, and 3 public objects */ + CuAssertIntEquals (tc, 3, at); + + CuAssertTrue (tc, has_handle (objects, at, MOCK_DATA_OBJECT)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_CAPITALIZE)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_CAPITALIZE)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_PREFIX)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_PREFIX)); + + p11_kit_iter_free (iter); + + /* The session is still valid ... */ + rv = mock_module.C_CloseSession (session); + CuAssertTrue (tc, rv == CKR_OK); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_with_slot (CuTest *tc) +{ + CK_OBJECT_HANDLE objects[128]; + CK_FUNCTION_LIST_PTR module; + CK_SLOT_ID slot; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &mock_module, MOCK_SLOT_ONE_ID, 0); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + CuAssertTrue (tc, at < 128); + objects[at] = p11_kit_iter_get_object (iter); + + slot = p11_kit_iter_get_slot (iter); + CuAssertTrue (tc, slot == MOCK_SLOT_ONE_ID); + + module = p11_kit_iter_get_module (iter); + CuAssertPtrEquals (tc, module, &mock_module); + at++; + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* 1 modules, each with 1 slot, and 3 public objects */ + CuAssertIntEquals (tc, 3, at); + + CuAssertTrue (tc, has_handle (objects, at, MOCK_DATA_OBJECT)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_CAPITALIZE)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_CAPITALIZE)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_PREFIX)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_PREFIX)); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_with_module (CuTest *tc) +{ + CK_OBJECT_HANDLE objects[128]; + CK_FUNCTION_LIST_PTR module; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &mock_module, 0, 0); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + CuAssertTrue (tc, at < 128); + objects[at] = p11_kit_iter_get_object (iter); + + module = p11_kit_iter_get_module (iter); + CuAssertPtrEquals (tc, module, &mock_module); + at++; + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* 1 modules, each with 1 slot, and 3 public objects */ + CuAssertIntEquals (tc, 3, at); + + CuAssertTrue (tc, has_handle (objects, at, MOCK_DATA_OBJECT)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_CAPITALIZE)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_CAPITALIZE)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_PREFIX)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_PREFIX)); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_keep_session (CuTest *tc) +{ + CK_SESSION_HANDLE session; + P11KitIter *iter; + CK_RV rv; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &mock_module, 0, 0); + + rv = p11_kit_iter_next (iter); + CuAssertTrue (tc, rv == CKR_OK); + + session = p11_kit_iter_keep_session (iter); + p11_kit_iter_free (iter); + + /* The session is still valid ... */ + rv = mock_module.C_CloseSession (session); + CuAssertTrue (tc, rv == CKR_OK); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_unrecognized (CuTest *tc) +{ + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + P11KitUri *uri; + CK_RV rv; + int count; + + modules = initialize_and_get_modules (tc); + + uri = p11_kit_uri_new (); + p11_kit_uri_set_unrecognized (uri, 1); + iter = p11_kit_iter_new (uri); + p11_kit_uri_free (uri); + + p11_kit_iter_begin (iter, modules); + + count = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + count++; + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Nothing should have matched */ + CuAssertIntEquals (tc, 0, count); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_uri_with_type (CuTest *tc) +{ + CK_OBJECT_HANDLE objects[128]; + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + P11KitUri *uri; + CK_RV rv; + int at; + int ret; + + modules = initialize_and_get_modules (tc); + + uri = p11_kit_uri_new (); + ret = p11_kit_uri_parse ("pkcs11:object-type=public", P11_KIT_URI_FOR_OBJECT, uri); + CuAssertIntEquals (tc, ret, P11_KIT_URI_OK); + + iter = p11_kit_iter_new (uri); + p11_kit_uri_free (uri); + + p11_kit_iter_begin (iter, modules); + + at = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + CuAssertTrue (tc, at < 128); + objects[at] = p11_kit_iter_get_object (iter); + at++; + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Three modules, each with 1 slot, and 2 public keys */ + CuAssertIntEquals (tc, 6, at); + + CuAssertTrue (tc, !has_handle (objects, at, MOCK_DATA_OBJECT)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_CAPITALIZE)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_CAPITALIZE)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_PREFIX)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_PREFIX)); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_filter (CuTest *tc) +{ + CK_OBJECT_HANDLE objects[128]; + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + CK_RV rv; + int at; + + CK_BBOOL vfalse = CK_FALSE; + CK_OBJECT_CLASS public_key = CKO_PUBLIC_KEY; + CK_ATTRIBUTE attrs[] = { + { CKA_PRIVATE, &vfalse, sizeof (vfalse) }, + { CKA_CLASS, &public_key, sizeof (public_key) }, + }; + + modules = initialize_and_get_modules (tc); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_add_filter (iter, attrs, 2); + + p11_kit_iter_begin (iter, modules); + + at = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + CuAssertTrue (tc, at < 128); + objects[at] = p11_kit_iter_get_object (iter); + at++; + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Three modules, each with 1 slot, and 2 public keys */ + CuAssertIntEquals (tc, 6, at); + + CuAssertTrue (tc, !has_handle (objects, at, MOCK_DATA_OBJECT)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_CAPITALIZE)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_CAPITALIZE)); + CuAssertTrue (tc, !has_handle (objects, at, MOCK_PRIVATE_KEY_PREFIX)); + CuAssertTrue (tc, has_handle (objects, at, MOCK_PUBLIC_KEY_PREFIX)); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_session_flags (CuTest *tc) +{ + CK_FUNCTION_LIST_PTR *modules; + CK_FUNCTION_LIST_PTR module; + CK_SESSION_HANDLE session; + CK_SESSION_INFO info; + P11KitIter *iter; + CK_RV rv; + + modules = initialize_and_get_modules (tc); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_set_session_flags (iter, CKF_RW_SESSION); + + p11_kit_iter_begin (iter, modules); + + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + module = p11_kit_iter_get_module (iter); + CuAssertPtrNotNull (tc, module); + + session = p11_kit_iter_get_session (iter); + CuAssertTrue (tc, session != 0); + + rv = (module->C_GetSessionInfo) (session, &info); + CuAssertTrue (tc, rv == CKR_OK); + + CuAssertIntEquals (tc, CKS_RW_PUBLIC_SESSION, info.state); + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_module_match (CuTest *tc) +{ + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + P11KitUri *uri; + CK_RV rv; + int count; + int ret; + + modules = initialize_and_get_modules (tc); + + uri = p11_kit_uri_new (); + ret = p11_kit_uri_parse ("pkcs11:library-description=MOCK%20LIBRARY", P11_KIT_URI_FOR_MODULE, uri); + CuAssertIntEquals (tc, P11_KIT_URI_OK, ret); + + iter = p11_kit_iter_new (uri); + p11_kit_uri_free (uri); + + p11_kit_iter_begin (iter, modules); + + count = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + count++; + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Three modules, each with 1 slot, and 3 public objects */ + CuAssertIntEquals (tc, 9, count); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_module_mismatch (CuTest *tc) +{ + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + P11KitUri *uri; + CK_RV rv; + int count; + int ret; + + modules = initialize_and_get_modules (tc); + + uri = p11_kit_uri_new (); + ret = p11_kit_uri_parse ("pkcs11:library-description=blah", P11_KIT_URI_FOR_MODULE, uri); + CuAssertIntEquals (tc, P11_KIT_URI_OK, ret); + + iter = p11_kit_iter_new (uri); + p11_kit_uri_free (uri); + + p11_kit_iter_begin (iter, modules); + + count = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + count++; + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Nothing should have matched */ + CuAssertIntEquals (tc, 0, count); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_token_match (CuTest *tc) +{ + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + P11KitUri *uri; + CK_RV rv; + int count; + int ret; + + modules = initialize_and_get_modules (tc); + + uri = p11_kit_uri_new (); + ret = p11_kit_uri_parse ("pkcs11:manufacturer=TEST%20MANUFACTURER", P11_KIT_URI_FOR_TOKEN, uri); + CuAssertIntEquals (tc, P11_KIT_URI_OK, ret); + + iter = p11_kit_iter_new (uri); + p11_kit_uri_free (uri); + + p11_kit_iter_begin (iter, modules); + + count = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + count++; + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Three modules, each with 1 slot, and 3 public objects */ + CuAssertIntEquals (tc, 9, count); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_token_mismatch (CuTest *tc) +{ + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + P11KitUri *uri; + CK_RV rv; + int count; + int ret; + + modules = initialize_and_get_modules (tc); + + uri = p11_kit_uri_new (); + ret = p11_kit_uri_parse ("pkcs11:manufacturer=blah", P11_KIT_URI_FOR_TOKEN, uri); + CuAssertIntEquals (tc, P11_KIT_URI_OK, ret); + + iter = p11_kit_iter_new (uri); + p11_kit_uri_free (uri); + + p11_kit_iter_begin (iter, modules); + + count = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + count++; + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Nothing should have matched */ + CuAssertIntEquals (tc, 0, count); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_getslotlist_fail_first (CuTest *tc) +{ + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + module.C_GetSlotList = mock_C_GetSlotList__fail_first; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + at++; + + CuAssertTrue (tc, rv == CKR_VENDOR_DEFINED); + + /* Should fail on the first iteration */ + CuAssertIntEquals (tc, 0, at); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_getslotlist_fail_late (CuTest *tc) +{ + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + module.C_GetSlotList = mock_C_GetSlotList__fail_late; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + at++; + + CuAssertTrue (tc, rv == CKR_VENDOR_DEFINED); + + /* Should fail on the first iteration */ + CuAssertIntEquals (tc, 0, at); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_token_not_initialized (CuTest *tc) +{ + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + module.C_GetTokenInfo = mock_C_GetTokenInfo_not_initialized; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + at++; + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Should fail on the first iteration */ + CuAssertIntEquals (tc, 0, at); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_open_session_fail (CuTest *tc) +{ + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + module.C_OpenSession = mock_C_OpenSession__fails; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + at++; + + CuAssertTrue (tc, rv == CKR_DEVICE_ERROR); + + /* Should fail on the first iteration */ + CuAssertIntEquals (tc, 0, at); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_find_init_fail (CuTest *tc) +{ + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + module.C_FindObjectsInit = mock_C_FindObjectsInit__fails; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + at++; + + CuAssertTrue (tc, rv == CKR_DEVICE_MEMORY); + + /* Should fail on the first iteration */ + CuAssertIntEquals (tc, 0, at); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_find_objects_fail (CuTest *tc) +{ + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_RV rv; + int at; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + module.C_FindObjects = mock_C_FindObjects__fails; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + at= 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) + at++; + + CuAssertTrue (tc, rv == CKR_DEVICE_REMOVED); + + /* Should fail on the first iteration */ + CuAssertIntEquals (tc, 0, at); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_load_attributes (CuTest *tc) +{ + CK_FUNCTION_LIST_PTR *modules; + P11KitIter *iter; + CK_ATTRIBUTE *attrs; + CK_OBJECT_HANDLE object; + CK_ULONG ulong; + CK_RV rv; + int at; + + CK_ATTRIBUTE types[] = { + { CKA_CLASS }, + { CKA_LABEL }, + }; + + modules = initialize_and_get_modules (tc); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin (iter, modules); + + attrs = p11_attrs_buildn (NULL, types, 2); + + at = 0; + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + rv = p11_kit_iter_load_attributes (iter, attrs, 2); + CuAssertTrue (tc, rv == CKR_OK); + + object = p11_kit_iter_get_object (iter); + switch (object) { + case MOCK_DATA_OBJECT: + CuAssertTrue (tc, p11_attrs_find_ulong (attrs, CKA_CLASS, &ulong) && ulong == CKO_DATA); + CuAssertTrue (tc, p11_attr_match_value (p11_attrs_find (attrs, CKA_LABEL), "TEST LABEL", -1)); + break; + case MOCK_PUBLIC_KEY_CAPITALIZE: + CuAssertTrue (tc, p11_attrs_find_ulong (attrs, CKA_CLASS, &ulong) && ulong == CKO_PUBLIC_KEY); + CuAssertTrue (tc, p11_attr_match_value (p11_attrs_find (attrs, CKA_LABEL), "Public Capitalize Key", -1)); + break; + case MOCK_PUBLIC_KEY_PREFIX: + CuAssertTrue (tc, p11_attrs_find_ulong (attrs, CKA_CLASS, &ulong) && ulong == CKO_PUBLIC_KEY); + CuAssertTrue (tc, p11_attr_match_value (p11_attrs_find (attrs, CKA_LABEL), "Public prefix key", -1)); + break; + default: + CuFail (tc, "Unknown object matched"); + break; + } + + at++; + } + + p11_attrs_free (attrs); + + CuAssertTrue (tc, rv == CKR_CANCEL); + + /* Three modules, each with 1 slot, and 3 public objects */ + CuAssertIntEquals (tc, 9, at); + + p11_kit_iter_free (iter); + + finalize_and_free_modules (tc, modules); +} + +static void +test_load_attributes_none (CuTest *tc) +{ + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_ATTRIBUTE *attrs; + CK_RV rv; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + attrs = p11_attrs_buildn (NULL, NULL, 0); + rv = p11_kit_iter_load_attributes (iter, attrs, 0); + CuAssertTrue (tc, rv == CKR_OK); + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_load_attributes_fail_first (CuTest *tc) +{ + CK_ATTRIBUTE label = { CKA_LABEL, }; + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_ATTRIBUTE *attrs; + CK_RV rv; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + module.C_GetAttributeValue = mock_C_GetAttributeValue__fail_first; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + attrs = p11_attrs_build (NULL, &label, NULL); + rv = p11_kit_iter_load_attributes (iter, attrs, 1); + CuAssertTrue (tc, rv == CKR_FUNCTION_REJECTED); + p11_attrs_free (attrs); + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +static void +test_load_attributes_fail_late (CuTest *tc) +{ + CK_ATTRIBUTE label = { CKA_LABEL, }; + CK_FUNCTION_LIST module; + P11KitIter *iter; + CK_ATTRIBUTE *attrs; + CK_RV rv; + + rv = p11_kit_initialize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); + + memcpy (&module, &mock_module, sizeof (CK_FUNCTION_LIST)); + module.C_GetAttributeValue = mock_C_GetAttributeValue__fail_late; + + iter = p11_kit_iter_new (NULL); + p11_kit_iter_begin_with (iter, &module, 0, 0); + + while ((rv = p11_kit_iter_next (iter)) == CKR_OK) { + attrs = p11_attrs_build (NULL, &label, NULL); + rv = p11_kit_iter_load_attributes (iter, attrs, 1); + CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED); + p11_attrs_free (attrs); + } + + CuAssertTrue (tc, rv == CKR_CANCEL); + + p11_kit_iter_free (iter); + + rv = p11_kit_finalize_module (&mock_module); + CuAssertTrue (tc, rv == CKR_OK); +} + +int +main (void) +{ + CuString *output = CuStringNew (); + CuSuite* suite = CuSuiteNew (); + int ret; + + setenv ("P11_KIT_STRICT", "1", 1); + p11_library_init (); + mock_module_init (); + + SUITE_ADD_TEST (suite, test_all); + SUITE_ADD_TEST (suite, test_unrecognized); + SUITE_ADD_TEST (suite, test_uri_with_type); + SUITE_ADD_TEST (suite, test_session_flags); + SUITE_ADD_TEST (suite, test_callback); + SUITE_ADD_TEST (suite, test_callback_fails); + SUITE_ADD_TEST (suite, test_callback_destroyer); + SUITE_ADD_TEST (suite, test_filter); + SUITE_ADD_TEST (suite, test_with_session); + SUITE_ADD_TEST (suite, test_with_slot); + SUITE_ADD_TEST (suite, test_with_module); + SUITE_ADD_TEST (suite, test_keep_session); + SUITE_ADD_TEST (suite, test_token_match); + SUITE_ADD_TEST (suite, test_token_mismatch); + SUITE_ADD_TEST (suite, test_module_match); + SUITE_ADD_TEST (suite, test_module_mismatch); + SUITE_ADD_TEST (suite, test_getslotlist_fail_first); + SUITE_ADD_TEST (suite, test_getslotlist_fail_late); + SUITE_ADD_TEST (suite, test_token_not_initialized); + SUITE_ADD_TEST (suite, test_open_session_fail); + SUITE_ADD_TEST (suite, test_find_init_fail); + SUITE_ADD_TEST (suite, test_find_objects_fail); + SUITE_ADD_TEST (suite, test_load_attributes); + SUITE_ADD_TEST (suite, test_load_attributes_none); + SUITE_ADD_TEST (suite, test_load_attributes_fail_first); + SUITE_ADD_TEST (suite, test_load_attributes_fail_late); + + CuSuiteRun (suite); + CuSuiteSummary (suite, output); + CuSuiteDetails (suite, output); + printf ("%s\n", output->buffer); + ret = suite->failCount; + CuSuiteDelete (suite); + CuStringDelete (output); + return ret; +} |