/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* GIO TLS tests
*
* Copyright (C) 2011 Collabora, Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see
* <http://www.gnu.org/licenses/>.
*
* In addition, when the library is used with OpenSSL, a special
* exception applies. Refer to the LICENSE_EXCEPTION file for details.
*
* Author: Stef Walter <stefw@collabora.co.uk>
*/
#include <gio/gio.h>
#include <sys/types.h>
#include <string.h>
#include "pkcs11/gpkcs11slot.h"
#include "pkcs11/gpkcs11util.h"
#include "mock-pkcs11.h"
#include "mock-interaction.h"
#include <p11-kit/p11-kit.h>
#include <stdlib.h>
typedef struct {
CK_FUNCTION_LIST funcs;
GPkcs11Slot *slot;
GPkcs11Slot *not_present;
} TestSlot;
static void
setup_slot (TestSlot *test,
gconstpointer unused)
{
CK_RV rv;
/* Copy this so we can replace certain functions in our tests */
memcpy (&test->funcs, &mock_default_functions, sizeof (test->funcs));
rv = p11_kit_module_initialize (&test->funcs);
g_assert (rv == CKR_OK);
test->slot = g_object_new (G_TYPE_PKCS11_SLOT,
"slot-id", MOCK_SLOT_ONE_ID,
"module", &test->funcs,
NULL);
g_assert (G_IS_PKCS11_SLOT (test->slot));
test->not_present = g_object_new (G_TYPE_PKCS11_SLOT,
"slot-id", MOCK_SLOT_TWO_ID,
"module", &test->funcs,
NULL);
g_assert (G_IS_PKCS11_SLOT (test->not_present));
}
static void
teardown_slot (TestSlot *test,
gconstpointer unused)
{
CK_RV rv;
g_assert_cmpint (G_OBJECT (test->slot)->ref_count, ==, 1);
g_object_unref (test->slot);
g_assert_cmpint (G_OBJECT (test->not_present)->ref_count, ==, 1);
g_object_unref (test->not_present);
rv = p11_kit_module_finalize (&test->funcs);
g_assert (rv == CKR_OK);
}
static void
test_properties (TestSlot *test,
gconstpointer unused)
{
CK_SLOT_ID id;
CK_FUNCTION_LIST_PTR module;
g_object_get (test->slot, "slot-id", &id, "module", &module, NULL);
g_assert_cmpuint (id, ==, MOCK_SLOT_ONE_ID);
g_assert (module == &test->funcs);
}
static void
test_token_info (TestSlot *test,
gconstpointer unused)
{
CK_TOKEN_INFO token_info;
char *label;
if (!g_pkcs11_slot_get_token_info (test->slot, &token_info))
g_assert_not_reached ();
label = p11_kit_space_strdup (token_info.label, sizeof (token_info.label));
g_assert_cmpstr (label, ==, "TEST LABEL");
free (label);
}
static void
test_token_info_not_present (TestSlot *test,
gconstpointer unused)
{
CK_TOKEN_INFO token_info;
char *label;
if (!g_pkcs11_slot_get_token_info (test->slot, &token_info))
g_assert_not_reached ();
label = p11_kit_space_strdup (token_info.label, sizeof (token_info.label));
g_assert_cmpstr (label, ==, "TEST LABEL");
free (label);
}
static void
test_matches_uri (TestSlot *test,
gconstpointer unused)
{
P11KitUri *uri;
uri = p11_kit_uri_new ();
if (p11_kit_uri_parse (MOCK_SLOT_ONE_URI, P11_KIT_URI_FOR_TOKEN, uri) != 0)
g_assert_not_reached ();
g_assert (!p11_kit_uri_any_unrecognized (uri));
if (!g_pkcs11_slot_matches_uri (test->slot, uri))
g_assert_not_reached();
if (g_pkcs11_slot_matches_uri (test->not_present, uri))
g_assert_not_reached ();
p11_kit_uri_free (uri);
}
static gboolean
accumulate_check_not_called (gpointer result,
gpointer user_data)
{
g_assert_not_reached ();
return FALSE;
}
static void
test_enumerate_no_match (TestSlot *test,
gconstpointer unused)
{
GPkcs11EnumerateState state;
CK_ATTRIBUTE_TYPE types[] = { CKA_LABEL, CKA_ID };
GError *error = NULL;
GPkcs11Array *match;
match = g_pkcs11_array_new ();
g_pkcs11_array_add_value (match, CKA_LABEL, "Non existant", -1);
g_pkcs11_array_add_value (match, CKA_ID, "Bad ID", -1);
state = g_pkcs11_slot_enumerate (test->slot, NULL,
match->attrs, match->count, FALSE,
types, G_N_ELEMENTS (types),
accumulate_check_not_called, NULL,
NULL, &error);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_CONTINUE);
g_assert_no_error (error);
g_pkcs11_array_unref (match);
}
static void
test_enumerate_not_present (TestSlot *test,
gconstpointer unused)
{
GPkcs11EnumerateState state;
CK_ATTRIBUTE_TYPE types[] = { CKA_LABEL, CKA_ID };
GError *error = NULL;
GPkcs11Array *match;
/* Empty match should match anything ... */
match = g_pkcs11_array_new ();
/* ... but token is not present, so nothing */
state = g_pkcs11_slot_enumerate (test->not_present, NULL,
match->attrs, match->count, FALSE,
types, G_N_ELEMENTS (types),
accumulate_check_not_called, NULL,
NULL, &error);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_CONTINUE);
g_assert_no_error (error);
g_pkcs11_array_unref (match);
}
static gboolean
accumulate_results (gpointer result,
gpointer user_data)
{
GPtrArray *results = user_data;
GPkcs11Array *attrs = result;
g_assert (results);
g_assert (attrs);
g_ptr_array_add (results, g_pkcs11_array_ref (attrs));
return TRUE;
}
static void
test_enumerate_all (TestSlot *test,
gconstpointer unused)
{
GPkcs11EnumerateState state;
CK_ATTRIBUTE_TYPE types[] = { CKA_LABEL, CKA_ID };
GError *error = NULL;
GPkcs11Array *match;
GPkcs11Array *attrs;
GPtrArray *results;
const CK_ATTRIBUTE *attr;
guint i;
/* Match anything */
match = g_pkcs11_array_new ();
results = g_ptr_array_new_with_free_func ((GDestroyNotify)g_pkcs11_array_unref);
state = g_pkcs11_slot_enumerate (test->slot, NULL,
match->attrs, match->count, FALSE,
types, G_N_ELEMENTS (types),
accumulate_results, results,
NULL, &error);
g_pkcs11_array_unref (match);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_CONTINUE);
g_assert_no_error (error);
g_assert_cmpuint (results->len, >, 1);
for (i = 0; i < results->len; i++)
{
attrs = results->pdata[i];
attr = g_pkcs11_array_find (attrs, CKA_LABEL);
g_assert (attr != NULL);
g_assert (g_utf8_validate (attr->pValue, attr->ulValueLen, NULL));
}
g_ptr_array_free (results, TRUE);
}
static gboolean
accumulate_first (gpointer result,
gpointer user_data)
{
GPtrArray *results = user_data;
GPkcs11Array *attrs = result;
g_assert (results);
g_assert (attrs);
g_assert_cmpuint (results->len, ==, 0);
g_ptr_array_add (results, g_pkcs11_array_ref (attrs));
return FALSE; /* Don't call again */
}
static void
test_enumerate_first (TestSlot *test,
gconstpointer unused)
{
GPkcs11EnumerateState state;
CK_ATTRIBUTE_TYPE types[] = { CKA_LABEL, CKA_ID };
GError *error = NULL;
GPkcs11Array *match;
GPkcs11Array *attrs;
GPtrArray *results;
const CK_ATTRIBUTE *attr;
/* Match anything */
match = g_pkcs11_array_new ();
results = g_ptr_array_new_with_free_func ((GDestroyNotify)g_pkcs11_array_unref);
state = g_pkcs11_slot_enumerate (test->slot, NULL,
match->attrs, match->count, FALSE,
types, G_N_ELEMENTS (types),
accumulate_first, results,
NULL, &error);
g_pkcs11_array_unref (match);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_STOP);
g_assert_no_error (error);
g_assert_cmpuint (results->len, ==, 1);
attrs = results->pdata[0];
attr = g_pkcs11_array_find (attrs, CKA_LABEL);
g_assert (attr != NULL);
g_assert (g_utf8_validate (attr->pValue, attr->ulValueLen, NULL));
g_ptr_array_free (results, TRUE);
}
static gboolean
accumulate_check_null_result (gpointer result,
gpointer user_data)
{
GPkcs11Array *attrs = result;
g_assert (attrs == NULL);
return TRUE; /* call again */
}
static void
test_enumerate_no_attrs (TestSlot *test,
gconstpointer unused)
{
GPkcs11EnumerateState state;
GError *error = NULL;
GPkcs11Array *match;
/* Match anything */
match = g_pkcs11_array_new ();
state = g_pkcs11_slot_enumerate (test->slot, NULL,
match->attrs, match->count, FALSE,
NULL, 0,
accumulate_check_null_result, NULL,
NULL, &error);
g_pkcs11_array_unref (match);
/* Didn't find anything, so continue */
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_CONTINUE);
g_assert_no_error (error);
}
static void
test_enumerate_fail_session (TestSlot *test,
gconstpointer unused)
{
GPkcs11EnumerateState state;
GError *error = NULL;
/* Make opening a session fail */
test->funcs.C_OpenSession = mock_fail_C_OpenSession;
state = g_pkcs11_slot_enumerate (test->slot, NULL,
NULL, 0, FALSE,
NULL, 0,
accumulate_check_not_called, NULL,
NULL, &error);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_FAILED);
g_assert_error (error, G_PKCS11_ERROR, CKR_GENERAL_ERROR);
g_error_free (error);
}
static void
test_enumerate_fail_attributes (TestSlot *test,
gconstpointer unused)
{
GPkcs11EnumerateState state;
GError *error = NULL;
CK_ATTRIBUTE_TYPE types[] = { CKA_LABEL, CKA_ID };
/* Make retrieving object attrs fail */
test->funcs.C_GetAttributeValue = mock_fail_C_GetAttributeValue;
state = g_pkcs11_slot_enumerate (test->slot, NULL,
NULL, 0, FALSE,
types, G_N_ELEMENTS (types),
accumulate_check_not_called, NULL,
NULL, &error);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_FAILED);
g_assert_error (error, G_PKCS11_ERROR, CKR_FUNCTION_FAILED);
g_error_free (error);
}
static gboolean
accumulate_cancel_on_first (gpointer result,
gpointer user_data)
{
GCancellable *cancellable = G_CANCELLABLE (user_data);
g_assert (!g_cancellable_is_cancelled (cancellable));
g_cancellable_cancel (cancellable);
return TRUE; /* call again, except that above cancellation should stop */
}
static void
test_enumerate_cancel (TestSlot *test,
gconstpointer unused)
{
GPkcs11EnumerateState state;
GError *error = NULL;
GPkcs11Array *match;
GCancellable *cancellable;
cancellable = g_cancellable_new ();
/* Match anything */
match = g_pkcs11_array_new ();
state = g_pkcs11_slot_enumerate (test->slot, NULL,
match->attrs, match->count, FALSE,
NULL, 0,
accumulate_cancel_on_first, cancellable,
cancellable, &error);
g_pkcs11_array_unref (match);
g_object_unref (cancellable);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_FAILED);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_error_free (error);
}
static void
test_enumerate_private (TestSlot *test,
gconstpointer unused)
{
CK_ATTRIBUTE_TYPE types[] = { CKA_LABEL, CKA_ID, CKA_PRIVATE };
GPkcs11EnumerateState state;
GError *error = NULL;
GPkcs11Array *match;
GPtrArray *results;
gboolean bval;
GTlsInteraction *interaction;
/* Match label of private object, see mock*/
match = g_pkcs11_array_new ();
g_pkcs11_array_add_value (match, CKA_LABEL, "PRIVATE", -1);
/* Shouldn't match anything, since not logged in */
state = g_pkcs11_slot_enumerate (test->slot, NULL,
match->attrs, match->count, FALSE,
types, G_N_ELEMENTS (types),
accumulate_check_not_called, NULL,
NULL, &error);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_CONTINUE);
g_assert_no_error (error);
/* This time we try to log in but no interaction is set */
state = g_pkcs11_slot_enumerate (test->slot, NULL,
match->attrs, match->count, TRUE, /* match privates */
types, G_N_ELEMENTS (types),
accumulate_check_not_called, NULL,
NULL, &error);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_CONTINUE);
g_assert_no_error (error);
/* This time we log in, and should have a match */
results = g_ptr_array_new_with_free_func ((GDestroyNotify)g_pkcs11_array_unref);
interaction = mock_interaction_new_static_password (MOCK_SLOT_ONE_PIN);
state = g_pkcs11_slot_enumerate (test->slot, interaction,
match->attrs, match->count, TRUE,
types, G_N_ELEMENTS (types),
accumulate_results, results,
NULL, &error);
g_assert_cmpuint (state, ==, G_PKCS11_ENUMERATE_CONTINUE);
g_assert_no_error (error);
/* One private object, with following info */
g_assert_cmpuint (results->len, ==, 1);
if (!g_pkcs11_array_find_boolean (results->pdata[0], CKA_PRIVATE, &bval))
g_assert_not_reached ();
g_assert (bval == TRUE);
g_object_unref (interaction);
g_pkcs11_array_unref (match);
g_ptr_array_free (results, TRUE);
}
int
main (int argc,
char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_add ("/pkcs11/slot/properties", TestSlot, NULL,
setup_slot, test_properties, teardown_slot);
g_test_add ("/pkcs11/slot/token-info", TestSlot, NULL,
setup_slot, test_token_info, teardown_slot);
g_test_add ("/pkcs11/slot/token-not-present", TestSlot, NULL,
setup_slot, test_token_info_not_present, teardown_slot);
g_test_add ("/pkcs11/slot/matches-uri", TestSlot, NULL,
setup_slot, test_matches_uri, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-no-match", TestSlot, NULL,
setup_slot, test_enumerate_no_match, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-not-present", TestSlot, NULL,
setup_slot, test_enumerate_not_present, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-all", TestSlot, NULL,
setup_slot, test_enumerate_all, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-first", TestSlot, NULL,
setup_slot, test_enumerate_first, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-no-attrs", TestSlot, NULL,
setup_slot, test_enumerate_no_attrs, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-fail-session", TestSlot, NULL,
setup_slot, test_enumerate_fail_session, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-fail-attributes", TestSlot, NULL,
setup_slot, test_enumerate_fail_attributes, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-cancel", TestSlot, NULL,
setup_slot, test_enumerate_cancel, teardown_slot);
g_test_add ("/pkcs11/slot/enumerate-private", TestSlot, NULL,
setup_slot, test_enumerate_private, teardown_slot);
return g_test_run();
}