summaryrefslogtreecommitdiff
path: root/trust
diff options
context:
space:
mode:
Diffstat (limited to 'trust')
-rw-r--r--trust/Makefile.am52
-rw-r--r--trust/module.c1517
-rw-r--r--trust/module.h42
-rw-r--r--trust/p11-kit-trust.module6
-rw-r--r--trust/parser.c1103
-rw-r--r--trust/parser.h108
-rw-r--r--trust/session.c206
-rw-r--r--trust/session.h78
-rw-r--r--trust/tests/Makefile.am44
-rw-r--r--trust/tests/anchors/cacert3.derbin0 -> 1885 bytes
-rw-r--r--trust/tests/anchors/testing-ca.derbin0 -> 970 bytes
-rw-r--r--trust/tests/certificates/cacert-ca.derbin0 -> 1857 bytes
-rw-r--r--trust/tests/certificates/self-signed-with-eku.derbin0 -> 480 bytes
-rw-r--r--trust/tests/certificates/self-signed-with-ku.derbin0 -> 501 bytes
-rw-r--r--trust/tests/files/cacert-ca.derbin0 -> 1857 bytes
-rw-r--r--trust/tests/files/cacert3.derbin0 -> 1885 bytes
-rw-r--r--trust/tests/files/self-server.derbin0 -> 396 bytes
-rw-r--r--trust/tests/files/testing-server.derbin0 -> 554 bytes
-rw-r--r--trust/tests/files/unrecognized-file.txt1
-rw-r--r--trust/tests/test-data.c128
-rw-r--r--trust/tests/test-data.h220
-rw-r--r--trust/tests/test-module.c331
-rw-r--r--trust/tests/test-parser.c315
-rw-r--r--trust/tests/test-session.c160
-rw-r--r--trust/tests/test-token.c106
-rw-r--r--trust/token.c256
-rw-r--r--trust/token.h51
27 files changed, 4724 insertions, 0 deletions
diff --git a/trust/Makefile.am b/trust/Makefile.am
new file mode 100644
index 0000000..413bb51
--- /dev/null
+++ b/trust/Makefile.am
@@ -0,0 +1,52 @@
+NULL =
+
+SUBDIRS = . tests
+
+COMMON = $(top_srcdir)/common
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/common \
+ $(NULL)
+
+MODULE_SRCS = \
+ parser.c parser.h \
+ module.c module.h \
+ session.c session.h \
+ token.c token.h \
+ $(NULL)
+
+configdir = $(p11_package_config_modules)
+config_DATA = p11-kit-trust.module
+
+moduledir = $(p11_module_path)
+module_LTLIBRARIES = \
+ p11-kit-trust.la
+
+p11_kit_trust_la_CFLAGS = \
+ $(LIBTASN1_CFLAGS)
+
+p11_kit_trust_la_LIBADD = \
+ $(top_builddir)/common/libp11-data.la \
+ $(top_builddir)/common/libp11-library.la \
+ $(top_builddir)/common/libp11-compat.la \
+ $(LIBTASN1_LIBS)
+
+p11_kit_trust_la_LDFLAGS = \
+ -no-undefined -module -avoid-version \
+ -version-info $(P11KIT_LT_RELEASE) \
+ -export-symbols-regex 'C_GetFunctionList' \
+ $(NULL)
+
+p11_kit_trust_la_SOURCES = $(MODULE_SRCS)
+
+noinst_LTLIBRARIES = \
+ libtrust-testable.la
+
+libtrust_testable_la_LDFLAGS = \
+ -no-undefined
+
+libtrust_testable_la_SOURCES = $(MODULE_SRCS)
+
+EXTRA_DIST = \
+ p11-kit-trust.module
diff --git a/trust/module.c b/trust/module.c
new file mode 100644
index 0000000..ab28095
--- /dev/null
+++ b/trust/module.c
@@ -0,0 +1,1517 @@
+/*
+ * 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 "attrs.h"
+#define P11_DEBUG_FLAG P11_DEBUG_TRUST
+#include "debug.h"
+#include "dict.h"
+#include "library.h"
+#include "module.h"
+#include "pkcs11.h"
+#include "session.h"
+#include "token.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MANUFACTURER_ID "PKCS#11 Kit "
+#define LIBRARY_DESCRIPTION "PKCS#11 Kit Trust Module "
+#define SLOT_DESCRIPTION "System Certificates, Trust Anchors, and Black Lists "
+#define TOKEN_LABEL "System Trust Anchors and Policy "
+#define TOKEN_MODEL "PKCS#11 Kit "
+#define TOKEN_SERIAL_NUMBER "1 "
+
+/* Arbitrary non-zero and non-one choice */
+#define SYSTEM_SLOT_ID 18UL
+
+static struct _Shared {
+ p11_dict *sessions;
+ p11_token *token;
+ char *anchor_paths;
+ char *certificate_paths;
+} gl = { NULL, NULL };
+
+/* Used during FindObjects */
+typedef struct _FindObjects {
+ CK_ATTRIBUTE *match;
+ CK_OBJECT_HANDLE *snapshot;
+ CK_ULONG iterator;
+} FindObjects;
+
+static CK_FUNCTION_LIST sys_function_list;
+
+static void
+find_objects_free (void *data)
+{
+ FindObjects *find = data;
+ p11_attrs_free (find->match);
+ free (find->snapshot);
+ free (find);
+}
+
+static CK_RV
+lookup_session (CK_SESSION_HANDLE handle,
+ p11_session **session)
+{
+ p11_session *sess;
+
+ if (!gl.sessions)
+ return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ sess = p11_dict_get (gl.sessions, &handle);
+ if (!sess)
+ return CKR_SESSION_HANDLE_INVALID;
+
+ if (sess && session)
+ *session = sess;
+ return CKR_OK;
+}
+
+static void
+parse_argument (char *arg)
+{
+ char *value;
+
+ value = arg + strcspn (arg, ":=");
+ if (!*value)
+ value = NULL;
+ else
+ *(value++) = 0;
+
+ if (strcmp (arg, "anchors") == 0) {
+ free (gl.anchor_paths);
+ gl.anchor_paths = value ? strdup (value) : NULL;
+
+ } else if (strcmp (arg, "certificates") == 0) {
+ free (gl.certificate_paths);
+ gl.certificate_paths = value ? strdup (value) : NULL;
+
+ } else {
+ p11_message ("unrecognized module argument: %s", arg);
+ }
+}
+
+static void
+parse_arguments (const char *string)
+{
+ char quote = '\0';
+ char *src, *dup, *at, *arg;
+
+ if (!string)
+ return;
+
+ src = dup = strdup (string);
+ if (!dup) {
+ p11_message ("couldn't allocate memory for argument string");
+ return;
+ }
+
+ arg = at = src;
+ for (src = dup; *src; src++) {
+
+ /* Matching quote */
+ if (quote == *src) {
+ quote = '\0';
+
+ /* Inside of quotes */
+ } else if (quote != '\0') {
+ if (*src == '\\') {
+ *at++ = *src++;
+ if (!*src) {
+ p11_message ("couldn't parse argument string: %s", string);
+ goto done;
+ }
+ if (*src != quote)
+ *at++ = '\\';
+ }
+ *at++ = *src;
+
+ /* Space, not inside of quotes */
+ } else if (isspace(*src)) {
+ *at = 0;
+ parse_argument (arg);
+ arg = at;
+
+ /* Other character outside of quotes */
+ } else {
+ switch (*src) {
+ case '\'':
+ case '"':
+ quote = *src;
+ break;
+ case '\\':
+ *at++ = *src++;
+ if (!*src) {
+ p11_message ("couldn't parse argument string: %s", string);
+ goto done;
+ }
+ /* fall through */
+ default:
+ *at++ = *src;
+ break;
+ }
+ }
+ }
+
+
+ if (at != arg) {
+ *at = 0;
+ parse_argument (arg);
+ }
+
+done:
+ free (dup);
+}
+
+static CK_RV
+sys_C_Finalize (CK_VOID_PTR reserved)
+{
+ CK_RV rv = CKR_OK;
+
+ p11_debug ("in");
+
+ /* WARNING: This function must be reentrant */
+
+ if (reserved) {
+ rv = CKR_ARGUMENTS_BAD;
+
+ } else {
+ p11_lock ();
+
+ if (!gl.sessions) {
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ } else {
+ free (gl.certificate_paths);
+ free (gl.anchor_paths);
+ gl.certificate_paths = gl.anchor_paths = NULL;
+
+ p11_dict_free (gl.sessions);
+ gl.sessions = NULL;
+
+ p11_token_free (gl.token);
+ gl.token = NULL;
+
+ rv = CKR_OK;
+ }
+
+ p11_unlock ();
+ }
+
+ p11_debug ("out: 0x%lx", rv);
+ return rv;
+}
+
+static CK_RV
+sys_C_Initialize (CK_VOID_PTR init_args)
+{
+ CK_C_INITIALIZE_ARGS *args = NULL;
+ int supplied_ok;
+ CK_RV rv;
+
+ p11_library_init_once ();
+
+ /* WARNING: This function must be reentrant */
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = CKR_OK;
+
+ /* pReserved must be NULL */
+ args = init_args;
+
+ /* ALL supplied function pointers need to have the value either NULL or non-NULL. */
+ supplied_ok = (args->CreateMutex == NULL && args->DestroyMutex == NULL &&
+ args->LockMutex == NULL && args->UnlockMutex == NULL) ||
+ (args->CreateMutex != NULL && args->DestroyMutex != NULL &&
+ args->LockMutex != NULL && args->UnlockMutex != NULL);
+ if (!supplied_ok) {
+ p11_message ("invalid set of mutex calls supplied");
+ rv = CKR_ARGUMENTS_BAD;
+ }
+
+ /*
+ * When the CKF_OS_LOCKING_OK flag isn't set return an error.
+ * We must be able to use our pthread functionality.
+ */
+ if (!(args->flags & CKF_OS_LOCKING_OK)) {
+ p11_message ("can't do without os locking");
+ rv = CKR_CANT_LOCK;
+ }
+
+ /*
+ * We support setting the socket path and other arguments from from the
+ * pReserved pointer, similar to how NSS PKCS#11 components are initialized.
+ */
+ if (rv == CKR_OK) {
+ if (args->pReserved)
+ parse_arguments ((const char*)args->pReserved);
+
+ gl.sessions = p11_dict_new (p11_dict_ulongptr_hash,
+ p11_dict_ulongptr_equal,
+ NULL, p11_session_free);
+
+ gl.token = p11_token_new (gl.anchor_paths ? gl.anchor_paths : SYSTEM_ANCHORS,
+ gl.certificate_paths ? gl.certificate_paths : SYSTEM_CERTIFICATES);
+
+ if (gl.sessions == NULL || gl.token == NULL) {
+ warn_if_reached ();
+ rv = CKR_GENERAL_ERROR;
+ }
+ }
+
+ p11_unlock ();
+
+ if (rv != CKR_OK)
+ sys_C_Finalize (NULL);
+
+ p11_debug ("out: 0x%lx", rv);
+ return rv;
+}
+
+static CK_RV
+sys_C_GetInfo (CK_INFO_PTR info)
+{
+ CK_RV rv = CKR_OK;
+
+ p11_library_init_once ();
+
+ p11_debug ("in");
+
+ return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_lock ();
+
+ if (!gl.sessions)
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ p11_unlock ();
+
+ if (rv == CKR_OK) {
+ memset (info, 0, sizeof (*info));
+ info->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
+ info->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
+ info->libraryVersion.major = PACKAGE_MAJOR;
+ info->libraryVersion.minor = PACKAGE_MINOR;
+ info->flags = 0;
+ strncpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32);
+ strncpy ((char*)info->libraryDescription, LIBRARY_DESCRIPTION, 32);
+ }
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list)
+{
+ /* Can be called before C_Initialize */
+ return_val_if_fail (list != NULL, CKR_ARGUMENTS_BAD);
+
+ *list = &sys_function_list;
+ return CKR_OK;
+}
+
+static CK_RV
+sys_C_GetSlotList (CK_BBOOL token_present,
+ CK_SLOT_ID_PTR slot_list,
+ CK_ULONG_PTR count)
+{
+ CK_RV rv = CKR_OK;
+
+ return_val_if_fail (count != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ if (!gl.sessions)
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ p11_unlock ();
+
+ if (rv != CKR_OK) {
+ /* already failed */
+
+ } else if (!slot_list) {
+ *count = 1;
+ rv = CKR_OK;
+
+ } else if (*count < 1) {
+ *count = 1;
+ rv = CKR_BUFFER_TOO_SMALL;
+
+ } else {
+ slot_list[0] = SYSTEM_SLOT_ID;
+ *count = 1;
+ rv = CKR_OK;
+ }
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_GetSlotInfo (CK_SLOT_ID id,
+ CK_SLOT_INFO_PTR info)
+{
+ CK_RV rv = CKR_OK;
+
+ return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID);
+ return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ if (!gl.sessions)
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ p11_unlock ();
+
+ if (rv == CKR_OK) {
+ memset (info, 0, sizeof (*info));
+ info->firmwareVersion.major = 0;
+ info->firmwareVersion.minor = 0;
+ info->hardwareVersion.major = 0;
+ info->hardwareVersion.minor = 0;
+ info->flags = CKF_TOKEN_PRESENT;
+ strncpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32);
+ strncpy ((char*)info->slotDescription, SLOT_DESCRIPTION, 64);
+ }
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_GetTokenInfo (CK_SLOT_ID id,
+ CK_TOKEN_INFO_PTR info)
+{
+ CK_RV rv = CKR_OK;
+
+ return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID);
+ return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ if (!gl.sessions)
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ p11_unlock ();
+
+ if (rv == CKR_OK) {
+ memset (info, 0, sizeof (*info));
+ info->firmwareVersion.major = 0;
+ info->firmwareVersion.minor = 0;
+ info->hardwareVersion.major = 0;
+ info->hardwareVersion.minor = 0;
+ info->flags = CKF_TOKEN_INITIALIZED | CKF_WRITE_PROTECTED;
+ strncpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32);
+ strncpy ((char*)info->label, TOKEN_LABEL, 32);
+ strncpy ((char*)info->model, TOKEN_MODEL, 16);
+ strncpy ((char*)info->serialNumber, TOKEN_SERIAL_NUMBER, 16);
+ info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
+ info->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
+ info->ulMaxRwSessionCount = 0;
+ info->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;
+ info->ulMaxPinLen = 0;
+ info->ulMinPinLen = 0;
+ info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
+ info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
+ }
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_GetMechanismList (CK_SLOT_ID id,
+ CK_MECHANISM_TYPE_PTR mechanism_list,
+ CK_ULONG_PTR count)
+{
+ CK_RV rv = CKR_OK;
+
+ return_val_if_fail (count != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ *count = 0;
+
+ p11_debug ("out: 0x%lx", rv);
+ return rv;
+}
+
+static CK_RV
+sys_C_GetMechanismInfo (CK_SLOT_ID id,
+ CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR info)
+{
+ return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID);
+ return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD);
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_InitToken (CK_SLOT_ID id,
+ CK_UTF8CHAR_PTR pin,
+ CK_ULONG pin_len,
+ CK_UTF8CHAR_PTR label)
+{
+ return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID);
+ return_val_if_reached (CKR_TOKEN_WRITE_PROTECTED);
+}
+
+static CK_RV
+sys_C_WaitForSlotEvent (CK_FLAGS flags,
+ CK_SLOT_ID_PTR slot,
+ CK_VOID_PTR reserved)
+{
+ p11_debug ("not supported");
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+static CK_RV
+sys_C_OpenSession (CK_SLOT_ID id,
+ CK_FLAGS flags,
+ CK_VOID_PTR user_data,
+ CK_NOTIFY callback,
+ CK_SESSION_HANDLE_PTR handle)
+{
+ p11_session *session;
+ CK_RV rv = CKR_OK;
+
+ return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID);
+ return_val_if_fail (handle != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ if (!gl.sessions) {
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ } else if (!(flags & CKF_SERIAL_SESSION)) {
+ rv = CKR_SESSION_PARALLEL_NOT_SUPPORTED;
+
+ } else if (flags & CKF_RW_SESSION) {
+ rv = CKR_TOKEN_WRITE_PROTECTED;
+
+ } else {
+ session = p11_session_new (gl.token);
+ if (p11_dict_set (gl.sessions, &session->handle, session)) {
+ rv = CKR_OK;
+ *handle = session->handle;
+ p11_debug ("session: %lu", *handle);
+ } else {
+ warn_if_reached ();
+ rv = CKR_GENERAL_ERROR;
+ }
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_CloseSession (CK_SESSION_HANDLE handle)
+{
+ CK_RV rv = CKR_OK;
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ if (!gl.sessions) {
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ } else if (p11_dict_remove (gl.sessions, &handle)) {
+ rv = CKR_OK;
+
+ } else {
+ rv = CKR_SESSION_HANDLE_INVALID;
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_CloseAllSessions (CK_SLOT_ID id)
+{
+ CK_RV rv = CKR_OK;
+
+ return_val_if_fail (id == SYSTEM_SLOT_ID, CKR_SLOT_ID_INVALID);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ if (!gl.sessions) {
+ rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+ } else {
+ p11_dict_clear (gl.sessions);
+ rv = CKR_OK;
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_GetFunctionStatus (CK_SESSION_HANDLE handle)
+{
+ return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
+}
+
+static CK_RV
+sys_C_CancelFunction (CK_SESSION_HANDLE handle)
+{
+ return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
+}
+
+static CK_RV
+sys_C_GetSessionInfo (CK_SESSION_HANDLE handle,
+ CK_SESSION_INFO_PTR info)
+{
+ CK_RV rv;
+
+ return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, NULL);
+
+ p11_unlock ();
+
+ if (rv == CKR_OK) {
+ info->flags = CKF_SERIAL_SESSION;
+ info->slotID = SYSTEM_SLOT_ID;
+ info->state = CKS_RO_PUBLIC_SESSION;
+ info->ulDeviceError = 0;
+ }
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_InitPIN (CK_SESSION_HANDLE handle,
+ CK_UTF8CHAR_PTR pin,
+ CK_ULONG pin_len)
+{
+ return_val_if_reached (CKR_TOKEN_WRITE_PROTECTED);
+}
+
+static CK_RV
+sys_C_SetPIN (CK_SESSION_HANDLE handle,
+ CK_UTF8CHAR_PTR old_pin,
+ CK_ULONG old_pin_len,
+ CK_UTF8CHAR_PTR new_pin,
+ CK_ULONG new_pin_len)
+{
+ return_val_if_reached (CKR_TOKEN_WRITE_PROTECTED);
+}
+
+static CK_RV
+sys_C_GetOperationState (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR operation_state,
+ CK_ULONG_PTR operation_state_len)
+{
+ p11_debug ("not supported");
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+static CK_RV
+sys_C_SetOperationState (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR operation_state,
+ CK_ULONG operation_state_len,
+ CK_OBJECT_HANDLE encryption_key,
+ CK_OBJECT_HANDLE authentication_key)
+{
+ p11_debug ("not supported");
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+static CK_RV
+sys_C_Login (CK_SESSION_HANDLE handle,
+ CK_USER_TYPE user_type,
+ CK_UTF8CHAR_PTR pin,
+ CK_ULONG pin_len)
+{
+ return_val_if_reached (CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+sys_C_Logout (CK_SESSION_HANDLE handle)
+{
+ return_val_if_reached (CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static CK_RV
+sys_C_CreateObject (CK_SESSION_HANDLE handle,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR new_object)
+{
+ CK_ATTRIBUTE *attrs;
+ p11_session *session;
+ CK_BBOOL token;
+ CK_RV rv;
+
+ return_val_if_fail (new_object != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, &session);
+ if (rv == CKR_OK) {
+ if (p11_attrs_findn_bool (template, count, CKA_TOKEN, &token) && token)
+ rv = CKR_TOKEN_WRITE_PROTECTED;
+ }
+
+ if (rv == CKR_OK) {
+ attrs = p11_attrs_buildn (NULL, template, count);
+ rv = p11_session_add_object (session, attrs, new_object);
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_CopyObject (CK_SESSION_HANDLE handle,
+ CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR new_object)
+{
+ CK_BBOOL vfalse = CK_FALSE;
+ CK_ATTRIBUTE token = { CKA_TOKEN, &vfalse, sizeof (vfalse) };
+ p11_session *session;
+ CK_ATTRIBUTE *original;
+ CK_ATTRIBUTE *attrs;
+ CK_BBOOL val;
+ CK_RV rv;
+
+ return_val_if_fail (new_object != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, &session);
+ if (rv == CKR_OK) {
+ original = p11_session_get_object (session, object, NULL);
+ if (original == NULL)
+ rv = CKR_OBJECT_HANDLE_INVALID;
+ }
+
+ if (rv == CKR_OK) {
+ if (p11_attrs_findn_bool (template, count, CKA_TOKEN, &val) && val)
+ rv = CKR_TOKEN_WRITE_PROTECTED;
+ }
+
+ if (rv == CKR_OK) {
+ attrs = p11_attrs_dup (original);
+ attrs = p11_attrs_buildn (attrs, template, count);
+ attrs = p11_attrs_build (attrs, &token, NULL);
+ rv = p11_session_add_object (session, attrs, new_object);
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_DestroyObject (CK_SESSION_HANDLE handle,
+ CK_OBJECT_HANDLE object)
+{
+ p11_session *session;
+ CK_RV rv;
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, &session);
+ if (rv == CKR_OK)
+ rv = p11_session_del_object (session, object);
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_GetObjectSize (CK_SESSION_HANDLE handle,
+ CK_OBJECT_HANDLE object,
+ CK_ULONG_PTR size)
+{
+ p11_session *session;
+ CK_RV rv;
+
+ return_val_if_fail (size != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, &session);
+ if (rv == CKR_OK) {
+ if (p11_session_get_object (session, object, NULL)) {
+ *size = CK_UNAVAILABLE_INFORMATION;
+ rv = CKR_OK;
+ } else {
+ rv = CKR_OBJECT_HANDLE_INVALID;
+ }
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_GetAttributeValue (CK_SESSION_HANDLE handle,
+ CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count)
+{
+ CK_ATTRIBUTE *attrs;
+ CK_ATTRIBUTE *result;
+ CK_ATTRIBUTE *attr;
+ p11_session *session;
+ CK_ULONG i;
+ CK_RV rv;
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, &session);
+ if (rv == CKR_OK) {
+ attrs = p11_session_get_object (session, object, NULL);
+ if (attrs == NULL)
+ rv = CKR_OBJECT_HANDLE_INVALID;
+ }
+
+ if (rv == CKR_OK) {
+ for (i = 0; i < count; i++) {
+ result = template + i;
+ attr = p11_attrs_find (attrs, result->type);
+ if (!attr) {
+ result->ulValueLen = (CK_ULONG)-1;
+ rv = CKR_ATTRIBUTE_TYPE_INVALID;
+ continue;
+ }
+
+ if (!result->pValue) {
+ result->ulValueLen = attr->ulValueLen;
+ continue;
+ }
+
+ if (result->ulValueLen >= attr->ulValueLen) {
+ memcpy (result->pValue, attr->pValue, attr->ulValueLen);
+ result->ulValueLen = attr->ulValueLen;
+ continue;
+ }
+
+ result->ulValueLen = (CK_ULONG)-1;
+ rv = CKR_BUFFER_TOO_SMALL;
+ }
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_SetAttributeValue (CK_SESSION_HANDLE handle,
+ CK_OBJECT_HANDLE object,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count)
+{
+ p11_session *session;
+ CK_RV rv;
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, &session);
+ if (rv == CKR_OK)
+ rv = p11_session_set_object (session, object, template, count);
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_FindObjectsInit (CK_SESSION_HANDLE handle,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count)
+{
+ CK_OBJECT_HANDLE *handle_ptr;
+ CK_BBOOL want_token_objects;
+ CK_BBOOL want_session_objects;
+ CK_BBOOL token;
+ p11_dict *objects;
+ FindObjects *find;
+ p11_session *session;
+ p11_dictiter iter;
+ CK_ULONG i;
+ CK_RV rv;
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ /* Are we searching for token objects? */
+ if (p11_attrs_findn_bool (template, count, CKA_TOKEN, &token)) {
+ want_token_objects = token;
+ want_session_objects = !token;
+ } else {
+ want_token_objects = CK_TRUE;
+ want_session_objects = CK_TRUE;
+ }
+
+ rv = lookup_session (handle, &session);
+
+ /* Refresh from disk if this session hasn't yet */
+ if (rv == CKR_OK && want_token_objects && !session->loaded) {
+ session->loaded = CK_TRUE;
+ p11_token_load (gl.token);
+ }
+
+ if (rv == CKR_OK) {
+ objects = p11_token_objects (gl.token);
+
+ find = calloc (1, sizeof (FindObjects));
+ warn_if_fail (find != NULL);
+
+ /* Make a copy of what we're matching */
+ if (find) {
+ find->match = p11_attrs_buildn (NULL, template, count);
+ warn_if_fail (find->match != NULL);
+
+ /* Build a session snapshot of all objects */
+ find->iterator = 0;
+ count = p11_dict_size (objects) + p11_dict_size (session->objects) + 1;
+ find->snapshot = calloc (count, sizeof (CK_OBJECT_HANDLE));
+ warn_if_fail (find->snapshot != NULL);
+ }
+
+ if (find && find->snapshot) {
+ i = 0;
+
+ if (want_token_objects) {
+ p11_dict_iterate (objects, &iter);
+ for ( ; p11_dict_next (&iter, (void *)&handle_ptr, NULL); i++) {
+ assert (i < count);
+ find->snapshot[i] = *handle_ptr;
+ }
+ }
+
+ if (want_session_objects) {
+ p11_dict_iterate (session->objects, &iter);
+ for ( ; p11_dict_next (&iter, (void *)&handle_ptr, NULL); i++) {
+ assert (i < count);
+ find->snapshot[i] = *handle_ptr;
+ }
+ }
+
+ assert (i < count);
+ assert (find->snapshot[i] == 0UL);
+ }
+
+ if (!find || !find->snapshot || !find->match)
+ rv = CKR_HOST_MEMORY;
+ else
+ p11_session_set_operation (session, find_objects_free, find);
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_FindObjects (CK_SESSION_HANDLE handle,
+ CK_OBJECT_HANDLE_PTR objects,
+ CK_ULONG max_count,
+ CK_ULONG_PTR count)
+{
+ CK_OBJECT_HANDLE object;
+ CK_ATTRIBUTE *attrs;
+ FindObjects *find = NULL;
+ p11_session *session;
+ CK_ULONG matched;
+ CK_RV rv;
+
+ return_val_if_fail (count != NULL, CKR_ARGUMENTS_BAD);
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, &session);
+ if (rv == CKR_OK) {
+ if (session->cleanup != find_objects_free)
+ rv = CKR_OPERATION_NOT_INITIALIZED;
+ find = session->operation;
+ }
+
+ if (rv == CKR_OK) {
+ matched = 0;
+ while (matched < max_count) {
+ object = find->snapshot[find->iterator];
+ if (!object)
+ break;
+
+ find->iterator++;
+
+ attrs = p11_session_get_object (session, object, NULL);
+ if (attrs == NULL)
+ continue;
+
+ if (p11_attrs_match (attrs, find->match)) {
+ objects[matched] = object;
+ matched++;
+ }
+ }
+
+ *count = matched;
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_FindObjectsFinal (CK_SESSION_HANDLE handle)
+{
+ p11_session *session;
+ CK_RV rv;
+
+ p11_debug ("in");
+
+ p11_lock ();
+
+ rv = lookup_session (handle, &session);
+ if (rv == CKR_OK) {
+ if (session->cleanup != find_objects_free)
+ rv = CKR_OPERATION_NOT_INITIALIZED;
+ else
+ p11_session_set_operation (session, NULL, NULL);
+ }
+
+ p11_unlock ();
+
+ p11_debug ("out: 0x%lx", rv);
+
+ return rv;
+}
+
+static CK_RV
+sys_C_EncryptInit (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_Encrypt (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR encrypted_data,
+ CK_ULONG_PTR encrypted_data_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_EncryptUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len,
+ CK_BYTE_PTR encrypted_part,
+ CK_ULONG_PTR encrypted_part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_EncryptFinal (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR last_part,
+ CK_ULONG_PTR last_part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DecryptInit (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_Decrypt (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR enc_data,
+ CK_ULONG enc_data_len,
+ CK_BYTE_PTR data,
+ CK_ULONG_PTR data_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DecryptUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG enc_part_len,
+ CK_BYTE_PTR part,
+ CK_ULONG_PTR part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DecryptFinal (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR last_part,
+ CK_ULONG_PTR last_part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DigestInit (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_Digest (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR digest,
+ CK_ULONG_PTR digest_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DigestUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DigestKey (CK_SESSION_HANDLE handle,
+ CK_OBJECT_HANDLE key)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DigestFinal (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR digest,
+ CK_ULONG_PTR digest_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_SignInit (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_Sign (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR signature,
+ CK_ULONG_PTR signature_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_SignUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_SignFinal (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR signature,
+ CK_ULONG_PTR signature_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_SignRecoverInit (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_SignRecover (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR signature,
+ CK_ULONG_PTR signature_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_VerifyInit (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_Verify (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR data,
+ CK_ULONG data_len,
+ CK_BYTE_PTR signature,
+ CK_ULONG signature_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_VerifyUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_VerifyFinal (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR signature,
+ CK_ULONG signature_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_VerifyRecoverInit (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_VerifyRecover (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR signature,
+ CK_ULONG signature_len,
+ CK_BYTE_PTR data,
+ CK_ULONG_PTR data_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DigestEncryptUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG_PTR enc_part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DecryptDigestUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG enc_part_len,
+ CK_BYTE_PTR part,
+ CK_ULONG_PTR part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_SignEncryptUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR part,
+ CK_ULONG part_len,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG_PTR enc_part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_DecryptVerifyUpdate (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR enc_part,
+ CK_ULONG enc_part_len,
+ CK_BYTE_PTR part,
+ CK_ULONG_PTR part_len)
+{
+ return_val_if_reached (CKR_OPERATION_NOT_INITIALIZED);
+}
+
+static CK_RV
+sys_C_GenerateKey (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_GenerateKeyPair (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_ATTRIBUTE_PTR pub_template,
+ CK_ULONG pub_count,
+ CK_ATTRIBUTE_PTR priv_template,
+ CK_ULONG priv_count,
+ CK_OBJECT_HANDLE_PTR pub_key,
+ CK_OBJECT_HANDLE_PTR priv_key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_WrapKey (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE wrapping_key,
+ CK_OBJECT_HANDLE key,
+ CK_BYTE_PTR wrapped_key,
+ CK_ULONG_PTR wrapped_key_len)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_UnwrapKey (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE unwrapping_key,
+ CK_BYTE_PTR wrapped_key,
+ CK_ULONG wrapped_key_len,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_DeriveKey (CK_SESSION_HANDLE handle,
+ CK_MECHANISM_PTR mechanism,
+ CK_OBJECT_HANDLE base_key,
+ CK_ATTRIBUTE_PTR template,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE_PTR key)
+{
+ return_val_if_reached (CKR_MECHANISM_INVALID);
+}
+
+static CK_RV
+sys_C_SeedRandom (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR seed,
+ CK_ULONG seed_len)
+{
+ return_val_if_reached (CKR_RANDOM_NO_RNG);
+}
+
+static CK_RV
+sys_C_GenerateRandom (CK_SESSION_HANDLE handle,
+ CK_BYTE_PTR random_data,
+ CK_ULONG random_len)
+{
+ return_val_if_reached (CKR_RANDOM_NO_RNG);
+}
+
+/* --------------------------------------------------------------------
+ * MODULE ENTRY POINT
+ */
+
+static CK_FUNCTION_LIST sys_function_list = {
+ { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR }, /* version */
+ sys_C_Initialize,
+ sys_C_Finalize,
+ sys_C_GetInfo,
+ sys_C_GetFunctionList,
+ sys_C_GetSlotList,
+ sys_C_GetSlotInfo,
+ sys_C_GetTokenInfo,
+ sys_C_GetMechanismList,
+ sys_C_GetMechanismInfo,
+ sys_C_InitToken,
+ sys_C_InitPIN,
+ sys_C_SetPIN,
+ sys_C_OpenSession,
+ sys_C_CloseSession,
+ sys_C_CloseAllSessions,
+ sys_C_GetSessionInfo,
+ sys_C_GetOperationState,
+ sys_C_SetOperationState,
+ sys_C_Login,
+ sys_C_Logout,
+ sys_C_CreateObject,
+ sys_C_CopyObject,
+ sys_C_DestroyObject,
+ sys_C_GetObjectSize,
+ sys_C_GetAttributeValue,
+ sys_C_SetAttributeValue,
+ sys_C_FindObjectsInit,
+ sys_C_FindObjects,
+ sys_C_FindObjectsFinal,
+ sys_C_EncryptInit,
+ sys_C_Encrypt,
+ sys_C_EncryptUpdate,
+ sys_C_EncryptFinal,
+ sys_C_DecryptInit,
+ sys_C_Decrypt,
+ sys_C_DecryptUpdate,
+ sys_C_DecryptFinal,
+ sys_C_DigestInit,
+ sys_C_Digest,
+ sys_C_DigestUpdate,
+ sys_C_DigestKey,
+ sys_C_DigestFinal,
+ sys_C_SignInit,
+ sys_C_Sign,
+ sys_C_SignUpdate,
+ sys_C_SignFinal,
+ sys_C_SignRecoverInit,
+ sys_C_SignRecover,
+ sys_C_VerifyInit,
+ sys_C_Verify,
+ sys_C_VerifyUpdate,
+ sys_C_VerifyFinal,
+ sys_C_VerifyRecoverInit,
+ sys_C_VerifyRecover,
+ sys_C_DigestEncryptUpdate,
+ sys_C_DecryptDigestUpdate,
+ sys_C_SignEncryptUpdate,
+ sys_C_DecryptVerifyUpdate,
+ sys_C_GenerateKey,
+ sys_C_GenerateKeyPair,
+ sys_C_WrapKey,
+ sys_C_UnwrapKey,
+ sys_C_DeriveKey,
+ sys_C_SeedRandom,
+ sys_C_GenerateRandom,
+ sys_C_GetFunctionStatus,
+ sys_C_CancelFunction,
+ sys_C_WaitForSlotEvent
+};
+
+#ifdef OS_WIN32
+__declspec(dllexport)
+#endif
+
+CK_RV
+C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list)
+{
+ return sys_C_GetFunctionList (list);
+}
+
+CK_ULONG
+p11_module_next_id (void)
+{
+ static CK_ULONG unique = 0x10;
+ return (unique)++;
+}
diff --git a/trust/module.h b/trust/module.h
new file mode 100644
index 0000000..13b928a
--- /dev/null
+++ b/trust/module.h
@@ -0,0 +1,42 @@
+/*
+ * 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 "pkcs11.h"
+
+#ifndef P11_MODULE_H_
+#define P11_MODULE_H_
+
+CK_ULONG p11_module_next_id (void);
+
+#endif /* P11_MODULE_H_ */
diff --git a/trust/p11-kit-trust.module b/trust/p11-kit-trust.module
new file mode 100644
index 0000000..ad0f254
--- /dev/null
+++ b/trust/p11-kit-trust.module
@@ -0,0 +1,6 @@
+
+# This is a module config for the 'included' p11-kit trust module
+module: p11-kit-trust.so
+
+# The order in which this is loaded in the trust policy
+trust-policy: 1
diff --git a/trust/parser.c b/trust/parser.c
new file mode 100644
index 0000000..ef72474
--- /dev/null
+++ b/trust/parser.c
@@ -0,0 +1,1103 @@
+/*
+ * 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 "attrs.h"
+#include "checksum.h"
+#define P11_DEBUG_FLAG P11_DEBUG_TRUST
+#include "debug.h"
+#include "dict.h"
+#include "library.h"
+#include "module.h"
+#include "parser.h"
+#include "pkcs11x.h"
+
+#include <libtasn1.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pkix.asn.h"
+
+struct _p11_parser {
+ node_asn *pkix_definitions;
+ p11_parser_sink sink;
+ void *sink_data;
+ const char *probable_label;
+ int flags;
+};
+
+typedef int (* parser_func) (p11_parser *parser,
+ const unsigned char *data,
+ size_t length);
+
+static node_asn *
+decode_asn1 (p11_parser *parser,
+ const char *struct_name,
+ const unsigned char *data,
+ size_t length,
+ char *message)
+{
+ char msg[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+ node_asn *definitions;
+ node_asn *el = NULL;
+ int ret;
+
+ if (message == NULL)
+ message = msg;
+
+ if (strncmp (struct_name, "PKIX1.", 6) == 0) {
+ definitions = parser->pkix_definitions;
+
+ } else {
+ p11_debug_precond ("unknown prefix for element: %s", struct_name);
+ return NULL;
+ }
+
+ ret = asn1_create_element (definitions, struct_name, &el);
+ if (ret != ASN1_SUCCESS) {
+ p11_debug_precond ("failed to create element %s at %s: %d",
+ struct_name, __func__, ret);
+ return NULL;
+ }
+
+ return_val_if_fail (ret == ASN1_SUCCESS, NULL);
+
+ /* asn1_der_decoding destroys the element if fails */
+ ret = asn1_der_decoding (&el, data, length, message);
+
+ if (ret != ASN1_SUCCESS) {
+ p11_debug ("couldn't parse %s: %s: %s",
+ struct_name, asn1_strerror (ret), message);
+ return NULL;
+ }
+
+ return el;
+}
+
+static void
+sink_object (p11_parser *parser,
+ CK_ATTRIBUTE *attrs)
+{
+ if (parser->sink)
+ (parser->sink) (attrs, parser->sink_data);
+ else
+ p11_attrs_free (attrs);
+}
+
+#define ID_LENGTH P11_CHECKSUM_SHA1_LENGTH
+
+static void
+id_generate (p11_parser *parser,
+ CK_BYTE *vid)
+{
+ CK_ULONG val = p11_module_next_id ();
+ p11_checksum_sha1 (vid, &val, sizeof (val), NULL);
+}
+
+static CK_ATTRIBUTE *
+build_object (p11_parser *parser,
+ CK_ATTRIBUTE *attrs,
+ CK_OBJECT_CLASS vclass,
+ CK_BYTE *vid,
+ const char *explicit_label)
+{
+ CK_BBOOL vtrue = CK_TRUE;
+ CK_BBOOL vfalse = CK_FALSE;
+ const char *vlabel;
+
+ CK_ATTRIBUTE klass = { CKA_CLASS, &vclass, sizeof (vclass) };
+ CK_ATTRIBUTE token = { CKA_TOKEN, &vtrue, sizeof (vtrue) };
+ CK_ATTRIBUTE private = { CKA_PRIVATE, &vfalse, sizeof (vfalse) };
+ CK_ATTRIBUTE modifiable = { CKA_MODIFIABLE, &vfalse, sizeof (vfalse) };
+ CK_ATTRIBUTE id = { CKA_ID, vid, ID_LENGTH };
+ CK_ATTRIBUTE label = { CKA_LABEL, };
+
+ vlabel = explicit_label ? (char *)explicit_label : parser->probable_label;
+ if (vlabel) {
+ label.pValue = (void *)vlabel;
+ label.ulValueLen = strlen (vlabel);
+ } else {
+ label.type = CKA_INVALID;
+ }
+
+ if (!vid)
+ id.type = CKA_INVALID;
+
+ return p11_attrs_build (attrs, &klass, &token, &private, &modifiable,
+ &id, &label, NULL);
+}
+
+static void
+calc_check_value (const unsigned char *data,
+ size_t length,
+ CK_BYTE *check_value)
+{
+ unsigned char checksum[P11_CHECKSUM_SHA1_LENGTH];
+ p11_checksum_sha1 (checksum, data, length, NULL);
+ memcpy (check_value, checksum, 3);
+}
+
+static int
+atoin (const char *p,
+ int digits)
+{
+ int ret = 0, base = 1;
+ while(--digits >= 0) {
+ if (p[digits] < '0' || p[digits] > '9')
+ return -1;
+ ret += (p[digits] - '0') * base;
+ base *= 10;
+ }
+ return ret;
+}
+
+static int
+two_to_four_digit_year (int year)
+{
+ time_t now;
+ struct tm tm;
+ int century, current;
+
+ return_val_if_fail (year >= 0 && year <= 99, -1);
+
+ /* Get the current year */
+ now = time (NULL);
+ return_val_if_fail (now >= 0, -1);
+ if (!gmtime_r (&now, &tm))
+ return_val_if_reached (-1);
+
+ current = (tm.tm_year % 100);
+ century = (tm.tm_year + 1900) - current;
+
+ /*
+ * Check if it's within 40 years before the
+ * current date.
+ */
+ if (current < 40) {
+ if (year < current)
+ return century + year;
+ if (year > 100 - (40 - current))
+ return (century - 100) + year;
+ } else {
+ if (year < current && year > (current - 40))
+ return century + year;
+ }
+
+ /*
+ * If it's after then adjust for overflows to
+ * the next century.
+ */
+ if (year < current)
+ return century + 100 + year;
+ else
+ return century + year;
+}
+
+static bool
+parse_utc_time (const char *time,
+ size_t n_time,
+ struct tm *when,
+ int *offset)
+{
+ const char *p, *e;
+ int year;
+
+ assert (when != NULL);
+ assert (time != NULL);
+ assert (offset != NULL);
+
+ /* YYMMDDhhmmss.ffff Z | +0000 */
+ if (n_time < 6 || n_time >= 28)
+ return false;
+
+ /* Reset everything to default legal values */
+ memset (when, 0, sizeof (*when));
+ *offset = 0;
+ when->tm_mday = 1;
+
+ /* Select the digits part of it */
+ p = time;
+ for (e = p; *e >= '0' && *e <= '9'; ++e);
+
+ if (p + 2 <= e) {
+ year = atoin (p, 2);
+ p += 2;
+
+ /*
+ * 40 years in the past is our century. 60 years
+ * in the future is the next century.
+ */
+ when->tm_year = two_to_four_digit_year (year) - 1900;
+ }
+ if (p + 2 <= e) {
+ when->tm_mon = atoin (p, 2) - 1;
+ p += 2;
+ }
+ if (p + 2 <= e) {
+ when->tm_mday = atoin (p, 2);
+ p += 2;
+ }
+ if (p + 2 <= e) {
+ when->tm_hour = atoin (p, 2);
+ p += 2;
+ }
+ if (p + 2 <= e) {
+ when->tm_min = atoin (p, 2);
+ p += 2;
+ }
+ if (p + 2 <= e) {
+ when->tm_sec = atoin (p, 2);
+ p += 2;
+ }
+
+ if (when->tm_year < 0 || when->tm_year > 9999 ||
+ when->tm_mon < 0 || when->tm_mon > 11 ||
+ when->tm_mday < 1 || when->tm_mday > 31 ||
+ when->tm_hour < 0 || when->tm_hour > 23 ||
+ when->tm_min < 0 || when->tm_min > 59 ||
+ when->tm_sec < 0 || when->tm_sec > 59)
+ return false;
+
+ /* Make sure all that got parsed */
+ if (p != e)
+ return false;
+
+ /* Now the remaining optional stuff */
+ e = time + n_time;
+
+ /* See if there's a fraction, and discard it if so */
+ if (p < e && *p == '.' && p + 5 <= e)
+ p += 5;
+
+ /* See if it's UTC */
+ if (p < e && *p == 'Z') {
+ p += 1;
+
+ /* See if it has a timezone */
+ } else if ((*p == '-' || *p == '+') && p + 3 <= e) {
+ int off, neg;
+
+ neg = *p == '-';
+ ++p;
+
+ off = atoin (p, 2) * 3600;
+ if (off < 0 || off > 86400)
+ return false;
+ p += 2;
+
+ if (p + 2 <= e) {
+ off += atoin (p, 2) * 60;
+ p += 2;
+ }
+
+ /* Use TZ offset */
+ if (neg)
+ *offset = 0 - off;
+ else
+ *offset = off;
+ }
+
+ /* Make sure everything got parsed */
+ if (p != e)
+ return false;
+
+ return true;
+}
+
+static bool
+parse_general_time (const char *time,
+ size_t n_time,
+ struct tm *when,
+ int *offset)
+{
+ const char *p, *e;
+
+ assert (time != NULL);
+ assert (when != NULL);
+ assert (offset != NULL);
+
+ /* YYYYMMDDhhmmss.ffff Z | +0000 */
+ if (n_time < 8 || n_time >= 30)
+ return false;
+
+ /* Reset everything to default legal values */
+ memset (when, 0, sizeof (*when));
+ *offset = 0;
+ when->tm_mday = 1;
+
+ /* Select the digits part of it */
+ p = time;
+ for (e = p; *e >= '0' && *e <= '9'; ++e);
+
+ if (p + 4 <= e) {
+ when->tm_year = atoin (p, 4) - 1900;
+ p += 4;
+ }
+ if (p + 2 <= e) {
+ when->tm_mon = atoin (p, 2) - 1;
+ p += 2;
+ }
+ if (p + 2 <= e) {
+ when->tm_mday = atoin (p, 2);
+ p += 2;
+ }
+ if (p + 2 <= e) {
+ when->tm_hour = atoin (p, 2);
+ p += 2;
+ }
+ if (p + 2 <= e) {
+ when->tm_min = atoin (p, 2);
+ p += 2;
+ }
+ if (p + 2 <= e) {
+ when->tm_sec = atoin (p, 2);
+ p += 2;
+ }
+
+ if (when->tm_year < 0 || when->tm_year > 9999 ||
+ when->tm_mon < 0 || when->tm_mon > 11 ||
+ when->tm_mday < 1 || when->tm_mday > 31 ||
+ when->tm_hour < 0 || when->tm_hour > 23 ||
+ when->tm_min < 0 || when->tm_min > 59 ||
+ when->tm_sec < 0 || when->tm_sec > 59)
+ return false;
+
+ /* Make sure all that got parsed */
+ if (p != e)
+ return false;
+
+ /* Now the remaining optional stuff */
+ e = time + n_time;
+
+ /* See if there's a fraction, and discard it if so */
+ if (p < e && *p == '.' && p + 5 <= e)
+ p += 5;
+
+ /* See if it's UTC */
+ if (p < e && *p == 'Z') {
+ p += 1;
+
+ /* See if it has a timezone */
+ } else if ((*p == '-' || *p == '+') && p + 3 <= e) {
+ int off, neg;
+
+ neg = *p == '-';
+ ++p;
+
+ off = atoin (p, 2) * 3600;
+ if (off < 0 || off > 86400)
+ return false;
+ p += 2;
+
+ if (p + 2 <= e) {
+ off += atoin (p, 2) * 60;
+ p += 2;
+ }
+
+ /* Use TZ offset */
+ if (neg)
+ *offset = 0 - off;
+ else
+ *offset = off;
+ }
+
+ /* Make sure everything got parsed */
+ if (p != e)
+ return false;
+
+ return true;
+}
+
+static bool
+calc_date (node_asn *cert,
+ const char *field,
+ CK_DATE *date)
+{
+ node_asn *choice;
+ struct tm when;
+ int tz_offset;
+ char buf[64];
+ time_t timet;
+ char *sub;
+ int len;
+ int ret;
+
+ choice = asn1_find_node (cert, field);
+ return_val_if_fail (choice != NULL, false);
+
+ len = sizeof (buf) - 1;
+ ret = asn1_read_value (cert, field, buf, &len);
+ return_val_if_fail (ret == ASN1_SUCCESS, false);
+
+ sub = strconcat (field, ".", buf, NULL);
+
+ if (strcmp (buf, "generalTime") == 0) {
+ len = sizeof (buf) - 1;
+ ret = asn1_read_value (cert, sub, buf, &len);
+ return_val_if_fail (ret == ASN1_SUCCESS, false);
+ if (!parse_general_time (buf, len, &when, &tz_offset))
+ return_val_if_reached (false);
+
+ } else if (strcmp (buf, "utcTime") == 0) {
+ len = sizeof (buf) - 1;
+ ret = asn1_read_value (cert, sub, buf, &len);
+ return_val_if_fail (ret == ASN1_SUCCESS, false);
+ if (!parse_utc_time (buf, len - 1, &when, &tz_offset))
+ return_val_if_reached (false);
+
+ } else {
+ return_val_if_reached (false);
+ }
+
+ free (sub);
+
+ /* In order to work with 32 bit time_t. */
+ if (sizeof (time_t) <= 4 && when.tm_year >= 2038) {
+ timet = (time_t)2145914603; /* 2037-12-31 23:23:23 */
+
+ /* Convert to seconds since epoch */
+ } else {
+ timet = timegm (&when);
+ return_val_if_fail (timet >= 0, false);
+ timet += tz_offset;
+ }
+
+ if (!gmtime_r (&timet, &when))
+ return_val_if_reached (false);
+
+ assert (sizeof (date->year) == 4);
+ snprintf ((char *)buf, 5, "%04d", 1900 + when.tm_year);
+ memcpy (date->year, buf, 4);
+
+ assert (sizeof (date->month) == 2);
+ snprintf ((char *)buf, 3, "%02d", when.tm_mon + 1);
+ memcpy (date->month, buf, 2);
+
+ assert (sizeof (date->day) == 2);
+ snprintf ((char *)buf, 3, "%02d", when.tm_mday);
+ memcpy (date->day, buf, 2);
+
+ return true;
+}
+
+static bool
+calc_trusted (p11_parser *parser,
+ node_asn *cert,
+ CK_BBOOL *vtrusted)
+{
+ assert (parser != NULL);
+ assert (vtrusted != NULL);
+
+ /*
+ * This calculates CKA_TRUSTED, which is a silly attribute, don't
+ * read too much into this. The real trust mechinisms are elsewhere.
+ */
+
+ *vtrusted = CK_FALSE;
+ if (parser->flags & P11_PARSE_FLAG_ANCHOR) {
+ *vtrusted = CK_TRUE;
+ return true;
+ }
+
+ /* Don't add this attribute unless anchor */
+ return false;
+}
+
+static bool
+calc_element (node_asn *el,
+ const unsigned char *data,
+ size_t length,
+ const char *field,
+ CK_ATTRIBUTE *attr)
+{
+ int ret;
+ int start, end;
+
+ ret = asn1_der_decoding_startEnd (el, data, length, field, &start, &end);
+ return_val_if_fail (ret == ASN1_SUCCESS, false);
+ return_val_if_fail (end >= start, false);
+
+ attr->pValue = (void *)(data + start);
+ attr->ulValueLen = (end - start) + 1;
+ return true;
+}
+
+static CK_ATTRIBUTE *
+build_x509_certificate (p11_parser *parser,
+ CK_ATTRIBUTE *attrs,
+ node_asn *cert,
+ const unsigned char *data,
+ size_t length)
+{
+ CK_CERTIFICATE_TYPE vx509 = CKC_X_509;
+ CK_BYTE vchecksum[3];
+
+ /* TODO: Implement */
+ CK_ULONG vcategory = 0;
+ CK_BBOOL vtrusted = CK_FALSE;
+ CK_DATE vstart;
+ CK_DATE vend;
+
+ CK_ATTRIBUTE certificate_type = { CKA_CERTIFICATE_TYPE, &vx509, sizeof (vx509) };
+ CK_ATTRIBUTE certificate_category = { CKA_CERTIFICATE_CATEGORY, &vcategory, sizeof (vcategory) };
+ CK_ATTRIBUTE value = { CKA_VALUE, (void *)data, length };
+
+ CK_ATTRIBUTE check_value = { CKA_CHECK_VALUE, &vchecksum, sizeof (vchecksum) };
+ CK_ATTRIBUTE trusted = { CKA_TRUSTED, &vtrusted, sizeof (vtrusted) };
+ CK_ATTRIBUTE start_date = { CKA_START_DATE, &vstart, sizeof (vstart) };
+ CK_ATTRIBUTE end_date = { CKA_END_DATE, &vend, sizeof (vend) };
+ CK_ATTRIBUTE subject = { CKA_SUBJECT, };
+ CK_ATTRIBUTE issuer = { CKA_ISSUER, };
+ CK_ATTRIBUTE serial_number = { CKA_SERIAL_NUMBER, };
+
+ /*
+ * The following are not present:
+ * CKA_URL
+ * CKA_HASH_OF_SUBJECT_PUBLIC_KEY
+ * CKA_HASH_OF_ISSUER_PUBLIC_KEY
+ * CKA_JAVA_MIDP_SECURITY_DOMAIN
+ */
+
+ calc_check_value (data, length, vchecksum);
+
+ /* This is a silly trust flag, we set it if the cert is an anchor */
+ if (!calc_trusted (parser, cert, &vtrusted))
+ trusted.type = CKA_INVALID;
+
+ if (!calc_date (cert, "tbsCertificate.validity.notBefore", &vstart))
+ start_date.type = CKA_INVALID;
+ if (!calc_date (cert, "tbsCertificate.validity.notAfter", &vend))
+ end_date.type = CKA_INVALID;
+
+ if (!calc_element (cert, data, length, "tbsCertificate.issuer.rdnSequence", &issuer))
+ issuer.type = CKA_INVALID;
+ if (!calc_element (cert, data, length, "tbsCertificate.subject.rdnSequence", &subject))
+ subject.type = CKA_INVALID;
+ if (!calc_element (cert, data, length, "tbsCertificate.serialNumber", &serial_number))
+ serial_number.type = CKA_INVALID;
+
+ return p11_attrs_build (attrs, &certificate_type, &certificate_category,
+ &check_value, &trusted, &start_date, &end_date,
+ &subject, &issuer, &serial_number, &value,
+ NULL);
+}
+
+static unsigned char *
+find_extension (node_asn *cert,
+ const char *extension_oid,
+ size_t *length)
+{
+ unsigned char *data = NULL;
+ char field[128];
+ char oid[128];
+ int len;
+ int ret;
+ int i;
+
+ assert (extension_oid != NULL);
+ assert (strlen (extension_oid) < sizeof (oid));
+
+ for (i = 1; ; i++) {
+ if (snprintf (field, sizeof (field), "tbsCertificate.extensions.?%u.extnID", i) < 0)
+ return_val_if_reached (NULL);
+
+ len = sizeof (oid) - 1;
+ ret = asn1_read_value (cert, field, oid, &len);
+
+ /* No more extensions */
+ if (ret == ASN1_ELEMENT_NOT_FOUND)
+ break;
+
+ /* A really, really long extension oid, not looking for it */
+ else if (ret == ASN1_MEM_ERROR)
+ continue;
+
+ return_val_if_fail (ret == ASN1_SUCCESS, NULL);
+
+ /* The one we're lookin for? */
+ if (strcmp (oid, extension_oid) != 0)
+ continue;
+
+ if (snprintf (field, sizeof (field), "tbsCertificate.extensions.?%u.extnValue", i) < 0)
+ return_val_if_reached (NULL);
+
+ len = 0;
+ ret = asn1_read_value (cert, field, NULL, &len);
+ return_val_if_fail (ret == ASN1_MEM_ERROR, NULL);
+
+ data = malloc (len);
+ return_val_if_fail (data != NULL, NULL);
+
+ ret = asn1_read_value (cert, field, data, &len);
+ return_val_if_fail (ret == ASN1_SUCCESS, NULL);
+
+ *length = len;
+ break;
+ }
+
+ return data;
+}
+
+int
+p11_parse_key_usage (p11_parser *parser,
+ const unsigned char *data,
+ size_t length,
+ unsigned int *ku)
+{
+ char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
+ unsigned char buf[2];
+ node_asn *ext;
+ int len;
+ int ret;
+
+ ext = decode_asn1 (parser, "PKIX1.KeyUsage", data, length, message);
+ if (ext == NULL)
+ return P11_PARSE_UNRECOGNIZED;
+
+ len = sizeof (buf);
+ ret = asn1_read_value (ext, "", buf, &len);
+ return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
+
+ /* A bit string, so combine into one set of flags */
+ *ku = buf[0] | (buf[1] << 8);
+
+ asn1_delete_structure (&ext);
+
+ return P11_PARSE_SUCCESS;
+}
+
+static unsigned int
+decode_ku (p11_parser *parser,
+ node_asn *cert)
+{
+ unsigned char *data;
+ size_t length;
+ unsigned int ku;
+
+ /*
+ * If the certificate extension was missing, then *all* key
+ * usages are to be set. If the extension was invalid, then
+ * fail safe to none of the key usages.
+ */
+
+ data = find_extension (cert, "2.5.29.15", &length);
+
+ if (!data)
+ return ~0U;
+
+ if (p11_parse_key_usage (parser, data, length, &ku) != P11_PARSE_SUCCESS) {
+ p11_message ("invalid key usage certificate extension");
+ ku = 0U;
+ }
+
+ free (data);
+
+ return ku;
+}
+
+int
+p11_parse_extended_key_usage (p11_parser *parser,
+ const unsigned char *data,
+ size_t length,
+ p11_dict *ekus)
+{
+ node_asn *ext;
+ char field[128];
+ char *eku;
+ int len;
+ int ret;
+ int i;
+
+ ext = decode_asn1 (parser, "PKIX1.ExtKeyUsageSyntax", data, length, NULL);
+ if (ext == NULL)
+ return P11_PARSE_UNRECOGNIZED;
+
+ for (i = 1; ; i++) {
+ if (snprintf (field, sizeof (field), "?%u", i) < 0)
+ return_val_if_reached (P11_PARSE_FAILURE);
+
+ len = 0;
+ ret = asn1_read_value (ext, field, NULL, &len);
+ if (ret == ASN1_ELEMENT_NOT_FOUND)
+ break;
+
+ return_val_if_fail (ret == ASN1_MEM_ERROR, P11_PARSE_FAILURE);
+
+ eku = malloc (len + 1);
+ return_val_if_fail (eku != NULL, P11_PARSE_FAILURE);
+
+ ret = asn1_read_value (ext, field, eku, &len);
+ return_val_if_fail (ret == ASN1_SUCCESS, P11_PARSE_FAILURE);
+
+ if (!p11_dict_set (ekus, eku, eku))
+ return_val_if_reached (P11_PARSE_FAILURE);
+ }
+
+ asn1_delete_structure (&ext);
+
+ return P11_PARSE_SUCCESS;
+
+}
+
+static p11_dict *
+decode_eku (p11_parser *parser,
+ node_asn *cert)
+{
+ unsigned char *data;
+ p11_dict *ekus;
+ char *eku;
+ size_t length;
+
+ ekus = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL);
+ return_val_if_fail (ekus != NULL, NULL);
+
+ /*
+ * If the certificate extension was missing, then *all* extended key
+ * usages are to be set. If the extension was invalid, then
+ * fail safe to none of the extended key usages.
+ */
+
+ data = find_extension (cert, "2.5.29.37", &length);
+ if (data) {
+ if (p11_parse_extended_key_usage (parser, data, length, ekus) != P11_PARSE_SUCCESS) {
+ p11_message ("invalid extended key usage certificate extension");
+ p11_dict_free (ekus);
+ ekus = NULL;
+ }
+ } else {
+ /* A star means anything to has_eku() */
+ eku = strdup ("*");
+ if (!eku || !p11_dict_set (ekus, eku, eku))
+ return_val_if_reached (NULL);
+ }
+
+ free (data);
+
+ return ekus;
+}
+
+static int
+has_eku (p11_dict *ekus,
+ const char *eku)
+{
+ return ekus != NULL && /* If a "*" present, then any thing allowed */
+ (p11_dict_get (ekus, eku) || p11_dict_get (ekus, "*"));
+}
+
+static CK_ATTRIBUTE *
+build_nss_trust_object (p11_parser *parser,
+ CK_ATTRIBUTE *attrs,
+ node_asn *cert,
+ const unsigned char *data,
+ size_t length)
+{
+ CK_BYTE vsha1_hash[P11_CHECKSUM_SHA1_LENGTH];
+ CK_BYTE vmd5_hash[P11_CHECKSUM_MD5_LENGTH];
+ CK_BBOOL vfalse = CK_FALSE;
+
+ CK_TRUST vdigital_signature;
+ CK_TRUST vnon_repudiation;
+ CK_TRUST vkey_encipherment;
+ CK_TRUST vdata_encipherment;
+ CK_TRUST vkey_agreement;
+ CK_TRUST vkey_cert_sign;
+ CK_TRUST vcrl_sign;
+
+ CK_TRUST vserver_auth;
+ CK_TRUST vclient_auth;
+ CK_TRUST vcode_signing;
+ CK_TRUST vemail_protection;
+ CK_TRUST vipsec_end_system;
+ CK_TRUST vipsec_tunnel;
+ CK_TRUST vipsec_user;
+ CK_TRUST vtime_stamping;
+
+ CK_ATTRIBUTE subject = { CKA_SUBJECT, };
+ CK_ATTRIBUTE issuer = { CKA_ISSUER, };
+ CK_ATTRIBUTE serial_number = { CKA_SERIAL_NUMBER, };
+
+ CK_ATTRIBUTE md5_hash = { CKA_CERT_MD5_HASH, vmd5_hash, sizeof (vmd5_hash) };
+ CK_ATTRIBUTE sha1_hash = { CKA_CERT_SHA1_HASH, vsha1_hash, sizeof (vsha1_hash) };
+
+ CK_ATTRIBUTE digital_signature = { CKA_TRUST_DIGITAL_SIGNATURE, &vdigital_signature, sizeof (vdigital_signature) };
+ CK_ATTRIBUTE non_repudiation = { CKA_TRUST_NON_REPUDIATION, &vnon_repudiation, sizeof (vnon_repudiation) };
+ CK_ATTRIBUTE key_encipherment = { CKA_TRUST_KEY_ENCIPHERMENT, &vkey_encipherment, sizeof (vkey_encipherment) };
+ CK_ATTRIBUTE data_encipherment = { CKA_TRUST_DATA_ENCIPHERMENT, &vdata_encipherment, sizeof (vdata_encipherment) };
+ CK_ATTRIBUTE key_agreement = { CKA_TRUST_KEY_AGREEMENT, &vkey_agreement, sizeof (vkey_agreement) };
+ CK_ATTRIBUTE key_cert_sign = { CKA_TRUST_KEY_CERT_SIGN, &vkey_cert_sign, sizeof (vkey_cert_sign) };
+ CK_ATTRIBUTE crl_sign = { CKA_TRUST_CRL_SIGN, &vcrl_sign, sizeof (vcrl_sign) };
+
+ CK_ATTRIBUTE server_auth = { CKA_TRUST_SERVER_AUTH, &vserver_auth, sizeof (vserver_auth) };
+ CK_ATTRIBUTE client_auth = { CKA_TRUST_CLIENT_AUTH, &vclient_auth, sizeof (vclient_auth) };
+ CK_ATTRIBUTE code_signing = { CKA_TRUST_CODE_SIGNING, &vcode_signing, sizeof (vcode_signing) };
+ CK_ATTRIBUTE email_protection = { CKA_TRUST_EMAIL_PROTECTION, &vemail_protection, sizeof (vemail_protection) };
+ CK_ATTRIBUTE ipsec_end_system = { CKA_TRUST_IPSEC_END_SYSTEM, &vipsec_end_system, sizeof (vipsec_end_system) };
+ CK_ATTRIBUTE ipsec_tunnel = { CKA_TRUST_IPSEC_TUNNEL, &vipsec_tunnel, sizeof (vipsec_tunnel) };
+ CK_ATTRIBUTE ipsec_user = { CKA_TRUST_IPSEC_USER, &vipsec_user, sizeof (vipsec_user) };
+ CK_ATTRIBUTE time_stamping = { CKA_TRUST_TIME_STAMPING, &vtime_stamping, sizeof (vtime_stamping) };
+
+ CK_ATTRIBUTE step_up_approved = { CKA_TRUST_STEP_UP_APPROVED, &vfalse, sizeof (vfalse) };
+
+ p11_dict *ekus;
+ unsigned int ku;
+ CK_TRUST value;
+ CK_TRUST unknown;
+
+ if (!calc_element (cert, data, length, "tbsCertificate.issuer.rdnSequence", &issuer))
+ issuer.type = CKA_INVALID;
+ if (!calc_element (cert, data, length, "tbsCertificate.subject.rdnSequence", &subject))
+ subject.type = CKA_INVALID;
+ if (!calc_element (cert, data, length, "tbsCertificate.serialNumber", &serial_number))
+ serial_number.type = CKA_INVALID;
+
+ p11_checksum_md5 (vmd5_hash, data, length, NULL);
+ p11_checksum_sha1 (vsha1_hash, data, length, NULL);
+
+ unknown = CKT_NETSCAPE_TRUST_UNKNOWN;
+ if (parser->flags & P11_PARSE_FLAG_ANCHOR)
+ value = CKT_NETSCAPE_TRUSTED_DELEGATOR;
+ else
+ value = CKT_NETSCAPE_TRUSTED;
+
+ ku = decode_ku (parser, cert);
+ vdigital_signature = (ku & P11_KU_DIGITAL_SIGNATURE) ? value : unknown;
+ vnon_repudiation = (ku & P11_KU_NON_REPUDIATION) ? value : unknown;
+ vkey_encipherment = (ku & P11_KU_KEY_ENCIPHERMENT) ? value : unknown;
+ vkey_agreement = (ku & P11_KU_KEY_AGREEMENT) ? value : unknown;
+ vkey_cert_sign = (ku & P11_KU_KEY_CERT_SIGN) ? value : unknown;
+ vcrl_sign = (ku & P11_KU_CRL_SIGN) ? value : unknown;
+
+ ekus = decode_eku (parser, cert);
+ vserver_auth = has_eku (ekus, P11_EKU_SERVER_AUTH) ? value : unknown;
+ vclient_auth = has_eku (ekus, P11_EKU_CLIENT_AUTH) ? value : unknown;
+ vcode_signing = has_eku (ekus, P11_EKU_CODE_SIGNING) ? value : unknown;
+ vemail_protection = has_eku (ekus, P11_EKU_EMAIL) ? value : unknown;
+ vipsec_end_system = has_eku (ekus, P11_EKU_IPSEC_END_SYSTEM) ? value : unknown;
+ vipsec_tunnel = has_eku (ekus, P11_EKU_IPSEC_TUNNEL) ? value : unknown;
+ vipsec_user = has_eku (ekus, P11_EKU_IPSEC_USER) ? value : unknown;
+ vtime_stamping = has_eku (ekus, P11_EKU_TIME_STAMPING) ? value : unknown;
+ p11_dict_free (ekus);
+
+ return p11_attrs_build (attrs, &subject, &issuer, &serial_number, &md5_hash, &sha1_hash,
+ &digital_signature, &non_repudiation, &key_encipherment,
+ &data_encipherment, &key_agreement, &key_cert_sign, &crl_sign,
+ &server_auth, &client_auth, &code_signing, &email_protection,
+ &ipsec_end_system, &ipsec_tunnel, &ipsec_user, &time_stamping,
+ &step_up_approved, NULL);
+
+}
+
+static int
+sink_nss_trust_object (p11_parser *parser,
+ CK_BYTE *vid,
+ node_asn *cert,
+ const unsigned char *data,
+ size_t length)
+{
+ CK_ATTRIBUTE *attrs = NULL;
+
+ attrs = build_object (parser, attrs, CKO_NETSCAPE_TRUST, vid, NULL);
+ return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
+
+ attrs = build_nss_trust_object (parser, attrs, cert, data, length);
+ return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
+
+ sink_object (parser, attrs);
+ return P11_PARSE_SUCCESS;
+}
+
+static int
+sink_x509_certificate (p11_parser *parser,
+ CK_BYTE *vid,
+ node_asn *cert,
+ const unsigned char *data,
+ size_t length)
+{
+ CK_ATTRIBUTE *attrs = NULL;
+
+ attrs = build_object (parser, attrs, CKO_CERTIFICATE, vid, NULL);
+ return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
+
+ attrs = build_x509_certificate (parser, attrs, cert, data, length);
+ return_val_if_fail (attrs != NULL, P11_PARSE_FAILURE);
+
+ sink_object (parser, attrs);
+ return P11_PARSE_SUCCESS;
+}
+
+static int
+parse_der_x509_certificate (p11_parser *parser,
+ const unsigned char *data,
+ size_t length)
+{
+ CK_BYTE vid[ID_LENGTH];
+ node_asn *cert;
+ int ret;
+
+ cert = decode_asn1 (parser, "PKIX1.Certificate", data, length, NULL);
+ if (cert == NULL)
+ return P11_PARSE_UNRECOGNIZED;
+
+ /* The CKA_ID links related objects */
+ id_generate (parser, vid);
+
+ ret = sink_x509_certificate (parser, vid, cert, data, length);
+ return_val_if_fail (ret == P11_PARSE_SUCCESS, ret);
+
+ ret = sink_nss_trust_object (parser, vid, cert, data, length);
+ return_val_if_fail (ret == P11_PARSE_SUCCESS, ret);
+
+ asn1_delete_structure (&cert);
+ return P11_PARSE_SUCCESS;
+}
+
+static parser_func all_parsers[] = {
+ parse_der_x509_certificate,
+ NULL,
+};
+
+p11_parser *
+p11_parser_new (void)
+{
+ char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
+ node_asn *definitions = NULL;
+ p11_parser *parser;
+ int ret;
+
+ ret = asn1_array2tree (pkix_asn1_tab, &definitions, message);
+ if (ret != ASN1_SUCCESS) {
+ p11_debug_precond ("failed to load pkix_asn1_tab in %s: %d %s",
+ __func__, ret, message);
+ return NULL;
+ }
+
+ parser = calloc (1, sizeof (p11_parser));
+ return_val_if_fail (parser != NULL, NULL);
+
+ parser->pkix_definitions = definitions;
+ return parser;
+}
+
+void
+p11_parser_free (p11_parser *parser)
+{
+ if (!parser)
+ return;
+
+ asn1_delete_structure (&parser->pkix_definitions);
+ free (parser);
+}
+
+int
+p11_parse_memory (p11_parser *parser,
+ const char *filename,
+ int flags,
+ const unsigned char *data,
+ size_t length,
+ p11_parser_sink sink,
+ void *sink_data)
+{
+ int ret = P11_PARSE_UNRECOGNIZED;
+ char *base;
+ int i;
+
+ return_val_if_fail (parser != NULL, P11_PARSE_FAILURE);
+ return_val_if_fail (parser->sink == NULL, P11_PARSE_FAILURE);
+
+ base = basename (filename);
+ parser->probable_label = base;
+ parser->sink = sink;
+ parser->sink_data = sink_data;
+ parser->flags = flags;
+
+ for (i = 0; all_parsers[i] != NULL; i++) {
+ ret = (all_parsers[i]) (parser, data, length);
+ if (ret != P11_PARSE_UNRECOGNIZED)
+ break;
+ }
+
+ parser->probable_label = NULL;
+ parser->sink = NULL;
+ parser->sink_data = NULL;
+ parser->flags = 0;
+
+ return ret;
+}
+
+int
+p11_parse_file (p11_parser *parser,
+ const char *filename,
+ int flags,
+ p11_parser_sink sink,
+ void *sink_data)
+{
+ void *data;
+ struct stat sb;
+ int fd;
+ int ret;
+
+ fd = open (filename, O_RDONLY);
+ if (fd == -1) {
+ p11_message ("couldn't open file: %s: %s", filename, strerror (errno));
+ return P11_PARSE_FAILURE;
+ }
+
+ if (fstat (fd, &sb) < 0) {
+ p11_message ("couldn't stat file: %s: %s", filename, strerror (errno));
+ return P11_PARSE_FAILURE;
+ }
+
+ data = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == NULL) {
+ p11_message ("couldn't map file: %s: %s", filename, strerror (errno));
+ return P11_PARSE_FAILURE;
+ }
+
+ ret = p11_parse_memory (parser, filename, flags, data, sb.st_size, sink, sink_data);
+
+ munmap (data, sb.st_size);
+ close (fd);
+
+ return ret;
+}
diff --git a/trust/parser.h b/trust/parser.h
new file mode 100644
index 0000000..44529ba
--- /dev/null
+++ b/trust/parser.h
@@ -0,0 +1,108 @@
+/*
+ * 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 "dict.h"
+#include "pkcs11.h"
+
+#ifndef P11_PARSER_H_
+#define P11_PARSER_H_
+
+enum {
+ P11_PARSE_FAILURE = -1,
+ P11_PARSE_UNRECOGNIZED = 0,
+ P11_PARSE_SUCCESS = 1,
+};
+
+enum {
+ P11_PARSE_FLAG_NONE = 0,
+ P11_PARSE_FLAG_ANCHOR = 1 << 0,
+};
+
+#define P11_PARSER_FIRST_HANDLE 0xA0000000UL
+
+#define P11_EKU_SERVER_AUTH "1.3.6.1.5.5.7.3.1"
+#define P11_EKU_CLIENT_AUTH "1.3.6.1.5.5.7.3.2"
+#define P11_EKU_CODE_SIGNING "1.3.6.1.5.5.7.3.3"
+#define P11_EKU_EMAIL "1.3.6.1.5.5.7.3.4"
+#define P11_EKU_IPSEC_END_SYSTEM "1.3.6.1.5.5.7.3.5"
+#define P11_EKU_IPSEC_TUNNEL "1.3.6.1.5.5.7.3.6"
+#define P11_EKU_IPSEC_USER "1.3.6.1.5.5.7.3.7"
+#define P11_EKU_TIME_STAMPING "1.3.6.1.5.5.7.3.8"
+
+enum {
+ P11_KU_DIGITAL_SIGNATURE = 128,
+ P11_KU_NON_REPUDIATION = 64,
+ P11_KU_KEY_ENCIPHERMENT = 32,
+ P11_KU_DATA_ENCIPHERMENT = 16,
+ P11_KU_KEY_AGREEMENT = 8,
+ P11_KU_KEY_CERT_SIGN = 4,
+ P11_KU_CRL_SIGN = 2,
+ P11_KU_ENCIPHER_ONLY = 1,
+ P11_KU_DECIPHER_ONLY = 32768,
+};
+
+typedef struct _p11_parser p11_parser;
+
+p11_parser * p11_parser_new (void);
+
+void p11_parser_free (p11_parser *parser);
+
+typedef void (* p11_parser_sink) (CK_ATTRIBUTE *attrs,
+ void *user_data);
+
+int p11_parse_memory (p11_parser *parser,
+ const char *filename,
+ int flags,
+ const unsigned char *data,
+ size_t length,
+ p11_parser_sink sink,
+ void *sink_data);
+
+int p11_parse_file (p11_parser *parser,
+ const char *filename,
+ int flags,
+ p11_parser_sink sink,
+ void *sink_data);
+
+int p11_parse_key_usage (p11_parser *parser,
+ const unsigned char *data,
+ size_t length,
+ unsigned int *ku);
+
+int p11_parse_extended_key_usage (p11_parser *parser,
+ const unsigned char *data,
+ size_t length,
+ p11_dict *ekus);
+
+#endif
diff --git a/trust/session.c b/trust/session.c
new file mode 100644
index 0000000..070364e
--- /dev/null
+++ b/trust/session.c
@@ -0,0 +1,206 @@
+/*
+ * 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 "attrs.h"
+#define P11_DEBUG_FLAG P11_DEBUG_TRUST
+#include "debug.h"
+#include "dict.h"
+#include "library.h"
+#include "pkcs11.h"
+#include "module.h"
+#include "session.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ CK_OBJECT_HANDLE handle;
+ CK_ATTRIBUTE *attrs;
+} Object;
+
+static void
+object_free (void *data)
+{
+ Object *object = data;
+ p11_attrs_free (object->attrs);
+ free (object);
+}
+
+p11_session *
+p11_session_new (p11_token *token)
+{
+ p11_session *session;
+
+ session = calloc (1, sizeof (p11_session));
+ return_val_if_fail (session != NULL, NULL);
+
+ session->handle = p11_module_next_id ();
+
+ session->objects = p11_dict_new (p11_dict_ulongptr_hash,
+ p11_dict_ulongptr_equal,
+ NULL, object_free);
+ return_val_if_fail (session->objects != NULL, NULL);
+
+ session->token = token;
+
+ return session;
+}
+
+void
+p11_session_free (void *data)
+{
+ p11_session *session = data;
+
+ p11_session_set_operation (session, NULL, NULL);
+ p11_dict_free (session->objects);
+
+ free (session);
+}
+
+CK_RV
+p11_session_add_object (p11_session *session,
+ CK_ATTRIBUTE *attrs,
+ CK_OBJECT_HANDLE *handle)
+{
+ Object *object;
+
+ assert (handle != NULL);
+ assert (session != NULL);
+
+ return_val_if_fail (attrs != NULL, CKR_GENERAL_ERROR);
+
+ object = malloc (sizeof (Object));
+ return_val_if_fail (object != NULL, CKR_HOST_MEMORY);
+
+ object->handle = p11_module_next_id ();
+ object->attrs = attrs;
+
+ if (!p11_dict_set (session->objects, &object->handle, object))
+ return_val_if_reached (CKR_HOST_MEMORY);
+
+ *handle = object->handle;
+ return CKR_OK;
+}
+
+CK_RV
+p11_session_del_object (p11_session *session,
+ CK_OBJECT_HANDLE handle)
+{
+ p11_dict *objects;
+
+ assert (session != NULL);
+
+ if (p11_dict_remove (session->objects, &handle))
+ return CKR_OK;
+
+ /* Look for in the global objects */
+ objects = p11_token_objects (session->token);
+ if (p11_dict_get (objects, &handle))
+ return CKR_TOKEN_WRITE_PROTECTED;
+
+ return CKR_OBJECT_HANDLE_INVALID;
+}
+
+CK_ATTRIBUTE *
+p11_session_get_object (p11_session *session,
+ CK_OBJECT_HANDLE handle,
+ CK_BBOOL *token)
+{
+ CK_ATTRIBUTE *attrs;
+ p11_dict *objects;
+ Object *object;
+
+ assert (session != NULL);
+
+ object = p11_dict_get (session->objects, &handle);
+ if (object) {
+ if (token)
+ *token = CK_FALSE;
+ return object->attrs;
+ }
+
+ objects = p11_token_objects (session->token);
+ attrs = p11_dict_get (objects, &handle);
+ if (attrs) {
+ if (token)
+ *token = CK_TRUE;
+ return attrs;
+ }
+
+ return NULL;
+}
+
+CK_RV
+p11_session_set_object (p11_session *session,
+ CK_OBJECT_HANDLE handle,
+ CK_ATTRIBUTE *template,
+ CK_ULONG count)
+{
+ CK_BBOOL token;
+ p11_dict *objects;
+ Object *object;
+
+ assert (session != NULL);
+
+ object = p11_dict_get (session->objects, &handle);
+ if (object == NULL) {
+ objects = p11_token_objects (session->token);
+ if (p11_dict_get (objects, &handle))
+ return CKR_TOKEN_WRITE_PROTECTED;
+ return CKR_OBJECT_HANDLE_INVALID;
+ }
+
+ if (!p11_attrs_findn_bool (template, count, CKA_TOKEN, &token) && token)
+ return CKR_TEMPLATE_INCONSISTENT;
+
+ object->attrs = p11_attrs_buildn (object->attrs, template, count);
+ return CKR_OK;
+}
+
+void
+p11_session_set_operation (p11_session *session,
+ p11_session_cleanup cleanup,
+ void *operation)
+{
+ assert (session != NULL);
+
+ if (session->cleanup)
+ (session->cleanup) (session->operation);
+ session->cleanup = cleanup;
+ session->operation = operation;
+}
diff --git a/trust/session.h b/trust/session.h
new file mode 100644
index 0000000..97aedb1
--- /dev/null
+++ b/trust/session.h
@@ -0,0 +1,78 @@
+/*
+ * 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 "pkcs11.h"
+#include "token.h"
+
+#ifndef P11_SESSION_H_
+#define P11_SESSION_H_
+
+typedef void (* p11_session_cleanup) (void *data);
+
+typedef struct {
+ CK_SESSION_HANDLE handle;
+ p11_dict *objects;
+ p11_token *token;
+ CK_BBOOL loaded;
+
+ /* Used by various operations */
+ p11_session_cleanup cleanup;
+ void *operation;
+} p11_session;
+
+p11_session * p11_session_new (p11_token *token);
+
+void p11_session_free (void *data);
+
+CK_RV p11_session_add_object (p11_session *session,
+ CK_ATTRIBUTE *attrs,
+ CK_OBJECT_HANDLE *handle);
+
+CK_RV p11_session_del_object (p11_session *session,
+ CK_OBJECT_HANDLE handle);
+
+CK_ATTRIBUTE * p11_session_get_object (p11_session *session,
+ CK_OBJECT_HANDLE handle,
+ CK_BBOOL *token);
+
+CK_RV p11_session_set_object (p11_session *session,
+ CK_OBJECT_HANDLE handle,
+ CK_ATTRIBUTE *template,
+ CK_ULONG count);
+
+void p11_session_set_operation (p11_session *session,
+ p11_session_cleanup cleanup,
+ void *operation);
+
+#endif /* P11_SESSION_H_ */
diff --git a/trust/tests/Makefile.am b/trust/tests/Makefile.am
new file mode 100644
index 0000000..2426f8a
--- /dev/null
+++ b/trust/tests/Makefile.am
@@ -0,0 +1,44 @@
+
+include $(top_srcdir)/build/Makefile.tests
+
+NULL =
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(srcdir)/.. \
+ -I$(top_srcdir)/common \
+ $(CUTEST_CFLAGS)
+
+noinst_LTLIBRARIES = \
+ libtestdata.la
+
+libtestdata_la_SOURCES = \
+ test-data.c test-data.h
+
+LDADD = \
+ $(top_builddir)/trust/libtrust-testable.la \
+ $(top_builddir)/common/libp11-data.la \
+ $(top_builddir)/common/libp11-library.la \
+ $(top_builddir)/common/libp11-compat.la \
+ $(builddir)/libtestdata.la \
+ $(LIBTASN1_LIBS) \
+ $(CUTEST_LIBS) \
+ $(NULL)
+
+CHECK_PROGS = \
+ test-parser \
+ test-token \
+ test-session \
+ test-module \
+ $(NULL)
+
+noinst_PROGRAMS = \
+ $(CHECK_PROGS)
+
+TESTS = $(CHECK_PROGS:=$(EXEEXT))
+
+EXTRA_DIST = \
+ anchors \
+ certificates \
+ files \
+ $(NULL)
diff --git a/trust/tests/anchors/cacert3.der b/trust/tests/anchors/cacert3.der
new file mode 100644
index 0000000..56f8c88
--- /dev/null
+++ b/trust/tests/anchors/cacert3.der
Binary files differ
diff --git a/trust/tests/anchors/testing-ca.der b/trust/tests/anchors/testing-ca.der
new file mode 100644
index 0000000..d3f70ea
--- /dev/null
+++ b/trust/tests/anchors/testing-ca.der
Binary files differ
diff --git a/trust/tests/certificates/cacert-ca.der b/trust/tests/certificates/cacert-ca.der
new file mode 100644
index 0000000..719b0ff
--- /dev/null
+++ b/trust/tests/certificates/cacert-ca.der
Binary files differ
diff --git a/trust/tests/certificates/self-signed-with-eku.der b/trust/tests/certificates/self-signed-with-eku.der
new file mode 100644
index 0000000..33e0760
--- /dev/null
+++ b/trust/tests/certificates/self-signed-with-eku.der
Binary files differ
diff --git a/trust/tests/certificates/self-signed-with-ku.der b/trust/tests/certificates/self-signed-with-ku.der
new file mode 100644
index 0000000..e6f36e3
--- /dev/null
+++ b/trust/tests/certificates/self-signed-with-ku.der
Binary files differ
diff --git a/trust/tests/files/cacert-ca.der b/trust/tests/files/cacert-ca.der
new file mode 100644
index 0000000..719b0ff
--- /dev/null
+++ b/trust/tests/files/cacert-ca.der
Binary files differ
diff --git a/trust/tests/files/cacert3.der b/trust/tests/files/cacert3.der
new file mode 100644
index 0000000..56f8c88
--- /dev/null
+++ b/trust/tests/files/cacert3.der
Binary files differ
diff --git a/trust/tests/files/self-server.der b/trust/tests/files/self-server.der
new file mode 100644
index 0000000..68fe9af
--- /dev/null
+++ b/trust/tests/files/self-server.der
Binary files differ
diff --git a/trust/tests/files/testing-server.der b/trust/tests/files/testing-server.der
new file mode 100644
index 0000000..cf2de65
--- /dev/null
+++ b/trust/tests/files/testing-server.der
Binary files differ
diff --git a/trust/tests/files/unrecognized-file.txt b/trust/tests/files/unrecognized-file.txt
new file mode 100644
index 0000000..4d5bac3
--- /dev/null
+++ b/trust/tests/files/unrecognized-file.txt
@@ -0,0 +1 @@
+# This file is not recognized by the parser \ No newline at end of file
diff --git a/trust/tests/test-data.c b/trust/tests/test-data.c
new file mode 100644
index 0000000..1decf2e
--- /dev/null
+++ b/trust/tests/test-data.c
@@ -0,0 +1,128 @@
+/*
+ * 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@gnome.org>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "attrs.h"
+#include "test-data.h"
+
+void
+test_check_object (CuTest *cu,
+ CK_ATTRIBUTE *attrs,
+ CK_OBJECT_CLASS klass,
+ const char *label)
+{
+ CK_BBOOL val;
+ CK_ULONG ulong;
+ CK_ATTRIBUTE *attr;
+
+ if (!p11_attrs_find_bool (attrs, CKA_TOKEN, &val))
+ CuFail (cu, "missing CKA_TOKEN");
+ CuAssertIntEquals (cu, CK_TRUE, val);
+
+ if (!p11_attrs_find_bool (attrs, CKA_PRIVATE, &val))
+ CuFail (cu, "missing CKA_PRIVATE");
+ CuAssertIntEquals (cu, CK_FALSE, val);
+
+ if (!p11_attrs_find_bool (attrs, CKA_MODIFIABLE, &val))
+ CuFail (cu, "missing CKA_MODIFIABLE");
+ CuAssertIntEquals (cu, CK_FALSE, val);
+
+ if (!p11_attrs_find_ulong (attrs, CKA_CLASS, &ulong))
+ CuFail (cu, "missing CKA_CLASS");
+ CuAssertIntEquals (cu, klass, ulong);
+
+ if (label) {
+ attr = p11_attrs_find_valid (attrs, CKA_LABEL);
+ CuAssertPtrNotNull (cu, attr);
+ CuAssertTrue (cu, p11_attr_match_value (attr, label, -1));
+ }
+}
+
+void
+test_check_cacert3_ca (CuTest *cu,
+ CK_ATTRIBUTE *attrs,
+ const char *label)
+{
+ CK_ATTRIBUTE *attr;
+ CK_ULONG ulong;
+
+ test_check_object (cu, attrs, CKO_CERTIFICATE, label);
+
+ if (!p11_attrs_find_ulong (attrs, CKA_CERTIFICATE_TYPE, &ulong))
+ CuFail (cu, "missing CKA_CERTIFICATE_TYPE");
+ CuAssertIntEquals (cu, CKC_X_509, ulong);
+
+ /* TODO: Implement */
+ if (!p11_attrs_find_ulong (attrs, CKA_CERTIFICATE_CATEGORY, &ulong))
+ CuFail (cu, "missing CKA_CERTIFICATE_CATEGORY");
+ CuAssertIntEquals (cu, 0, ulong);
+
+ attr = p11_attrs_find (attrs, CKA_VALUE);
+ CuAssertPtrNotNull (cu, attr);
+ CuAssertTrue (cu, p11_attr_match_value (attr, test_cacert3_ca_der,
+ sizeof (test_cacert3_ca_der)));
+
+ attr = p11_attrs_find_valid (attrs, CKA_CHECK_VALUE);
+ CuAssertPtrNotNull (cu, attr);
+ CuAssertTrue (cu, p11_attr_match_value (attr, "\xad\x7c\x3f", 3));
+
+ attr = p11_attrs_find (attrs, CKA_START_DATE);
+ CuAssertPtrNotNull (cu, attr);
+ CuAssertTrue (cu, p11_attr_match_value (attr, "20110523", -1));
+
+ attr = p11_attrs_find_valid (attrs, CKA_END_DATE);
+ CuAssertPtrNotNull (cu, attr);
+ CuAssertTrue (cu, p11_attr_match_value (attr, "20210520", -1));
+
+ attr = p11_attrs_find (attrs, CKA_SUBJECT);
+ CuAssertPtrNotNull (cu, attr);
+ CuAssertTrue (cu, p11_attr_match_value (attr, test_cacert3_ca_subject,
+ sizeof (test_cacert3_ca_subject)));
+
+ attr = p11_attrs_find (attrs, CKA_ISSUER);
+ CuAssertPtrNotNull (cu, attr);
+ CuAssertTrue (cu, p11_attr_match_value (attr, test_cacert3_ca_issuer,
+ sizeof (test_cacert3_ca_issuer)));
+
+ attr = p11_attrs_find (attrs, CKA_SERIAL_NUMBER);
+ CuAssertPtrNotNull (cu, attr);
+ CuAssertTrue (cu, p11_attr_match_value (attr, test_cacert3_ca_serial,
+ sizeof (test_cacert3_ca_serial)));
+}
diff --git a/trust/tests/test-data.h b/trust/tests/test-data.h
new file mode 100644
index 0000000..9789493
--- /dev/null
+++ b/trust/tests/test-data.h
@@ -0,0 +1,220 @@
+/*
+ * 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@gnome.org>
+ */
+
+#include <sys/types.h>
+
+#ifndef TEST_DATA_H_
+#define TEST_DATA_H_
+
+void test_check_object (CuTest *cu,
+ CK_ATTRIBUTE *attrs,
+ CK_OBJECT_CLASS klass,
+ const char *label);
+
+void test_check_cacert3_ca (CuTest *cu,
+ CK_ATTRIBUTE *attrs,
+ const char *label);
+
+static const unsigned char test_cacert3_ca_der[] = {
+ 0x30, 0x82, 0x07, 0x59, 0x30, 0x82, 0x05, 0x41, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x0a,
+ 0x41, 0x8a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+ 0x00, 0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f,
+ 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15,
+ 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72,
+ 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19,
+ 0x43, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20,
+ 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
+ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72,
+ 0x74, 0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x31, 0x30, 0x35, 0x32, 0x33, 0x31, 0x37, 0x34, 0x38, 0x30, 0x32, 0x5a, 0x17, 0x0d, 0x32,
+ 0x31, 0x30, 0x35, 0x32, 0x30, 0x31, 0x37, 0x34, 0x38, 0x30, 0x32, 0x5a, 0x30, 0x54, 0x31, 0x14,
+ 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x20,
+ 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74,
+ 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x43,
+ 0x41, 0x63, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x52, 0x6f,
+ 0x6f, 0x74, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82,
+ 0x02, 0x01, 0x00, 0xab, 0x49, 0x35, 0x11, 0x48, 0x7c, 0xd2, 0x26, 0x7e, 0x53, 0x94, 0xcf, 0x43,
+ 0xa9, 0xdd, 0x28, 0xd7, 0x42, 0x2a, 0x8b, 0xf3, 0x87, 0x78, 0x19, 0x58, 0x7c, 0x0f, 0x9e, 0xda,
+ 0x89, 0x7d, 0xe1, 0xfb, 0xeb, 0x72, 0x90, 0x0d, 0x74, 0xa1, 0x96, 0x64, 0xab, 0x9f, 0xa0, 0x24,
+ 0x99, 0x73, 0xda, 0xe2, 0x55, 0x76, 0xc7, 0x17, 0x7b, 0xf5, 0x04, 0xac, 0x46, 0xb8, 0xc3, 0xbe,
+ 0x7f, 0x64, 0x8d, 0x10, 0x6c, 0x24, 0xf3, 0x61, 0x9c, 0xc0, 0xf2, 0x90, 0xfa, 0x51, 0xe6, 0xf5,
+ 0x69, 0x01, 0x63, 0xc3, 0x0f, 0x56, 0xe2, 0x4a, 0x42, 0xcf, 0xe2, 0x44, 0x8c, 0x25, 0x28, 0xa8,
+ 0xc5, 0x79, 0x09, 0x7d, 0x46, 0xb9, 0x8a, 0xf3, 0xe9, 0xf3, 0x34, 0x29, 0x08, 0x45, 0xe4, 0x1c,
+ 0x9f, 0xcb, 0x94, 0x04, 0x1c, 0x81, 0xa8, 0x14, 0xb3, 0x98, 0x65, 0xc4, 0x43, 0xec, 0x4e, 0x82,
+ 0x8d, 0x09, 0xd1, 0xbd, 0xaa, 0x5b, 0x8d, 0x92, 0xd0, 0xec, 0xde, 0x90, 0xc5, 0x7f, 0x0a, 0xc2,
+ 0xe3, 0xeb, 0xe6, 0x31, 0x5a, 0x5e, 0x74, 0x3e, 0x97, 0x33, 0x59, 0xe8, 0xc3, 0x03, 0x3d, 0x60,
+ 0x33, 0xbf, 0xf7, 0xd1, 0x6f, 0x47, 0xc4, 0xcd, 0xee, 0x62, 0x83, 0x52, 0x6e, 0x2e, 0x08, 0x9a,
+ 0xa4, 0xd9, 0x15, 0x18, 0x91, 0xa6, 0x85, 0x92, 0x47, 0xb0, 0xae, 0x48, 0xeb, 0x6d, 0xb7, 0x21,
+ 0xec, 0x85, 0x1a, 0x68, 0x72, 0x35, 0xab, 0xff, 0xf0, 0x10, 0x5d, 0xc0, 0xf4, 0x94, 0xa7, 0x6a,
+ 0xd5, 0x3b, 0x92, 0x7e, 0x4c, 0x90, 0x05, 0x7e, 0x93, 0xc1, 0x2c, 0x8b, 0xa4, 0x8e, 0x62, 0x74,
+ 0x15, 0x71, 0x6e, 0x0b, 0x71, 0x03, 0xea, 0xaf, 0x15, 0x38, 0x9a, 0xd4, 0xd2, 0x05, 0x72, 0x6f,
+ 0x8c, 0xf9, 0x2b, 0xeb, 0x5a, 0x72, 0x25, 0xf9, 0x39, 0x46, 0xe3, 0x72, 0x1b, 0x3e, 0x04, 0xc3,
+ 0x64, 0x27, 0x22, 0x10, 0x2a, 0x8a, 0x4f, 0x58, 0xa7, 0x03, 0xad, 0xbe, 0xb4, 0x2e, 0x13, 0xed,
+ 0x5d, 0xaa, 0x48, 0xd7, 0xd5, 0x7d, 0xd4, 0x2a, 0x7b, 0x5c, 0xfa, 0x46, 0x04, 0x50, 0xe4, 0xcc,
+ 0x0e, 0x42, 0x5b, 0x8c, 0xed, 0xdb, 0xf2, 0xcf, 0xfc, 0x96, 0x93, 0xe0, 0xdb, 0x11, 0x36, 0x54,
+ 0x62, 0x34, 0x38, 0x8f, 0x0c, 0x60, 0x9b, 0x3b, 0x97, 0x56, 0x38, 0xad, 0xf3, 0xd2, 0x5b, 0x8b,
+ 0xa0, 0x5b, 0xea, 0x4e, 0x96, 0xb8, 0x7c, 0xd7, 0xd5, 0xa0, 0x86, 0x70, 0x40, 0xd3, 0x91, 0x29,
+ 0xb7, 0xa2, 0x3c, 0xad, 0xf5, 0x8c, 0xbb, 0xcf, 0x1a, 0x92, 0x8a, 0xe4, 0x34, 0x7b, 0xc0, 0xd8,
+ 0x6c, 0x5f, 0xe9, 0x0a, 0xc2, 0xc3, 0xa7, 0x20, 0x9a, 0x5a, 0xdf, 0x2c, 0x5d, 0x52, 0x5c, 0xba,
+ 0x47, 0xd5, 0x9b, 0xef, 0x24, 0x28, 0x70, 0x38, 0x20, 0x2f, 0xd5, 0x7f, 0x29, 0xc0, 0xb2, 0x41,
+ 0x03, 0x68, 0x92, 0xcc, 0xe0, 0x9c, 0xcc, 0x97, 0x4b, 0x45, 0xef, 0x3a, 0x10, 0x0a, 0xab, 0x70,
+ 0x3a, 0x98, 0x95, 0x70, 0xad, 0x35, 0xb1, 0xea, 0x85, 0x2b, 0xa4, 0x1c, 0x80, 0x21, 0x31, 0xa9,
+ 0xae, 0x60, 0x7a, 0x80, 0x26, 0x48, 0x00, 0xb8, 0x01, 0xc0, 0x93, 0x63, 0x55, 0x22, 0x91, 0x3c,
+ 0x56, 0xe7, 0xaf, 0xdb, 0x3a, 0x25, 0xf3, 0x8f, 0x31, 0x54, 0xea, 0x26, 0x8b, 0x81, 0x59, 0xf9,
+ 0xa1, 0xd1, 0x53, 0x11, 0xc5, 0x7b, 0x9d, 0x03, 0xf6, 0x74, 0x11, 0xe0, 0x6d, 0xb1, 0x2c, 0x3f,
+ 0x2c, 0x86, 0x91, 0x99, 0x71, 0x9a, 0xa6, 0x77, 0x8b, 0x34, 0x60, 0xd1, 0x14, 0xb4, 0x2c, 0xac,
+ 0x9d, 0xaf, 0x8c, 0x10, 0xd3, 0x9f, 0xc4, 0x6a, 0xf8, 0x6f, 0x13, 0xfc, 0x73, 0x59, 0xf7, 0x66,
+ 0x42, 0x74, 0x1e, 0x8a, 0xe3, 0xf8, 0xdc, 0xd2, 0x6f, 0x98, 0x9c, 0xcb, 0x47, 0x98, 0x95, 0x40,
+ 0x05, 0xfb, 0xe9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x0d, 0x30, 0x82, 0x02, 0x09,
+ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x75, 0xa8, 0x71, 0x60, 0x4c,
+ 0x88, 0x13, 0xf0, 0x78, 0xd9, 0x89, 0x77, 0xb5, 0x6d, 0xc5, 0x89, 0xdf, 0xbc, 0xb1, 0x7a, 0x30,
+ 0x81, 0xa3, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0x9b, 0x30, 0x81, 0x98, 0x80, 0x14, 0x16,
+ 0xb5, 0x32, 0x1b, 0xd4, 0xc7, 0xf3, 0xe0, 0xe6, 0x8e, 0xf3, 0xbd, 0xd2, 0xb0, 0x3a, 0xee, 0xb2,
+ 0x39, 0x18, 0xd1, 0xa1, 0x7d, 0xa4, 0x7b, 0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06,
+ 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+ 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06,
+ 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69,
+ 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
+ 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12,
+ 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f,
+ 0x72, 0x67, 0x82, 0x01, 0x00, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+ 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x5d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x01, 0x01, 0x04, 0x51, 0x30, 0x4f, 0x30, 0x23, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e,
+ 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x30, 0x28, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+ 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x63,
+ 0x61, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x4a, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x43, 0x30, 0x41,
+ 0x30, 0x3f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0x90, 0x4a, 0x30, 0x33, 0x30, 0x31,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x25, 0x68, 0x74, 0x74, 0x70,
+ 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72,
+ 0x67, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x70, 0x68, 0x70, 0x3f, 0x69, 0x64, 0x3d, 0x31,
+ 0x30, 0x30, 0x34, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x08, 0x04, 0x27,
+ 0x16, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41, 0x63,
+ 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x70, 0x68,
+ 0x70, 0x3f, 0x69, 0x64, 0x3d, 0x31, 0x30, 0x30, 0x50, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86,
+ 0xf8, 0x42, 0x01, 0x0d, 0x04, 0x43, 0x16, 0x41, 0x54, 0x6f, 0x20, 0x67, 0x65, 0x74, 0x20, 0x79,
+ 0x6f, 0x75, 0x72, 0x20, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x46, 0x52, 0x45, 0x45, 0x2c, 0x20, 0x67, 0x6f,
+ 0x20, 0x74, 0x6f, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43,
+ 0x41, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x29, 0x28, 0x85,
+ 0xae, 0x44, 0xa9, 0xb9, 0xaf, 0xa4, 0x79, 0x13, 0xf0, 0xa8, 0xa3, 0x2b, 0x97, 0x60, 0xf3, 0x5c,
+ 0xee, 0xe3, 0x2f, 0xc1, 0xf6, 0xe2, 0x66, 0xa0, 0x11, 0xae, 0x36, 0x37, 0x3a, 0x76, 0x15, 0x04,
+ 0x53, 0xea, 0x42, 0xf5, 0xf9, 0xea, 0xc0, 0x15, 0xd8, 0xa6, 0x82, 0xd9, 0xe4, 0x61, 0xae, 0x72,
+ 0x0b, 0x29, 0x5c, 0x90, 0x43, 0xe8, 0x41, 0xb2, 0xe1, 0x77, 0xdb, 0x02, 0x13, 0x44, 0x78, 0x47,
+ 0x55, 0xaf, 0x58, 0xfc, 0xcc, 0x98, 0xf6, 0x45, 0xb9, 0xd1, 0x20, 0xf8, 0xd8, 0x21, 0x07, 0xfe,
+ 0x6d, 0xaa, 0x73, 0xd4, 0xb3, 0xc6, 0x07, 0xe9, 0x09, 0x85, 0xcc, 0x3b, 0xf2, 0xb6, 0xbe, 0x2c,
+ 0x1c, 0x25, 0xd5, 0x71, 0x8c, 0x39, 0xb5, 0x2e, 0xea, 0xbe, 0x18, 0x81, 0xba, 0xb0, 0x93, 0xb8,
+ 0x0f, 0xe3, 0xe6, 0xd7, 0x26, 0x8c, 0x31, 0x5a, 0x72, 0x03, 0x84, 0x52, 0xe6, 0xa6, 0xf5, 0x33,
+ 0x22, 0x45, 0x0a, 0xc8, 0x0b, 0x0d, 0x8a, 0xb8, 0x36, 0x6f, 0x90, 0x09, 0xa1, 0xab, 0xbd, 0xd7,
+ 0xd5, 0x4e, 0x2e, 0x71, 0xa2, 0xd4, 0xae, 0xfa, 0xa7, 0x54, 0x2b, 0xeb, 0x35, 0x8d, 0x5a, 0xb7,
+ 0x54, 0x88, 0x2f, 0xee, 0x74, 0x9f, 0xed, 0x48, 0x16, 0xca, 0x0d, 0x48, 0xd0, 0x94, 0xd3, 0xac,
+ 0xa4, 0xa2, 0xf6, 0x24, 0xdf, 0x92, 0xe3, 0xbd, 0xeb, 0x43, 0x40, 0x91, 0x6e, 0x1c, 0x18, 0x8e,
+ 0x56, 0xb4, 0x82, 0x12, 0xf3, 0xa9, 0x93, 0x9f, 0xd4, 0xbc, 0x9c, 0xad, 0x9c, 0x75, 0xee, 0x5a,
+ 0x97, 0x1b, 0x95, 0xe7, 0x74, 0x2d, 0x1c, 0x0f, 0xb0, 0x2c, 0x97, 0x9f, 0xfb, 0xa9, 0x33, 0x39,
+ 0x7a, 0xe7, 0x03, 0x3a, 0x92, 0x8e, 0x22, 0xf6, 0x8c, 0x0d, 0xe4, 0xd9, 0x7e, 0x0d, 0x76, 0x18,
+ 0xf7, 0x01, 0xf9, 0xef, 0x96, 0x96, 0xa2, 0x55, 0x73, 0xc0, 0x3c, 0x71, 0xb4, 0x1d, 0x1a, 0x56,
+ 0x43, 0xb7, 0xc3, 0x0a, 0x8d, 0x72, 0xfc, 0xe2, 0x10, 0x09, 0x0b, 0x41, 0xce, 0x8c, 0x94, 0xa0,
+ 0xf9, 0x03, 0xfd, 0x71, 0x73, 0x4b, 0x8a, 0x57, 0x33, 0xe5, 0x8e, 0x74, 0x7e, 0x15, 0x01, 0x00,
+ 0xe6, 0xcc, 0x4a, 0x1c, 0xe7, 0x7f, 0x95, 0x19, 0x2d, 0xc5, 0xa5, 0x0c, 0x8b, 0xbb, 0xb5, 0xed,
+ 0x85, 0xb3, 0x5c, 0xd3, 0xdf, 0xb8, 0xb9, 0xf2, 0xca, 0xc7, 0x0d, 0x01, 0x14, 0xac, 0x70, 0x58,
+ 0xc5, 0x8c, 0x8d, 0x33, 0xd4, 0x9d, 0x66, 0xa3, 0x1a, 0x50, 0x95, 0x23, 0xfc, 0x48, 0xe0, 0x06,
+ 0x43, 0x12, 0xd9, 0xcd, 0xa7, 0x86, 0x39, 0x2f, 0x36, 0x72, 0xa3, 0x80, 0x10, 0xe4, 0xe1, 0xf3,
+ 0xd1, 0xcb, 0x5b, 0x1a, 0xc0, 0xe4, 0x80, 0x9a, 0x7c, 0x13, 0x73, 0x06, 0x4f, 0xdb, 0xa3, 0x6b,
+ 0x24, 0x0a, 0xba, 0xb3, 0x1c, 0xbc, 0x4a, 0x78, 0xbb, 0xe5, 0xe3, 0x75, 0x38, 0xa5, 0x48, 0xa7,
+ 0xa2, 0x1e, 0xaf, 0x76, 0xd4, 0x5e, 0xf7, 0x38, 0x86, 0x56, 0x5a, 0x89, 0xce, 0xd6, 0xc3, 0xa7,
+ 0x79, 0xb2, 0x52, 0xa0, 0xc6, 0xf1, 0x85, 0xb4, 0x25, 0x8c, 0xf2, 0x3f, 0x96, 0xb3, 0x10, 0xd9,
+ 0x8d, 0x6c, 0x57, 0x3b, 0x9f, 0x6f, 0x86, 0x3a, 0x18, 0x82, 0x22, 0x36, 0xc8, 0xb0, 0x91, 0x38,
+ 0xdb, 0x2a, 0xa1, 0x93, 0xaa, 0x84, 0x3f, 0xf5, 0x27, 0x65, 0xae, 0x73, 0xd5, 0xc8, 0xd5, 0xd3,
+ 0x77, 0xea, 0x4b, 0x9d, 0xc7, 0x41, 0xbb, 0xc7, 0xc0, 0xe3, 0xa0, 0x3f, 0xe4, 0x7d, 0xa4, 0x8d,
+ 0x73, 0xe6, 0x12, 0x4b, 0xdf, 0xa1, 0x73, 0x73, 0x73, 0x3a, 0x80, 0xe8, 0xd5, 0xcb, 0x8e, 0x2f,
+ 0xcb, 0xea, 0x13, 0xa7, 0xd6, 0x41, 0x8b, 0xac, 0xfa, 0x3c, 0x89, 0xd7, 0x24, 0xf5, 0x4e, 0xb4,
+ 0xe0, 0x61, 0x92, 0xb7, 0xf3, 0x37, 0x98, 0xc4, 0xbe, 0x96, 0xa3, 0xb7, 0x8a,
+};
+
+static const char test_cacert3_ca_subject[] = {
+ 0x30, 0x54, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x43, 0x41, 0x63,
+ 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
+ 0x0b, 0x13, 0x15, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x43, 0x41,
+ 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x13, 0x43, 0x41, 0x63, 0x65, 0x72, 0x74, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+ 0x33, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+};
+
+static const char test_cacert3_ca_issuer[] = {
+ 0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f, 0x6f,
+ 0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74,
+ 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43,
+ 0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x41,
+ 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
+ 0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67,
+};
+
+static const char test_cacert3_ca_serial[] = {
+ 0x02, 0x03, 0x0a, 0x41, 0x8a,
+};
+
+static const char test_ku_ds_and_np[] = {
+ 0x03, 0x03, 0x07, 0xc0, 0x00,
+};
+
+static const char test_ku_none[] = {
+ 0x03, 0x03, 0x07, 0x00, 0x00,
+};
+
+static const char test_ku_cert_crl_sign[] = {
+ 0x03, 0x03, 0x07, 0x06, 0x00,
+};
+
+static const char test_eku_server_and_client[] = {
+ 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x03, 0x02,
+};
+
+static const char test_eku_none[] = {
+ 0x30, 0x00,
+};
+
+static const char test_eku_client_email_and_timestamp[] = {
+ 0x30, 0x1e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06,
+ 0x01, 0x05, 0x05, 0x07, 0x03, 0x04, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x08,
+};
+
+#endif /* TEST_DATA_H_ */
diff --git a/trust/tests/test-module.c b/trust/tests/test-module.c
new file mode 100644
index 0000000..8bd8e10
--- /dev/null
+++ b/trust/tests/test-module.c
@@ -0,0 +1,331 @@
+/*
+ * 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@gnome.org>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "attrs.h"
+#include "checksum.h"
+#include "debug.h"
+#include "library.h"
+#include "pkcs11x.h"
+#include "test-data.h"
+#include "token.h"
+
+struct {
+ CK_FUNCTION_LIST *module;
+ CK_SLOT_ID slot;
+ CK_SESSION_HANDLE session;
+} test;
+
+static void
+setup (CuTest *cu)
+{
+ CK_C_INITIALIZE_ARGS args;
+ const char *anchors;
+ const char *certs;
+ char *arguments;
+ CK_ULONG count;
+ CK_RV rv;
+
+ memset (&test, 0, sizeof (test));
+
+ /* This is the entry point of the trust module, linked to this test */
+ rv = C_GetFunctionList (&test.module);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ memset (&args, 0, sizeof (args));
+ anchors = SRCDIR "/anchors:" SRCDIR "/files/cacert-ca.der";
+ certs = SRCDIR "/certificates";
+ if (asprintf (&arguments, "anchors='%s' certificates='%s'", anchors, certs) < 0)
+ CuAssertTrue (cu, false && "not reached");
+ args.pReserved = arguments;
+ args.flags = CKF_OS_LOCKING_OK;
+
+ rv = test.module->C_Initialize (&args);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ free (arguments);
+
+ count = 1;
+ rv = test.module->C_GetSlotList (CK_TRUE, &test.slot, &count);
+ CuAssertTrue (cu, rv == CKR_OK);
+ CuAssertTrue (cu, count == 1);
+
+ rv = test.module->C_OpenSession (test.slot, CKF_SERIAL_SESSION, NULL, NULL, &test.session);
+ CuAssertTrue (cu, rv == CKR_OK);
+}
+
+static void
+teardown (CuTest *cu)
+{
+ CK_RV rv;
+
+ rv = test.module->C_CloseSession (test.session);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ rv = test.module->C_Finalize (NULL);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ memset (&test, 0, sizeof (test));
+}
+
+static CK_ULONG
+find_objects (CuTest *cu,
+ CK_ATTRIBUTE *match,
+ CK_OBJECT_HANDLE *objects,
+ CK_ULONG num_objects)
+{
+ CK_RV rv;
+ CK_ULONG count;
+
+ count = p11_attrs_count (match);
+
+ rv = test.module->C_FindObjectsInit (test.session, match, count);
+ CuAssertTrue (cu, rv == CKR_OK);
+ rv = test.module->C_FindObjects (test.session, objects, num_objects, &num_objects);
+ CuAssertTrue (cu, rv == CKR_OK);
+ rv = test.module->C_FindObjectsFinal (test.session);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ return num_objects;
+}
+
+static void
+check_trust_object_equiv (CuTest *cu,
+ CK_OBJECT_HANDLE trust,
+ CK_ATTRIBUTE *cert)
+{
+ unsigned char subject[1024];
+ unsigned char issuer[1024];
+ unsigned char serial[128];
+ CK_BBOOL modifiable;
+ CK_BBOOL private;
+ CK_BBOOL token;
+ CK_RV rv;
+
+ /* The following attributes should be equivalent to the certificate */
+ CK_ATTRIBUTE equiv[] = {
+ { CKA_TOKEN, &token, sizeof (token) },
+ { CKA_PRIVATE, &private, sizeof (private) },
+ { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
+ { CKA_ISSUER, issuer, sizeof (issuer) },
+ { CKA_SUBJECT, subject, sizeof (subject) },
+ { CKA_SERIAL_NUMBER, serial, sizeof (serial) },
+ { CKA_INVALID, },
+ };
+
+ rv = test.module->C_GetAttributeValue (test.session, trust, equiv, 6);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ CuAssertTrue (cu, p11_attrs_match (cert, equiv));
+}
+
+static void
+check_trust_object_hashes (CuTest *cu,
+ CK_OBJECT_HANDLE trust,
+ CK_ATTRIBUTE *cert)
+{
+ unsigned char sha1[P11_CHECKSUM_SHA1_LENGTH];
+ unsigned char md5[P11_CHECKSUM_MD5_LENGTH];
+ unsigned char check[128];
+ CK_ATTRIBUTE *value;
+ CK_RV rv;
+
+ CK_ATTRIBUTE hashes[] = {
+ { CKA_CERT_SHA1_HASH, sha1, sizeof (sha1) },
+ { CKA_CERT_MD5_HASH, md5, sizeof (md5) },
+ { CKA_INVALID, },
+ };
+
+ rv = test.module->C_GetAttributeValue (test.session, trust, hashes, 2);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ value = p11_attrs_find (cert, CKA_VALUE);
+ CuAssertPtrNotNull (cu, value);
+
+ p11_checksum_md5 (check, value->pValue, value->ulValueLen, NULL);
+ CuAssertTrue (cu, memcmp (md5, check, sizeof (md5)) == 0);
+
+ p11_checksum_sha1 (check, value->pValue, value->ulValueLen, NULL);
+ CuAssertTrue (cu, memcmp (sha1, check, sizeof (sha1)) == 0);
+}
+
+static void
+check_has_trust_object (CuTest *cu,
+ CK_ATTRIBUTE *cert)
+{
+ CK_OBJECT_CLASS trust_object = CKO_NETSCAPE_TRUST;
+ CK_ATTRIBUTE klass = { CKA_CLASS, &trust_object, sizeof (trust_object) };
+ CK_OBJECT_HANDLE objects[2];
+ CK_ATTRIBUTE *match;
+ CK_ATTRIBUTE *attr;
+ CK_ULONG count;
+
+ attr = p11_attrs_find (cert, CKA_ID);
+ CuAssertPtrNotNull (cu, attr);
+
+ match = p11_attrs_build (NULL, &klass, attr, NULL);
+ count = find_objects (cu, match, objects, 2);
+ CuAssertIntEquals (cu, 1, count);
+
+ check_trust_object_equiv (cu, objects[0], cert);
+ check_trust_object_hashes (cu, objects[0], cert);
+}
+
+static void
+check_certificate (CuTest *cu,
+ CK_OBJECT_HANDLE handle)
+{
+ unsigned char label[4096]= { 0, };
+ CK_OBJECT_CLASS klass;
+ unsigned char value[4096];
+ unsigned char subject[1024];
+ unsigned char issuer[1024];
+ unsigned char serial[128];
+ unsigned char id[128];
+ CK_CERTIFICATE_TYPE type;
+ CK_BBOOL val;
+ CK_BYTE check[3];
+ CK_DATE start;
+ CK_DATE end;
+ CK_ULONG category;
+ CK_BBOOL modifiable;
+ CK_BBOOL private;
+ CK_BBOOL token;
+ CK_RV rv;
+
+ CK_ATTRIBUTE attrs[] = {
+ { CKA_CLASS, &klass, sizeof (klass) },
+ { CKA_TOKEN, &token, sizeof (token) },
+ { CKA_PRIVATE, &private, sizeof (private) },
+ { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
+ { CKA_VALUE, value, sizeof (value) },
+ { CKA_ISSUER, issuer, sizeof (issuer) },
+ { CKA_SUBJECT, subject, sizeof (subject) },
+ { CKA_CERTIFICATE_TYPE, &type, sizeof (type) },
+ { CKA_CERTIFICATE_CATEGORY, &category, sizeof (category) },
+ { CKA_START_DATE, &start, sizeof (start) },
+ { CKA_END_DATE, &end, sizeof (end) },
+ { CKA_SERIAL_NUMBER, serial, sizeof (serial) },
+ { CKA_CHECK_VALUE, check, sizeof (check) },
+ { CKA_ID, id, sizeof (id) },
+ { CKA_LABEL, label, sizeof (label) },
+ { CKA_INVALID, },
+ };
+
+ /* Note that we don't pass the CKA_INVALID attribute in */
+ rv = test.module->C_GetAttributeValue (test.session, handle, attrs, 15);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ /* If this is the cacert3 certificate, check its values */
+ if (memcmp (value, test_cacert3_ca_der, sizeof (test_cacert3_ca_der)) == 0) {
+ CK_BBOOL trusted;
+
+ CK_ATTRIBUTE anchor[] = {
+ { CKA_TRUSTED, &trusted, sizeof (trusted) },
+ { CKA_INVALID, },
+ };
+
+ test_check_cacert3_ca (cu, attrs, NULL);
+
+ /* Get anchor specific attributes */
+ rv = test.module->C_GetAttributeValue (test.session, handle, anchor, 1);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ /* It lives in the trusted directory */
+ if (!p11_attrs_find_bool (anchor, CKA_TRUSTED, &val))
+ CuFail (cu, "missing CKA_TRUSTED");
+ CuAssertIntEquals (cu, CK_TRUE, val);
+
+ /* Other certificates, we can't check the values */
+ } else {
+ test_check_object (cu, attrs, CKO_CERTIFICATE, NULL);
+ }
+
+ check_has_trust_object (cu, attrs);
+}
+
+static void
+test_find_certificates (CuTest *cu)
+{
+ CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
+
+ CK_ATTRIBUTE match[] = {
+ { CKA_CLASS, &klass, sizeof (klass) },
+ { CKA_INVALID, }
+ };
+
+ CK_OBJECT_HANDLE objects[16];
+ CK_ULONG count;
+ CK_ULONG i;
+
+ setup (cu);
+
+ count = find_objects (cu, match, objects, 16);
+ CuAssertIntEquals (cu, 6, count);
+
+ for (i = 0; i < count; i++)
+ check_certificate (cu, objects[i]);
+
+ teardown (cu);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ setenv ("P11_KIT_STRICT", "1", 1);
+ p11_debug_init ();
+ /* p11_message_quiet (); */
+
+ SUITE_ADD_TEST (suite, test_find_certificates);
+
+ 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/trust/tests/test-parser.c b/trust/tests/test-parser.c
new file mode 100644
index 0000000..c224669
--- /dev/null
+++ b/trust/tests/test-parser.c
@@ -0,0 +1,315 @@
+/*
+ * 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@gnome.org>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "array.h"
+#include "attrs.h"
+#include "debug.h"
+#include "library.h"
+#include "parser.h"
+#include "test-data.h"
+
+struct {
+ p11_parser *parser;
+ p11_array *objects;
+} test;
+
+static void
+setup (CuTest *cu)
+{
+ test.parser = p11_parser_new ();
+ CuAssertPtrNotNull (cu, test.parser);
+
+ test.objects = p11_array_new (p11_attrs_free);
+ CuAssertPtrNotNull (cu, test.objects);
+}
+
+static void
+teardown (CuTest *cu)
+{
+ p11_parser_free (test.parser);
+ p11_array_free (test.objects);
+ memset (&test, 0, sizeof (test));
+}
+
+static void
+on_parse_object (CK_ATTRIBUTE *attrs,
+ void *data)
+{
+ CuTest *cu = data;
+
+ CuAssertPtrNotNull (cu, attrs);
+ CuAssertTrue (cu, p11_attrs_count (attrs) > 0);
+
+ p11_array_push (test.objects, attrs);
+}
+
+static void
+test_parse_der_certificate (CuTest *cu)
+{
+ CK_ATTRIBUTE *attrs;
+ CK_ATTRIBUTE *attr;
+ int ret;
+
+ setup (cu);
+
+ ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der",
+ 0, on_parse_object, cu);
+ CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret);
+
+ /* Should have gotten certificate and a trust object */
+ CuAssertIntEquals (cu, 2, test.objects->num);
+
+ attrs = test.objects->elem[0];
+ test_check_cacert3_ca (cu, attrs, NULL);
+
+ attr = p11_attrs_find (attrs, CKA_TRUSTED);
+ CuAssertPtrEquals (cu, NULL, attr);
+
+ teardown (cu);
+}
+
+static void
+test_parse_anchor (CuTest *cu)
+{
+ CK_ATTRIBUTE *attrs;
+ CK_BBOOL val;
+ int ret;
+
+ setup (cu);
+
+ ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der",
+ P11_PARSE_FLAG_ANCHOR, on_parse_object, cu);
+ CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret);
+
+ /* Should have gotten a certificate and a trust object */
+ CuAssertIntEquals (cu, 2, test.objects->num);
+
+ attrs = test.objects->elem[0];
+ test_check_cacert3_ca (cu, attrs, NULL);
+
+ if (!p11_attrs_find_bool (attrs, CKA_TRUSTED, &val))
+ CuFail (cu, "missing CKA_TRUSTED");
+ CuAssertIntEquals (cu, CK_TRUE, val);
+
+ teardown (cu);
+}
+
+/* TODO: A certificate that uses generalTime needs testing */
+
+static void
+test_parse_no_sink (CuTest *cu)
+{
+ int ret;
+
+ setup (cu);
+
+ ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der",
+ 0, NULL, NULL);
+ CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret);
+
+ teardown (cu);
+}
+
+static void
+test_parse_invalid_file (CuTest *cu)
+{
+ int ret;
+
+ setup (cu);
+
+ ret = p11_parse_file (test.parser, "/nonexistant", 0, on_parse_object, cu);
+ CuAssertIntEquals (cu, P11_PARSE_FAILURE, ret);
+
+ teardown (cu);
+}
+
+static void
+test_parse_unrecognized (CuTest *cu)
+{
+ int ret;
+
+ setup (cu);
+
+ ret = p11_parse_file (test.parser, SRCDIR "/files/unrecognized-file.txt",
+ 0, on_parse_object, cu);
+ CuAssertIntEquals (cu, P11_PARSE_UNRECOGNIZED, ret);
+
+ teardown (cu);
+}
+
+struct {
+ const char *eku;
+ size_t length;
+ const char *expected[16];
+} extended_key_usage_fixtures[] = {
+ { test_eku_server_and_client, sizeof (test_eku_server_and_client),
+ { P11_EKU_CLIENT_AUTH, P11_EKU_SERVER_AUTH, NULL }, },
+ { test_eku_none, sizeof (test_eku_none),
+ { NULL, }, },
+ { test_eku_client_email_and_timestamp, sizeof (test_eku_client_email_and_timestamp),
+ { P11_EKU_CLIENT_AUTH, P11_EKU_EMAIL, P11_EKU_TIME_STAMPING }, },
+ { NULL },
+};
+
+static void
+test_parse_extended_key_usage (CuTest *cu)
+{
+ p11_dict *ekus;
+ int i, j;
+ int ret;
+
+ setup (cu);
+
+ for (i = 0; extended_key_usage_fixtures[i].eku != NULL; i++) {
+ ekus = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL);
+
+ ret = p11_parse_extended_key_usage (test.parser,
+ (const unsigned char *)extended_key_usage_fixtures[i].eku,
+ extended_key_usage_fixtures[i].length, ekus);
+ CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret);
+
+ for (j = 0; extended_key_usage_fixtures[i].expected[j] != NULL; j++)
+ CuAssertTrue (cu, p11_dict_get (ekus, extended_key_usage_fixtures[i].expected[j]) != NULL);
+ CuAssertIntEquals (cu, j, p11_dict_size (ekus));
+
+ p11_dict_free (ekus);
+ }
+
+ teardown (cu);
+}
+
+static void
+test_bad_extended_key_usage (CuTest *cu)
+{
+ p11_dict *ekus;
+ int ret;
+
+ setup (cu);
+
+ ekus = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, NULL);
+
+ ret = p11_parse_extended_key_usage (test.parser, (const unsigned char *)"blah", 4, ekus);
+ CuAssertIntEquals (cu, P11_PARSE_UNRECOGNIZED, ret);
+
+ p11_dict_free (ekus);
+
+ teardown (cu);
+}
+
+struct {
+ const char *ku;
+ size_t length;
+ unsigned int expected;
+} key_usage_fixtures[] = {
+ { test_ku_ds_and_np, sizeof (test_ku_ds_and_np), P11_KU_DIGITAL_SIGNATURE | P11_KU_NON_REPUDIATION },
+ { test_ku_none, sizeof (test_ku_none), 0 },
+ { test_ku_cert_crl_sign, sizeof (test_ku_cert_crl_sign), P11_KU_KEY_CERT_SIGN | P11_KU_CRL_SIGN },
+ { NULL },
+};
+
+static void
+test_parse_key_usage (CuTest *cu)
+{
+ unsigned int ku;
+ int i;
+ int ret;
+
+ setup (cu);
+
+ for (i = 0; key_usage_fixtures[i].ku != NULL; i++) {
+ ku = 0;
+
+ ret = p11_parse_key_usage (test.parser,
+ (const unsigned char *)key_usage_fixtures[i].ku,
+ key_usage_fixtures[i].length, &ku);
+ CuAssertIntEquals (cu, P11_PARSE_SUCCESS, ret);
+
+ CuAssertIntEquals (cu, key_usage_fixtures[i].expected, ku);
+ }
+
+ teardown (cu);
+}
+
+static void
+test_bad_key_usage (CuTest *cu)
+{
+ unsigned int ku;
+ int ret;
+
+ setup (cu);
+
+ ret = p11_parse_key_usage (test.parser, (const unsigned char *)"blah", 4, &ku);
+ CuAssertIntEquals (cu, P11_PARSE_UNRECOGNIZED, ret);
+
+ teardown (cu);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ setenv ("P11_KIT_STRICT", "1", 1);
+ p11_debug_init ();
+ p11_message_quiet ();
+
+ SUITE_ADD_TEST (suite, test_parse_der_certificate);
+ SUITE_ADD_TEST (suite, test_parse_anchor);
+ SUITE_ADD_TEST (suite, test_parse_no_sink);
+ SUITE_ADD_TEST (suite, test_parse_invalid_file);
+ SUITE_ADD_TEST (suite, test_parse_unrecognized);
+ SUITE_ADD_TEST (suite, test_bad_extended_key_usage);
+ SUITE_ADD_TEST (suite, test_parse_extended_key_usage);
+ SUITE_ADD_TEST (suite, test_bad_key_usage);
+ SUITE_ADD_TEST (suite, test_parse_key_usage);
+
+ 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/trust/tests/test-session.c b/trust/tests/test-session.c
new file mode 100644
index 0000000..48c9146
--- /dev/null
+++ b/trust/tests/test-session.c
@@ -0,0 +1,160 @@
+/*
+ * 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@gnome.org>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "attrs.h"
+#include "debug.h"
+#include "library.h"
+#include "session.h"
+#include "token.h"
+
+struct {
+ p11_token *token;
+ p11_session *session;
+} test;
+
+static void
+setup (CuTest *cu)
+{
+ test.token = p11_token_new ("", "");
+ CuAssertPtrNotNull (cu, test.token);
+
+ test.session = p11_session_new (test.token);
+ CuAssertPtrNotNull (cu, test.session);
+}
+
+static void
+teardown (CuTest *cu)
+{
+ p11_session_free (test.session);
+ p11_token_free (test.token);
+ memset (&test, 0, sizeof (test));
+}
+
+static void
+test_session_add_get (CuTest *cu)
+{
+ CK_ATTRIBUTE original[] = {
+ { CKA_LABEL, "yay", 3 },
+ { CKA_VALUE, "eight", 5 },
+ { CKA_INVALID }
+ };
+
+ CK_ATTRIBUTE *attrs;
+ CK_ATTRIBUTE *check;
+ CK_OBJECT_HANDLE handle;
+ CK_BBOOL token;
+
+ setup (cu);
+
+ attrs = p11_attrs_dup (original);
+ p11_session_add_object (test.session, attrs, &handle);
+
+ check = p11_session_get_object (test.session, handle, &token);
+
+ CuAssertPtrEquals (cu, attrs, check);
+ CuAssertTrue (cu, token == CK_FALSE);
+
+ check = p11_session_get_object (test.session, 1UL, &token);
+ CuAssertPtrEquals (cu, NULL, check);
+
+ teardown (cu);
+}
+
+static void
+test_session_del (CuTest *cu)
+{
+ CK_ATTRIBUTE original[] = {
+ { CKA_LABEL, "yay", 3 },
+ { CKA_VALUE, "eight", 5 },
+ { CKA_INVALID }
+ };
+
+ CK_ATTRIBUTE *attrs;
+ CK_ATTRIBUTE *check;
+ CK_OBJECT_HANDLE handle;
+ CK_BBOOL token;
+ CK_RV rv;
+
+ setup (cu);
+
+ attrs = p11_attrs_dup (original);
+ p11_session_add_object (test.session, attrs, &handle);
+
+ check = p11_session_get_object (test.session, handle, &token);
+ CuAssertPtrEquals (cu, attrs, check);
+ CuAssertTrue (cu, token == CK_FALSE);
+
+ rv = p11_session_del_object (test.session, 1UL);
+ CuAssertTrue (cu, rv == CKR_OBJECT_HANDLE_INVALID);
+
+ rv = p11_session_del_object (test.session, handle);
+ CuAssertTrue (cu, rv == CKR_OK);
+
+ check = p11_session_get_object (test.session, handle, &token);
+ CuAssertPtrEquals (cu, NULL, check);
+
+ teardown (cu);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ setenv ("P11_KIT_STRICT", "1", 1);
+ p11_debug_init ();
+ p11_message_quiet ();
+
+ SUITE_ADD_TEST (suite, test_session_add_get);
+ SUITE_ADD_TEST (suite, test_session_del);
+
+ 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/trust/tests/test-token.c b/trust/tests/test-token.c
new file mode 100644
index 0000000..1d9228a
--- /dev/null
+++ b/trust/tests/test-token.c
@@ -0,0 +1,106 @@
+/*
+ * 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@gnome.org>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "attrs.h"
+#include "debug.h"
+#include "library.h"
+#include "token.h"
+
+struct {
+ p11_token *token;
+} test;
+
+static void
+setup (CuTest *cu)
+{
+ test.token = p11_token_new (SRCDIR "/anchors:" SRCDIR "/files/cacert-ca.der",
+ SRCDIR "/files/self-server.der");
+ CuAssertPtrNotNull (cu, test.token);
+}
+
+static void
+teardown (CuTest *cu)
+{
+ p11_token_free (test.token);
+ memset (&test, 0, sizeof (test));
+}
+
+static void
+test_token_load (CuTest *cu)
+{
+ p11_dict *objects;
+ int count;
+
+ setup (cu);
+
+ count = p11_token_load (test.token);
+ CuAssertIntEquals (cu, 4, count);
+
+ /* A certificate and trust object for each parsed object */
+ objects = p11_token_objects (test.token);
+ CuAssertIntEquals (cu, count * 2, p11_dict_size (objects));
+
+ teardown (cu);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ setenv ("P11_KIT_STRICT", "1", 1);
+ p11_debug_init ();
+ p11_message_quiet ();
+
+ SUITE_ADD_TEST (suite, test_token_load);
+
+ 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/trust/token.c b/trust/token.c
new file mode 100644
index 0000000..8a607f0
--- /dev/null
+++ b/trust/token.c
@@ -0,0 +1,256 @@
+/*
+ * 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 "attrs.h"
+#include "compat.h"
+#include "debug.h"
+#include "errno.h"
+#include "library.h"
+#include "module.h"
+#include "parser.h"
+#include "pkcs11.h"
+#include "token.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct _p11_token {
+ p11_parser *parser;
+ p11_dict *objects;
+ const char *anchor_paths;
+ const char *other_paths;
+ const char *certificate_paths;
+ int loaded;
+};
+
+static void
+on_parser_object (CK_ATTRIBUTE *attrs,
+ void *user_data)
+{
+ CK_OBJECT_HANDLE object;
+ CK_OBJECT_HANDLE *key;
+ p11_token *token = user_data;
+
+ object = p11_module_next_id ();
+
+ key = memdup (&object, sizeof (object));
+ return_if_fail (key != NULL);
+
+ if (!p11_dict_set (token->objects, key, attrs))
+ return_if_reached ();
+}
+
+static int
+loader_load_file (p11_token *token,
+ const char *filename,
+ struct stat *sb,
+ int flags)
+{
+ int ret;
+
+ ret = p11_parse_file (token->parser, filename, flags,
+ on_parser_object, token);
+
+ return ret == P11_PARSE_SUCCESS ? 1 : 0;
+}
+
+static int
+loader_load_directory (p11_token *token,
+ const char *directory,
+ int flags)
+{
+ struct dirent *dp;
+ struct stat sb;
+ char *path;
+ int total = 0;
+ int ret;
+ DIR *dir;
+
+ /* First we load all the modules */
+ dir = opendir (directory);
+ if (!dir) {
+ p11_message ("couldn't list directory: %s: %s",
+ directory, strerror (errno));
+ return 0;
+ }
+
+ /* We're within a global mutex, so readdir is safe */
+ while ((dp = readdir (dir)) != NULL) {
+ path = strconcat (directory, "/", dp->d_name, NULL);
+ return_val_if_fail (path != NULL, -1);
+
+ if (stat (path, &sb) < 0) {
+ p11_message ("couldn't stat path: %s", path);
+
+ } else if (!S_ISDIR (sb.st_mode)) {
+ ret = loader_load_file (token, path, &sb, flags);
+ return_val_if_fail (ret > 0, ret);
+ total += ret;
+ }
+
+ free (path);
+ }
+
+ closedir (dir);
+ return total;
+}
+
+static int
+loader_load_path (p11_token *token,
+ const char *path,
+ int flags)
+{
+ struct stat sb;
+
+ if (stat (path, &sb) < 0) {
+ if (errno == ENOENT) {
+ p11_message ("trust certificate path does not exist: %s",
+ path);
+ } else {
+ p11_message ("cannot access trust certificate path: %s: %s",
+ path, strerror (errno));
+ }
+
+ return 0;
+ }
+
+ if (S_ISDIR (sb.st_mode))
+ return loader_load_directory (token, path, flags);
+ else
+ return loader_load_file (token, path, &sb, flags);
+}
+
+static int
+loader_load_paths (p11_token *token,
+ const char *paths,
+ int flags)
+{
+ const char *pos;
+ int total = 0;
+ char *path;
+ int ret;
+
+ while (paths) {
+ pos = strchr (paths, ':');
+ if (pos == NULL) {
+ path = strdup (paths);
+ paths = NULL;
+ } else {
+ path = strndup (paths, pos - paths);
+ paths = pos + 1;
+ }
+
+ return_val_if_fail (path != NULL, -1);
+
+ if (path[0] != '\0') {
+ /* We don't expect this to fail except for in strange circumstances */
+ ret = loader_load_path (token, path, flags);
+ if (ret < 0)
+ return_val_if_reached (-1);
+ total += ret;
+ }
+
+ free (path);
+ }
+
+ return total;
+}
+
+int
+p11_token_load (p11_token *token)
+{
+ int anchors;
+ int other;
+
+ if (token->loaded)
+ return 0;
+ token->loaded = 1;
+
+ anchors = loader_load_paths (token, token->anchor_paths, P11_PARSE_FLAG_ANCHOR);
+ if (anchors < 0)
+ return anchors;
+
+ other = loader_load_paths (token, token->other_paths, P11_PARSE_FLAG_NONE);
+ if (other < 0)
+ return other;
+
+ return anchors + other;
+}
+
+p11_dict *
+p11_token_objects (p11_token *token)
+{
+ return token->objects;
+}
+
+void
+p11_token_free (p11_token *token)
+{
+ if (!token)
+ return;
+
+ p11_dict_free (token->objects);
+ p11_parser_free (token->parser);
+ free (token);
+}
+
+p11_token *
+p11_token_new (const char *anchor_paths,
+ const char *other_paths)
+{
+ p11_token *token;
+
+ token = calloc (1, sizeof (p11_token));
+ return_val_if_fail (token != NULL, NULL);
+
+ token->parser = p11_parser_new ();
+ return_val_if_fail (token->parser != NULL, NULL);
+
+ token->objects = p11_dict_new (p11_dict_ulongptr_hash,
+ p11_dict_ulongptr_equal,
+ free, p11_attrs_free);
+ return_val_if_fail (token->objects != NULL, NULL);
+
+ token->anchor_paths = anchor_paths;
+ token->other_paths = other_paths;
+ token->loaded = 0;
+
+ return token;
+}
diff --git a/trust/token.h b/trust/token.h
new file mode 100644
index 0000000..1152a68
--- /dev/null
+++ b/trust/token.h
@@ -0,0 +1,51 @@
+/*
+ * 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>
+ */
+
+#ifndef P11_TOKEN_H_
+#define P11_TOKEN_H_
+
+#include "dict.h"
+
+typedef struct _p11_token p11_token;
+
+p11_token * p11_token_new (const char *anchor_paths,
+ const char *other_paths);
+
+void p11_token_free (p11_token *token);
+
+int p11_token_load (p11_token *token);
+
+p11_dict * p11_token_objects (p11_token *token);
+
+#endif /* P11_TOKEN_H_ */