/*
* 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>
*/
#define CRYPTOKI_EXPORTS
#include "config.h"
#include "test.h"
#include "test-trust.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "attrs.h"
#include "digest.h"
#include "library.h"
#include "path.h"
#include "parser.h"
#include "pkcs11x.h"
#include "token.h"
#include <assert.h>
/*
* This is the number of input paths. Should match the
* paths below near :
*
* paths='%s'
*/
#define NUM_SLOTS 3
static CK_OBJECT_CLASS data = CKO_DATA;
static CK_BBOOL vtrue = CK_TRUE;
static CK_BBOOL vfalse = CK_FALSE;
struct {
CK_FUNCTION_LIST *module;
CK_SLOT_ID slots[NUM_SLOTS];
char *directory;
p11_asn1_cache *cache;
p11_parser *parser;
char *unreadable;
} test;
static void
setup (void *unused)
{
CK_C_INITIALIZE_ARGS args;
const char *paths;
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);
assert (rv == CKR_OK);
memset (&args, 0, sizeof (args));
paths = SRCDIR "/trust/input" P11_PATH_SEP \
SRCDIR "/trust/fixtures/self-signed-with-ku.der" P11_PATH_SEP \
SRCDIR "/trust/fixtures/thawte.pem";
if (asprintf (&arguments, "paths='%s'", paths) < 0)
assert (false && "not reached");
args.pReserved = arguments;
args.flags = CKF_OS_LOCKING_OK;
rv = test.module->C_Initialize (&args);
assert (rv == CKR_OK);
free (arguments);
count = NUM_SLOTS;
rv = test.module->C_GetSlotList (CK_TRUE, test.slots, &count);
assert (rv == CKR_OK);
assert (count == NUM_SLOTS);
}
static void
teardown (void *unused)
{
CK_RV rv;
if (test.parser)
p11_parser_free (test.parser);
p11_asn1_cache_free (test.cache);
rv = test.module->C_Finalize (NULL);
assert (rv == CKR_OK);
if (test.unreadable)
chmod (test.unreadable, 0644);
free (test.unreadable);
if (test.directory)
p11_test_directory_delete (test.directory);
free (test.directory);
memset (&test, 0, sizeof (test));
}
static void
setup_writable (void *unused)
{
CK_C_INITIALIZE_ARGS args;
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);
assert (rv == CKR_OK);
test.directory = p11_test_directory ("test-module");
memset (&args, 0, sizeof (args));
if (asprintf (&arguments, "paths='%s'", test.directory) < 0)
assert (false && "not reached");
args.pReserved = arguments;
args.flags = CKF_OS_LOCKING_OK;
rv = test.module->C_Initialize (&args);
assert (rv == CKR_OK);
free (arguments);
count = 1;
rv = test.module->C_GetSlotList (CK_TRUE, test.slots, &count);
assert_num_eq (rv, CKR_OK);
assert_num_eq (count, 1);
test.cache = p11_asn1_cache_new ();
test.parser = p11_parser_new (test.cache);
p11_parser_formats (test.parser, p11_parser_format_persist, NULL);
}
/* This is similar to setup(), but it adds an unreadable content in
* the anchor directory. */
static void
setup_unreadable (void *unused)
{
CK_C_INITIALIZE_ARGS args;
const char *paths;
char *p, *anchors;
FILE *f, *ff;
char buffer[4096];
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);
assert (rv == CKR_OK);
test.directory = p11_test_directory ("test-module");
anchors = p11_path_build (test.directory, "anchors", NULL);
#ifdef OS_UNIX
if (mkdir (anchors, S_IRWXU) < 0)
#else
if (mkdir (anchors) < 0)
#endif
assert_fail ("mkdir()", anchors);
test.unreadable = p11_path_build (anchors, "unreadable", NULL);
f = fopen (test.unreadable, "w");
fwrite ("foo", 3, 1, f);
fclose (f);
chmod (test.unreadable, 0);
p = p11_path_build (anchors, "thawte", NULL);
ff = fopen (p, "w");
f = fopen (SRCDIR "/trust/fixtures/thawte.pem", "r");
while (!feof (f)) {
size_t size;
size = fread (buffer, 1, sizeof (buffer), f);
if (ferror (f))
assert_fail ("fread()",
SRCDIR "/trust/fixtures/thawte.pem");
fwrite (buffer, 1, size, ff);
if (ferror (ff))
assert_fail ("write()", p);
}
free (p);
fclose (ff);
fclose (f);
free (anchors);
memset (&args, 0, sizeof (args));
paths = SRCDIR "/trust/input" P11_PATH_SEP \
SRCDIR "/trust/fixtures/self-signed-with-ku.der";
if (asprintf (&arguments, "paths='%s%c%s'",
paths, P11_PATH_SEP_C, test.directory) < 0)
assert (false && "not reached");
args.pReserved = arguments;
args.flags = CKF_OS_LOCKING_OK;
rv = test.module->C_Initialize (&args);
assert (rv == CKR_OK);
free (arguments);
count = NUM_SLOTS;
rv = test.module->C_GetSlotList (CK_TRUE, test.slots, &count);
assert (rv == CKR_OK);
assert (count == NUM_SLOTS);
}
static void
test_get_slot_list (void)
{
CK_SLOT_ID slots[NUM_SLOTS];
CK_ULONG count;
CK_RV rv;
int i;
rv = test.module->C_GetSlotList (TRUE, NULL, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (NUM_SLOTS, count);
count = 1;
rv = test.module->C_GetSlotList (TRUE, slots, &count);
assert_num_eq (CKR_BUFFER_TOO_SMALL, rv);
assert_num_eq (NUM_SLOTS, count);
count = NUM_SLOTS;
memset (slots, 0, sizeof (slots));
rv = test.module->C_GetSlotList (TRUE, slots, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (NUM_SLOTS, count);
for (i = 0; i < NUM_SLOTS; i++)
assert (slots[i] != 0);
}
static void
test_null_initialize (void)
{
CK_FUNCTION_LIST *module;
CK_RV rv;
/* This is the entry point of the trust module, linked to this test */
rv = C_GetFunctionList (&module);
assert_num_eq (rv, CKR_OK);
rv = module->C_Initialize (NULL);
assert_num_eq (rv, CKR_OK);
rv = module->C_Finalize (NULL);
assert_num_eq (CKR_OK, rv);
}
static void
test_multi_initialize (void)
{
static CK_C_INITIALIZE_ARGS args =
{ NULL, NULL, NULL, NULL, CKF_OS_LOCKING_OK, NULL, };
CK_FUNCTION_LIST *module;
CK_SESSION_HANDLE session;
CK_SLOT_ID slots[8];
CK_SESSION_INFO info;
CK_ULONG count;
CK_RV rv;
/* This is the entry point of the trust module, linked to this test */
rv = C_GetFunctionList (&module);
assert_num_eq (rv, CKR_OK);
args.pReserved = "paths='" SYSCONFDIR "/trust/input'";
rv = module->C_Initialize (&args);
assert_num_eq (rv, CKR_OK);
count = 8;
rv = module->C_GetSlotList (CK_TRUE, slots, &count);
assert_num_eq (rv, CKR_OK);
assert_num_cmp (count, ==, 1);
rv = module->C_OpenSession (slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert_num_eq (rv, CKR_OK);
rv = module->C_GetSessionInfo (session, &info);
assert_num_eq (rv, CKR_OK);
assert_num_eq (info.slotID, slots[0]);
rv = module->C_Initialize (&args);
assert_num_eq (rv, CKR_OK);
rv = module->C_GetSessionInfo (session, &info);
assert_num_eq (rv, CKR_OK);
assert_num_eq (info.slotID, slots[0]);
rv = module->C_Finalize (NULL);
assert_num_eq (CKR_OK, rv);
rv = module->C_Finalize (NULL);
assert_num_eq (CKR_OK, rv);
rv = module->C_Finalize (NULL);
assert_num_eq (CKR_CRYPTOKI_NOT_INITIALIZED, rv);
}
static void
test_get_slot_info (void)
{
CK_SLOT_ID slots[NUM_SLOTS];
CK_SLOT_INFO info;
char description[64];
CK_ULONG count;
size_t length;
CK_RV rv;
int i;
/* These are the paths passed in in setup() */
const char *paths[] = {
SRCDIR "/trust/input",
SRCDIR "/trust/fixtures/self-signed-with-ku.der",
SRCDIR "/trust/fixtures/thawte.pem"
};
count = NUM_SLOTS;
rv = test.module->C_GetSlotList (TRUE, slots, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (NUM_SLOTS, count);
for (i = 0; i < NUM_SLOTS; i++) {
rv = test.module->C_GetSlotInfo (slots[i], &info);
assert_num_eq (CKR_OK, rv);
memset (description, ' ', sizeof (description));
length = strlen(paths[i]);
if (length > sizeof (description))
length = sizeof (description);
memcpy (description, paths[i], length);
assert (memcmp (info.slotDescription, description, sizeof (description)) == 0);
}
}
static void
test_get_token_info (void)
{
CK_C_INITIALIZE_ARGS args;
CK_FUNCTION_LIST *module;
CK_SLOT_ID slots[NUM_SLOTS];
CK_TOKEN_INFO info;
char label[32];
CK_ULONG count;
CK_RV rv;
int i;
/* These are the paths passed in in setup() */
const char *labels[] = {
"System Trust",
"Default Trust",
"the-basename",
};
/* This is the entry point of the trust module, linked to this test */
rv = C_GetFunctionList (&module);
assert (rv == CKR_OK);
memset (&args, 0, sizeof (args));
args.pReserved = "paths='" \
P11_SYSTEM_TRUST_PREFIX "/trust/input" P11_PATH_SEP \
P11_DEFAULT_TRUST_PREFIX "/trust/fixtures/blah" P11_PATH_SEP \
"/some/other/path/the-basename'";
args.flags = CKF_OS_LOCKING_OK;
rv = module->C_Initialize (&args);
assert (rv == CKR_OK);
count = NUM_SLOTS;
rv = module->C_GetSlotList (CK_TRUE, slots, &count);
assert (rv == CKR_OK);
assert (count == NUM_SLOTS);
for (i = 0; i < NUM_SLOTS; i++) {
rv = module->C_GetTokenInfo (slots[i], &info);
assert_num_eq (CKR_OK, rv);
memset (label, ' ', sizeof (label));
memcpy (label, labels[i], strlen (labels[i]));
assert (memcmp (info.label, label, sizeof (label)) == 0);
}
rv = module->C_Finalize (NULL);
assert_num_eq (CKR_OK, rv);
}
static void
test_get_session_info (void)
{
CK_SLOT_ID slots[NUM_SLOTS];
CK_SESSION_HANDLE sessions[NUM_SLOTS];
CK_SESSION_INFO info;
CK_ULONG count;
CK_RV rv;
int i;
count = NUM_SLOTS;
rv = test.module->C_GetSlotList (TRUE, slots, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (NUM_SLOTS, count);
/* Open two sessions with each token */
for (i = 0; i < NUM_SLOTS; i++) {
rv = test.module->C_OpenSession (slots[i], CKF_SERIAL_SESSION, NULL, NULL, &sessions[i]);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_GetSessionInfo (sessions[i], &info);
assert_num_eq (CKR_OK, rv);
assert_num_eq (slots[i], info.slotID);
assert_num_eq (CKF_SERIAL_SESSION, info.flags);
}
}
static void
test_close_all_sessions (void)
{
CK_SLOT_ID slots[NUM_SLOTS];
CK_SESSION_HANDLE sessions[NUM_SLOTS][2];
CK_SESSION_INFO info;
CK_ULONG count;
CK_RV rv;
int i;
count = NUM_SLOTS;
rv = test.module->C_GetSlotList (TRUE, slots, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (NUM_SLOTS, count);
/* Open two sessions with each token */
for (i = 0; i < NUM_SLOTS; i++) {
rv = test.module->C_OpenSession (slots[i], CKF_SERIAL_SESSION, NULL, NULL, &sessions[i][0]);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_GetSessionInfo (sessions[i][0], &info);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_OpenSession (slots[i], CKF_SERIAL_SESSION, NULL, NULL, &sessions[i][1]);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_GetSessionInfo (sessions[i][0], &info);
assert_num_eq (CKR_OK, rv);
}
/* Close all the sessions on the first token */
rv = test.module->C_CloseAllSessions (slots[0]);
assert_num_eq (CKR_OK, rv);
/* Those sessions should be closed */
rv = test.module->C_GetSessionInfo (sessions[0][0], &info);
assert_num_eq (CKR_SESSION_HANDLE_INVALID, rv);
rv = test.module->C_GetSessionInfo (sessions[0][1], &info);
assert_num_eq (CKR_SESSION_HANDLE_INVALID, rv);
/* Other sessions should still be open */
for (i = 1; i < NUM_SLOTS; i++) {
rv = test.module->C_GetSessionInfo (sessions[i][0], &info);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_GetSessionInfo (sessions[i][0], &info);
assert_num_eq (CKR_OK, rv);
}
}
static CK_ULONG
find_objects (CK_ATTRIBUTE *match,
CK_OBJECT_HANDLE *sessions,
CK_OBJECT_HANDLE *objects,
CK_ULONG max_objects)
{
CK_SESSION_HANDLE session;
CK_RV rv;
CK_ULONG found;
CK_ULONG count;
int i, j;
found = 0;
for (i = 0; i < NUM_SLOTS; i++) {
rv = test.module->C_OpenSession (test.slots[i], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert (rv == CKR_OK);
rv = test.module->C_FindObjectsInit (session, match, p11_attrs_count (match));
assert (rv == CKR_OK);
rv = test.module->C_FindObjects (session, objects + found, max_objects - found, &count);
assert (rv == CKR_OK);
rv = test.module->C_FindObjectsFinal (session);
assert (rv == CKR_OK);
for (j = found ; j < found + count; j++)
sessions[j] = session;
found += count;
}
assert (found < max_objects);
return found;
}
static void
check_trust_object_equiv (CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE trust,
CK_ATTRIBUTE *cert)
{
unsigned char subject[1024];
unsigned char issuer[1024];
unsigned char serial[128];
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_ISSUER, issuer, sizeof (issuer) },
{ CKA_SUBJECT, subject, sizeof (subject) },
{ CKA_SERIAL_NUMBER, serial, sizeof (serial) },
{ CKA_INVALID, },
};
rv = test.module->C_GetAttributeValue (session, trust, equiv, 5);
assert_num_eq (CKR_OK, rv);
test_check_attrs (equiv, cert);
}
static void
check_trust_object_hashes (CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE trust,
CK_ATTRIBUTE *cert)
{
unsigned char sha1[P11_DIGEST_SHA1_LEN];
unsigned char md5[P11_DIGEST_MD5_LEN];
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 (session, trust, hashes, 2);
assert (rv == CKR_OK);
value = p11_attrs_find_valid (cert, CKA_VALUE);
assert_ptr_not_null (value);
p11_digest_md5 (check, value->pValue, value->ulValueLen, NULL);
assert (memcmp (md5, check, sizeof (md5)) == 0);
p11_digest_sha1 (check, value->pValue, value->ulValueLen, NULL);
assert (memcmp (sha1, check, sizeof (sha1)) == 0);
}
static void
check_has_trust_object (CK_ATTRIBUTE *cert)
{
CK_OBJECT_CLASS trust_object = CKO_NSS_TRUST;
CK_ATTRIBUTE klass = { CKA_CLASS, &trust_object, sizeof (trust_object) };
CK_OBJECT_HANDLE objects[2];
CK_SESSION_HANDLE sessions[2];
CK_ATTRIBUTE *match;
CK_ATTRIBUTE *attr;
CK_ULONG count;
attr = p11_attrs_find_valid (cert, CKA_ID);
assert_ptr_not_null (attr);
match = p11_attrs_build (NULL, &klass, attr, NULL);
count = find_objects (match, sessions, objects, 2);
assert_num_eq (1, count);
check_trust_object_equiv (sessions[0], objects[0], cert);
check_trust_object_hashes (sessions[0], objects[0], cert);
p11_attrs_free (match);
}
static void
check_certificate (CK_SESSION_HANDLE session,
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_BYTE check[3];
CK_DATE start;
CK_DATE end;
CK_ULONG category;
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_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 (session, handle, attrs, 14);
assert_num_eq (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_BBOOL vtrue = CK_TRUE;
CK_ATTRIBUTE anchor[] = {
{ CKA_TRUSTED, &trusted, sizeof (trusted) },
{ CKA_INVALID, },
};
CK_ATTRIBUTE check[] = {
{ CKA_TRUSTED, &vtrue, sizeof (vtrue) },
{ CKA_INVALID, },
};
test_check_cacert3_ca (attrs, NULL);
/* Get anchor specific attributes */
rv = test.module->C_GetAttributeValue (session, handle, anchor, 1);
assert (rv == CKR_OK);
/* It lives in the trusted directory */
test_check_attrs (check, anchor);
/* Other certificates, we can't check the values */
} else {
test_check_object (attrs, CKO_CERTIFICATE, NULL);
}
check_has_trust_object (attrs);
}
static void
test_find_certificates (void)
{
CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
CK_ATTRIBUTE match[] = {
{ CKA_CLASS, &klass, sizeof (klass) },
{ CKA_INVALID, }
};
CK_OBJECT_HANDLE objects[16];
CK_SESSION_HANDLE sessions[16];
CK_ULONG count;
CK_ULONG i;
count = find_objects (match, sessions, objects, 16);
assert_num_eq (9, count);
for (i = 0; i < count; i++)
check_certificate (sessions[i], objects[i]);
}
static void
test_find_extensions (void)
{
CK_OBJECT_CLASS klass = CKO_X_CERTIFICATE_EXTENSION;
unsigned char spki[] = {
0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
0x89, 0x02, 0x81, 0x81, 0x00, 0xd1, 0xb5, 0x36,
0xa3, 0x89, 0xee, 0xaa, 0x80, 0x2f, 0x53, 0xfd,
0x12, 0x75, 0x3e, 0xf3, 0x7a, 0x9e, 0xd6, 0xaf,
0xfa, 0xbc, 0x1c, 0x60, 0x10, 0x4b, 0x26, 0x81,
0x13, 0x1a, 0x59, 0xe3, 0xfe, 0x45, 0x6c, 0x38,
0x04, 0x39, 0x27, 0x46, 0x57, 0xfd, 0xd5, 0xbc,
0x8d, 0x8a, 0x10, 0xb6, 0x3b, 0xd4, 0x0a, 0x81,
0x5a, 0x45, 0x2f, 0xec, 0x3e, 0x81, 0xf0, 0xd9,
0x4e, 0x4f, 0x97, 0xdf, 0x4b, 0x32, 0x0f, 0x08,
0xb1, 0x26, 0xa2, 0xbd, 0x69, 0x61, 0x5d, 0x66,
0x39, 0x63, 0x2f, 0x10, 0x70, 0x35, 0xfb, 0x07,
0x85, 0x0a, 0xff, 0x57, 0x12, 0xc1, 0xf4, 0x83,
0x1d, 0xf9, 0xc6, 0xd3, 0xa4, 0xb6, 0x70, 0x2b,
0x80, 0xa1, 0x40, 0x7f, 0x48, 0x4e, 0xd9, 0xad,
0xeb, 0x80, 0xcc, 0xcf, 0x92, 0xc1, 0xd1, 0x83,
0x64, 0x01, 0x23, 0x47, 0x8e, 0xbd, 0x31, 0x98,
0x05, 0x6b, 0x6b, 0x7c, 0x37, 0x02, 0x03, 0x01,
0x00, 0x01
};
CK_ATTRIBUTE match[] = {
{ CKA_CLASS, &klass, sizeof (klass) },
{ CKA_PUBLIC_KEY_INFO, spki, sizeof (spki) },
{ CKA_INVALID, }
};
CK_OBJECT_HANDLE objects[16];
CK_SESSION_HANDLE sessions[16];
CK_ULONG count;
count = find_objects (match, sessions, objects, 16);
assert_num_eq (1, count);
}
static void
test_find_builtin (void)
{
CK_OBJECT_CLASS klass = CKO_NSS_BUILTIN_ROOT_LIST;
CK_ATTRIBUTE match[] = {
{ CKA_CLASS, &klass, sizeof (klass) },
{ CKA_TOKEN, &vtrue, sizeof (vtrue) },
{ CKA_PRIVATE, &vfalse, sizeof (vfalse) },
{ CKA_MODIFIABLE, &vfalse, sizeof (vfalse) },
{ CKA_INVALID, }
};
CK_OBJECT_HANDLE objects[16];
CK_SESSION_HANDLE sessions[16];
CK_ULONG count;
/* One per token */
count = find_objects (match, sessions, objects, 16);
assert_num_eq (NUM_SLOTS, count);
}
static void
test_session_object (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_ULONG size;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert (rv == CKR_OK);
rv = test.module->C_CreateObject (session, original, 2, &handle);
assert (rv == CKR_OK);
rv = test.module->C_GetObjectSize (session, handle, &size);
assert (rv == CKR_OK);
}
static void
test_session_find (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_OBJECT_HANDLE check;
CK_ULONG count;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_CreateObject (session, original, 2, &handle);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjectsInit (session, original, 2);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjects (session, &check, 1, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (1, count);
assert_num_eq (handle, check);
rv = test.module->C_FindObjectsFinal (session);
assert_num_eq (CKR_OK, rv);
}
static void
test_session_find_no_attr (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_INVALID }
};
CK_ATTRIBUTE match[] = {
{ CKA_COLOR, "blah", 4 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_OBJECT_HANDLE check;
CK_ULONG count;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_CreateObject (session, original, 3, &handle);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjectsInit (session, match, 1);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjects (session, &check, 1, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (0, count);
rv = test.module->C_FindObjectsFinal (session);
assert_num_eq (CKR_OK, rv);
}
static void
test_lookup_invalid (void)
{
CK_SESSION_HANDLE session;
CK_ULONG size;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert (rv == CKR_OK);
rv = test.module->C_GetObjectSize (session, 88888, &size);
assert (rv == CKR_OBJECT_HANDLE_INVALID);
}
static void
test_remove_token (void)
{
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_ULONG count;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert_num_eq (rv, CKR_OK);
rv = test.module->C_FindObjectsInit (session, NULL, 0);
assert_num_eq (rv, CKR_OK);
rv = test.module->C_FindObjects (session, &handle, 1, &count);
assert_num_eq (rv, CKR_OK);
assert_num_eq (1, count);
rv = test.module->C_DestroyObject (session, handle);
if (rv != CKR_TOKEN_WRITE_PROTECTED)
assert_num_eq (rv, CKR_SESSION_READ_ONLY);
}
static void
test_setattr_token (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_ULONG count;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert_num_eq (rv, CKR_OK);
rv = test.module->C_FindObjectsInit (session, NULL, 0);
assert_num_eq (rv, CKR_OK);
rv = test.module->C_FindObjects (session, &handle, 1, &count);
assert_num_eq (rv, CKR_OK);
assert_num_eq (1, count);
rv = test.module->C_SetAttributeValue (session, handle, original, 2);
if (rv != CKR_TOKEN_WRITE_PROTECTED)
assert_num_eq (rv, CKR_ATTRIBUTE_READ_ONLY);
}
static void
test_session_copy (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_OBJECT_HANDLE copy;
CK_ULONG size;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_CreateObject (session, original, 2, &handle);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_CopyObject (session, handle, original, 2, ©);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_GetObjectSize (session, copy, &size);
assert_num_eq (CKR_OK, rv);
}
static void
test_session_setattr (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert (rv == CKR_OK);
rv = test.module->C_CreateObject (session, original, 2, &handle);
assert (rv == CKR_OK);
rv = test.module->C_SetAttributeValue (session, handle, original, 2);
assert (rv == CKR_OK);
}
static void
test_session_remove (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert (rv == CKR_OK);
rv = test.module->C_CreateObject (session, original, 2, &handle);
assert (rv == CKR_OK);
rv = test.module->C_DestroyObject (session, handle);
assert (rv == CKR_OK);
rv = test.module->C_DestroyObject (session, handle);
assert (rv == CKR_OBJECT_HANDLE_INVALID);
}
static void
test_find_serial_der_decoded (void)
{
CK_OBJECT_CLASS nss_trust = CKO_NSS_TRUST;
CK_ATTRIBUTE object[] = {
{ CKA_CLASS, &nss_trust, sizeof (nss_trust) },
{ CKA_SERIAL_NUMBER, "\x02\x03\x01\x02\x03", 5 },
{ CKA_INVALID }
};
CK_ATTRIBUTE match_decoded[] = {
{ CKA_CLASS, &nss_trust, sizeof (nss_trust) },
{ CKA_SERIAL_NUMBER, "\x01\x02\x03", 3 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_OBJECT_HANDLE check;
CK_ULONG count;
CK_RV rv;
/*
* WORKAROUND: NSS calls us asking for CKA_SERIAL_NUMBER items that are
* not DER encoded. It shouldn't be doing this. We never return any certificate
* serial numbers that are not DER encoded.
*
* So work around the issue here while the NSS guys fix this issue.
* This code should be removed in future versions.
*
* See work_around_broken_nss_serial_number_lookups().
*/
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_CreateObject (session, object, 2, &handle);
assert_num_eq (CKR_OK, rv);
/* Do a standard find for the same object */
rv = test.module->C_FindObjectsInit (session, object, 2);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjects (session, &check, 1, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (1, count);
assert_num_eq (handle, check);
rv = test.module->C_FindObjectsFinal (session);
assert_num_eq (CKR_OK, rv);
/* Do a find for the serial number decoded */
rv = test.module->C_FindObjectsInit (session, match_decoded, 2);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjects (session, &check, 1, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (1, count);
assert_num_eq (handle, check);
rv = test.module->C_FindObjectsFinal (session);
assert_num_eq (CKR_OK, rv);
}
static void
test_find_serial_der_mismatch (void)
{
CK_OBJECT_CLASS nss_trust = CKO_NSS_TRUST;
CK_ATTRIBUTE object[] = {
{ CKA_CLASS, &nss_trust, sizeof (nss_trust) },
{ CKA_SERIAL_NUMBER, "\x02\x03\x01\x02\x03", 5 },
{ CKA_INVALID }
};
CK_ATTRIBUTE match[] = {
{ CKA_SERIAL_NUMBER, NULL, 0 },
{ CKA_CLASS, &nss_trust, sizeof (nss_trust) },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_OBJECT_HANDLE check;
CK_ULONG count;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_CreateObject (session, object, 2, &handle);
assert_num_eq (CKR_OK, rv);
/* Do a find with a null serial number, no match */
rv = test.module->C_FindObjectsInit (session, match, 2);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjects (session, &check, 1, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (0, count);
rv = test.module->C_FindObjectsFinal (session);
assert_num_eq (CKR_OK, rv);
/* Do a find with a wrong length, no match */
match[0].pValue = "at";
match[0].ulValueLen = 2;
rv = test.module->C_FindObjectsInit (session, match, 2);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjects (session, &check, 1, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (0, count);
rv = test.module->C_FindObjectsFinal (session);
assert_num_eq (CKR_OK, rv);
/* Do a find with a right length, wrong value, no match */
match[0].pValue = "one";
match[0].ulValueLen = 3;
rv = test.module->C_FindObjectsInit (session, match, 2);
assert_num_eq (CKR_OK, rv);
rv = test.module->C_FindObjects (session, &check, 1, &count);
assert_num_eq (CKR_OK, rv);
assert_num_eq (0, count);
rv = test.module->C_FindObjectsFinal (session);
assert_num_eq (CKR_OK, rv);
}
static void
test_login_logout (void)
{
CK_SESSION_HANDLE session;
CK_RV rv;
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION, NULL, NULL, &session);
assert (rv == CKR_OK);
/* Just testing our stubs for now */
rv = test.module->C_Login (session, CKU_USER, NULL, 0);
assert (rv == CKR_USER_TYPE_INVALID);
rv = test.module->C_Logout (session);
assert (rv == CKR_USER_NOT_LOGGED_IN);
}
static void
test_token_writable (void)
{
CK_TOKEN_INFO info;
CK_RV rv;
rv = test.module->C_GetTokenInfo (test.slots[0], &info);
assert_num_eq (rv, CKR_OK);
assert_num_eq (info.flags & CKF_WRITE_PROTECTED, 0);
}
static void
test_session_read_only_create (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_TOKEN, &vtrue, sizeof (vtrue) },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
CK_RV rv;
/* Read-only session */
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION,
NULL, NULL, &session);
assert (rv == CKR_OK);
/* Create a token object */
rv = test.module->C_CreateObject (session, original, 4, &handle);
assert_num_eq (rv, CKR_SESSION_READ_ONLY);
}
static void
test_create_and_write (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_TOKEN, &vtrue, sizeof (vtrue) },
{ CKA_INVALID }
};
CK_ATTRIBUTE expected[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "eight", 5 },
{ CKA_APPLICATION, "", 0 },
{ CKA_OBJECT_ID, "", 0 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
p11_array *parsed;
char *path;
CK_RV rv;
int ret;
/* Read-only session */
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
NULL, NULL, &session);
assert_num_eq (rv, CKR_OK);
/* Create a token object */
rv = test.module->C_CreateObject (session, original, 4, &handle);
assert_num_eq (rv, CKR_OK);
/* The expected file name */
path = p11_path_build (test.directory, "yay.p11-kit", NULL);
p11_parser_formats (test.parser, p11_parser_format_persist, NULL);
ret = p11_parse_file (test.parser, path, NULL, 0);
assert_num_eq (ret, P11_PARSE_SUCCESS);
free (path);
parsed = p11_parser_parsed (test.parser);
assert_num_eq (parsed->num, 1);
test_check_attrs (expected, parsed->elem[0]);
}
static void
test_modify_and_write (void)
{
CK_ATTRIBUTE original[] = {
{ CKA_VALUE, "eight", 5 },
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_TOKEN, &vtrue, sizeof (vtrue) },
{ CKA_MODIFIABLE, &vtrue, sizeof (vtrue) },
{ CKA_INVALID }
};
CK_ATTRIBUTE expected[] = {
{ CKA_CLASS, &data, sizeof (data) },
{ CKA_LABEL, "yay", 3 },
{ CKA_VALUE, "nine", 4 },
{ CKA_APPLICATION, "", 0 },
{ CKA_OBJECT_ID, "", 0 },
{ CKA_INVALID }
};
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE handle;
p11_array *parsed;
char *path;
CK_RV rv;
int ret;
/* Read-only session */
rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
NULL, NULL, &session);
assert_num_eq (rv, CKR_OK);
/* Create a token object */
rv = test.module->C_CreateObject (session, original, 5, &handle);
assert_num_eq (rv, CKR_OK);
/* Now modify the object */
original[0].pValue = "nine";
original[0].ulValueLen = 4;
rv = test.module->C_SetAttributeValue (session, handle, original, 5);
assert_num_eq (rv, CKR_OK);
/* The expected file name */
path = p11_path_build (test.directory, "yay.p11-kit", NULL);
ret = p11_parse_file (test.parser, path, NULL, 0);
assert_num_eq (ret, P11_PARSE_SUCCESS);
free (path);
parsed = p11_parser_parsed (test.parser);
assert_num_eq (parsed->num, 1);
test_check_attrs (expected, parsed->elem[0]);
}
static void
test_token_write_protected (void)
{
CK_C_INITIALIZE_ARGS args;
CK_FUNCTION_LIST *module;
CK_SLOT_ID slots[NUM_SLOTS];
CK_TOKEN_INFO info;
char label[32];
CK_ULONG count;
CK_RV rv;
int i;
/* These are the paths passed in in setup() */
const char *labels[] = {
"System Trust",
"Default Trust",
"the-basename",
};
/* This is the entry point of the trust module, linked to this test */
rv = C_GetFunctionList (&module);
assert (rv == CKR_OK);
memset (&args, 0, sizeof (args));
args.pReserved = "paths='" \
P11_SYSTEM_TRUST_PREFIX "/trust/input" P11_PATH_SEP \
P11_DEFAULT_TRUST_PREFIX "/trust/fixtures/blah" P11_PATH_SEP \
"/some/other/path/the-basename'";
args.flags = CKF_OS_LOCKING_OK;
rv = module->C_Initialize (&args);
assert (rv == CKR_OK);
count = NUM_SLOTS;
rv = module->C_GetSlotList (CK_TRUE, slots, &count);
assert (rv == CKR_OK);
assert (count == NUM_SLOTS);
for (i = 0; i < NUM_SLOTS; i++) {
rv = module->C_GetTokenInfo (slots[i], &info);
assert_num_eq (CKR_OK, rv);
memset (label, ' ', sizeof (label));
memcpy (label, labels[i], strlen (labels[i]));
assert (memcmp (info.label, label, sizeof (label)) == 0);
switch (i) {
case 0:
assert_num_cmp (0, ==, info.flags & CKF_WRITE_PROTECTED);
break;
case 1:
assert_num_cmp (0, !=, info.flags & CKF_WRITE_PROTECTED);
break;
default:
break;
}
}
rv = module->C_Finalize (NULL);
assert_num_eq (CKR_OK, rv);
}
int
main (int argc,
char *argv[])
{
p11_library_init ();
p11_fixture (setup, teardown);
p11_test (test_get_slot_list, "/module/get_slot_list");
p11_test (test_get_slot_info, "/module/get_slot_info");
p11_fixture (NULL, NULL);
p11_test (test_null_initialize, "/module/initialize-null");
p11_test (test_multi_initialize, "/module/initialize-multi");
p11_test (test_get_token_info, "/module/get_token_info");
p11_fixture (setup, teardown);
p11_test (test_get_session_info, "/module/get_session_info");
p11_test (test_close_all_sessions, "/module/close_all_sessions");
p11_test (test_find_certificates, "/module/find_certificates");
p11_test (test_find_extensions, "/module/find_extensions");
p11_test (test_find_builtin, "/module/find_builtin");
p11_test (test_lookup_invalid, "/module/lookup_invalid");
p11_test (test_remove_token, "/module/remove_token");
p11_test (test_setattr_token, "/module/setattr_token");
p11_test (test_session_object, "/module/session_object");
p11_test (test_session_find, "/module/session_find");
p11_test (test_session_find_no_attr, "/module/session_find_no_attr");
p11_test (test_session_copy, "/module/session_copy");
p11_test (test_session_remove, "/module/session_remove");
p11_test (test_session_setattr, "/module/session_setattr");
p11_test (test_find_serial_der_decoded, "/module/find_serial_der_decoded");
p11_test (test_find_serial_der_mismatch, "/module/find_serial_der_mismatch");
p11_test (test_login_logout, "/module/login_logout");
p11_fixture (setup_writable, teardown);
p11_test (test_token_writable, "/module/token-writable");
p11_test (test_session_read_only_create, "/module/session-read-only-create");
p11_test (test_create_and_write, "/module/create-and-write");
p11_test (test_modify_and_write, "/module/modify-and-write");
p11_fixture (NULL, NULL);
p11_test (test_token_write_protected, "/module/token-write-protected");
p11_fixture (setup_unreadable, teardown);
p11_test (test_find_certificates, "/module/unreadable");
return p11_test_run (argc, argv);
}