diff options
Diffstat (limited to 'trust')
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 Binary files differnew file mode 100644 index 0000000..56f8c88 --- /dev/null +++ b/trust/tests/anchors/cacert3.der diff --git a/trust/tests/anchors/testing-ca.der b/trust/tests/anchors/testing-ca.der Binary files differnew file mode 100644 index 0000000..d3f70ea --- /dev/null +++ b/trust/tests/anchors/testing-ca.der diff --git a/trust/tests/certificates/cacert-ca.der b/trust/tests/certificates/cacert-ca.der Binary files differnew file mode 100644 index 0000000..719b0ff --- /dev/null +++ b/trust/tests/certificates/cacert-ca.der diff --git a/trust/tests/certificates/self-signed-with-eku.der b/trust/tests/certificates/self-signed-with-eku.der Binary files differnew file mode 100644 index 0000000..33e0760 --- /dev/null +++ b/trust/tests/certificates/self-signed-with-eku.der diff --git a/trust/tests/certificates/self-signed-with-ku.der b/trust/tests/certificates/self-signed-with-ku.der Binary files differnew file mode 100644 index 0000000..e6f36e3 --- /dev/null +++ b/trust/tests/certificates/self-signed-with-ku.der diff --git a/trust/tests/files/cacert-ca.der b/trust/tests/files/cacert-ca.der Binary files differnew file mode 100644 index 0000000..719b0ff --- /dev/null +++ b/trust/tests/files/cacert-ca.der diff --git a/trust/tests/files/cacert3.der b/trust/tests/files/cacert3.der Binary files differnew file mode 100644 index 0000000..56f8c88 --- /dev/null +++ b/trust/tests/files/cacert3.der diff --git a/trust/tests/files/self-server.der b/trust/tests/files/self-server.der Binary files differnew file mode 100644 index 0000000..68fe9af --- /dev/null +++ b/trust/tests/files/self-server.der diff --git a/trust/tests/files/testing-server.der b/trust/tests/files/testing-server.der Binary files differnew file mode 100644 index 0000000..cf2de65 --- /dev/null +++ b/trust/tests/files/testing-server.der 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_ */ |