diff options
Diffstat (limited to 'p11-kit/test-rpc.c')
-rw-r--r-- | p11-kit/test-rpc.c | 1061 |
1 files changed, 1061 insertions, 0 deletions
diff --git a/p11-kit/test-rpc.c b/p11-kit/test-rpc.c new file mode 100644 index 0000000..0ce2c55 --- /dev/null +++ b/p11-kit/test-rpc.c @@ -0,0 +1,1061 @@ +/* + * Copyright (c) 2012 Stefan Walter + * 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 <stef@thewalter.net> + */ + +#include "config.h" +#include "test.h" + +#include "debug.h" +#include "library.h" +#include "message.h" +#include "mock.h" +#include "p11-kit.h" +#include "private.h" +#include "rpc.h" +#include "rpc-message.h" +#include "virtual.h" + +#include <sys/types.h> +#include <sys/wait.h> +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +static void +test_new_free (void) +{ + p11_buffer *buf; + + buf = p11_rpc_buffer_new (0); + + assert_ptr_not_null (buf->data); + assert_num_eq (0, buf->len); + assert_num_eq (0, buf->flags); + assert (buf->size == 0); + assert_ptr_not_null (buf->ffree); + assert_ptr_not_null (buf->frealloc); + + p11_rpc_buffer_free (buf); +} + +static void +test_uint16 (void) +{ + p11_buffer buffer; + uint16_t val = 0xFFFF; + size_t next; + bool ret; + + p11_buffer_init (&buffer, 0); + + next = 0; + ret = p11_rpc_buffer_get_uint16 (&buffer, &next, &val); + assert_num_eq (false, ret); + assert_num_eq (0, next); + assert_num_eq (0xFFFF, val); + + p11_buffer_reset (&buffer, 0); + + ret = p11_rpc_buffer_set_uint16 (&buffer, 0, 0x6789); + assert_num_eq (false, ret); + + p11_buffer_reset (&buffer, 0); + + p11_buffer_add (&buffer, (unsigned char *)"padding", 7); + + p11_rpc_buffer_add_uint16 (&buffer, 0x6789); + assert_num_eq (9, buffer.len); + assert (!p11_buffer_failed (&buffer)); + + next = 7; + ret = p11_rpc_buffer_get_uint16 (&buffer, &next, &val); + assert_num_eq (true, ret); + assert_num_eq (9, next); + assert_num_eq (0x6789, val); + + p11_buffer_uninit (&buffer); +} + +static void +test_uint16_static (void) +{ + p11_buffer buf = { (unsigned char *)"pad0\x67\x89", 6, }; + uint16_t val = 0xFFFF; + size_t next; + bool ret; + + next = 4; + ret = p11_rpc_buffer_get_uint16 (&buf, &next, &val); + assert_num_eq (true, ret); + assert_num_eq (6, next); + assert_num_eq (0x6789, val); +} + +static void +test_uint32 (void) +{ + p11_buffer buffer; + uint32_t val = 0xFFFFFFFF; + size_t next; + bool ret; + + p11_buffer_init (&buffer, 0); + + next = 0; + ret = p11_rpc_buffer_get_uint32 (&buffer, &next, &val); + assert_num_eq (false, ret); + assert_num_eq (0, next); + assert_num_eq (0xFFFFFFFF, val); + + p11_buffer_reset (&buffer, 0); + + ret = p11_rpc_buffer_set_uint32 (&buffer, 0, 0x12345678); + assert_num_eq (false, ret); + + p11_buffer_reset (&buffer, 0); + + p11_buffer_add (&buffer, (unsigned char *)"padding", 7); + + p11_rpc_buffer_add_uint32 (&buffer, 0x12345678); + assert_num_eq (11, buffer.len); + assert (!p11_buffer_failed (&buffer)); + + next = 7; + ret = p11_rpc_buffer_get_uint32 (&buffer, &next, &val); + assert_num_eq (true, ret); + assert_num_eq (11, next); + assert_num_eq (0x12345678, val); + + p11_buffer_uninit (&buffer); +} + +static void +test_uint32_static (void) +{ + p11_buffer buf = { (unsigned char *)"pad0\x23\x45\x67\x89", 8, }; + uint32_t val = 0xFFFFFFFF; + size_t next; + bool ret; + + next = 4; + ret = p11_rpc_buffer_get_uint32 (&buf, &next, &val); + assert_num_eq (true, ret); + assert_num_eq (8, next); + assert_num_eq (0x23456789, val); +} + +static void +test_uint64 (void) +{ + p11_buffer buffer; + uint64_t val = 0xFFFFFFFFFFFFFFFF; + size_t next; + bool ret; + + p11_buffer_init (&buffer, 0); + + next = 0; + ret = p11_rpc_buffer_get_uint64 (&buffer, &next, &val); + assert_num_eq (0, ret); + assert_num_eq (0, next); + assert (0xFFFFFFFFFFFFFFFF == val); + + p11_buffer_reset (&buffer, 0); + + p11_buffer_add (&buffer, (unsigned char *)"padding", 7); + + p11_rpc_buffer_add_uint64 (&buffer, 0x0123456708ABCDEF); + assert_num_eq (15, buffer.len); + assert (!p11_buffer_failed (&buffer)); + + next = 7; + ret = p11_rpc_buffer_get_uint64 (&buffer, &next, &val); + assert_num_eq (true, ret); + assert_num_eq (15, next); + assert (0x0123456708ABCDEF == val); + + p11_buffer_uninit (&buffer); +} + +static void +test_uint64_static (void) +{ + p11_buffer buf = { (unsigned char *)"pad0\x89\x67\x45\x23\x11\x22\x33\x44", 12, }; + uint64_t val = 0xFFFFFFFFFFFFFFFF; + size_t next; + bool ret; + + next = 4; + ret = p11_rpc_buffer_get_uint64 (&buf, &next, &val); + assert_num_eq (true, ret); + assert_num_eq (12, next); + assert (0x8967452311223344 == val); +} + +static void +test_byte_array (void) +{ + p11_buffer buffer; + unsigned char bytes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }; + + const unsigned char *val; + size_t length = ~0; + size_t next; + bool ret; + + p11_buffer_init (&buffer, 0); + + /* Invalid read */ + + next = 0; + ret = p11_rpc_buffer_get_byte_array (&buffer, &next, &val, &length); + assert_num_eq (false, ret); + assert_num_eq (0, next); + assert_num_eq (~0, length); + + /* Test full array */ + + p11_buffer_reset (&buffer, 0); + p11_buffer_add (&buffer, (unsigned char *)"padding", 7); + + p11_rpc_buffer_add_byte_array (&buffer, bytes, 32); + assert_num_eq (43, buffer.len); + assert (!p11_buffer_failed (&buffer)); + + next = 7; + ret = p11_rpc_buffer_get_byte_array (&buffer, &next, &val, &length); + assert_num_eq (true, ret); + assert_num_eq (43, next); + assert_num_eq (32, length); + assert (memcmp (val, bytes, 32) == 0); + + p11_buffer_uninit (&buffer); +} + +static void +test_byte_array_null (void) +{ + p11_buffer buffer; + const unsigned char *val; + size_t length = ~0; + size_t next; + bool ret; + + p11_buffer_init (&buffer, 0); + + p11_buffer_reset (&buffer, 0); + p11_buffer_add (&buffer, (unsigned char *)"padding", 7); + + p11_rpc_buffer_add_byte_array (&buffer, NULL, 0); + assert_num_eq (11, buffer.len); + assert (!p11_buffer_failed (&buffer)); + + next = 7; + ret = p11_rpc_buffer_get_byte_array (&buffer, &next, &val, &length); + assert_num_eq (true, ret); + assert_num_eq (11, next); + assert_num_eq (0, length); + assert_ptr_eq (NULL, (void*)val); + + p11_buffer_uninit (&buffer); +} + +static void +test_byte_array_too_long (void) +{ + p11_buffer buffer; + const unsigned char *val = NULL; + size_t length = ~0; + size_t next; + bool ret; + + p11_buffer_init (&buffer, 0); + + p11_buffer_reset (&buffer, 0); + p11_buffer_add (&buffer, (unsigned char *)"padding", 7); + assert (!p11_buffer_failed (&buffer)); + + /* Passing a too short buffer here shouldn't matter, as length is checked for sanity */ + p11_rpc_buffer_add_byte_array (&buffer, (unsigned char *)"", 0x9fffffff); + assert (p11_buffer_failed (&buffer)); + + /* Force write a too long byte arary to buffer */ + p11_buffer_reset (&buffer, 0); + p11_rpc_buffer_add_uint32 (&buffer, 0x9fffffff); + + next = 0; + ret = p11_rpc_buffer_get_byte_array (&buffer, &next, &val, &length); + assert_num_eq (false, ret); + assert_num_eq (0, next); + assert_num_eq (~0, length); + assert_ptr_eq (NULL, (void*)val); + + p11_buffer_uninit (&buffer); +} + +static void +test_byte_array_static (void) +{ + unsigned char data[] = { 'p', 'a', 'd', 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }; + p11_buffer buf = { data, 0x40, }; + const unsigned char *val; + size_t length = ~0; + size_t next; + bool ret; + + next = 4; + ret = p11_rpc_buffer_get_byte_array (&buf, &next, &val, &length); + assert_num_eq (true, ret); + assert_num_eq (40, next); + assert_num_eq (32, length); + assert (memcmp (data + 8, val, 32) == 0); +} + +static p11_virtual base; +static pid_t rpc_initialized = 0; + +static CK_RV +rpc_initialize (p11_rpc_client_vtable *vtable, + void *init_reserved) +{ + pid_t pid = getpid (); + + assert_str_eq (vtable->data, "vtable-data"); + assert_num_cmp (pid, !=, rpc_initialized); + rpc_initialized = pid; + + return CKR_OK; +} + +static CK_RV +rpc_initialize_fails (p11_rpc_client_vtable *vtable, + void *init_reserved) +{ + pid_t pid = getpid (); + + assert_str_eq (vtable->data, "vtable-data"); + assert_num_cmp (pid, !=, rpc_initialized); + return CKR_FUNCTION_FAILED; +} + +static CK_RV +rpc_initialize_device_removed (p11_rpc_client_vtable *vtable, + void *init_reserved) +{ + pid_t pid = getpid (); + + assert_str_eq (vtable->data, "vtable-data"); + assert_num_cmp (pid, !=, rpc_initialized); + return CKR_DEVICE_REMOVED; +} + +static CK_RV +rpc_transport (p11_rpc_client_vtable *vtable, + p11_buffer *request, + p11_buffer *response) +{ + bool ret; + + assert_str_eq (vtable->data, "vtable-data"); + + /* Just pass directly to the server code */ + ret = p11_rpc_server_handle (&base.funcs, request, response); + assert (ret == true); + + return CKR_OK; +} + +static void +rpc_finalize (p11_rpc_client_vtable *vtable, + void *fini_reserved) +{ + pid_t pid = getpid (); + + assert_str_eq (vtable->data, "vtable-data"); + assert_num_cmp (pid, ==, rpc_initialized); + rpc_initialized = 0; +} + +static void +test_initialize (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport, rpc_finalize }; + pid_t pid = getpid (); + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + rpc_initialized = 0; + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + rv = mixin.funcs.C_Initialize (&mixin.funcs, NULL); + assert (rv == CKR_OK); + assert_num_eq (pid, rpc_initialized); + + rv = mixin.funcs.C_Finalize (&mixin.funcs, NULL); + assert (rv == CKR_OK); + assert_num_cmp (pid, !=, rpc_initialized); + + p11_virtual_uninit (&mixin); +} + +static void +test_not_initialized (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport, rpc_finalize }; + p11_virtual mixin; + CK_INFO info; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + rpc_initialized = 0; + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + rv = (mixin.funcs.C_GetInfo) (&mixin.funcs, &info); + assert (rv == CKR_CRYPTOKI_NOT_INITIALIZED); + + p11_virtual_uninit (&mixin); +} + +static void +test_initialize_fails_on_client (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize_fails, rpc_transport, rpc_finalize }; + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + rpc_initialized = 0; + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL); + assert (rv == CKR_FUNCTION_FAILED); + assert_num_eq (0, rpc_initialized); + + p11_virtual_uninit (&mixin); +} + +static CK_RV +rpc_transport_fails (p11_rpc_client_vtable *vtable, + p11_buffer *request, + p11_buffer *response) +{ + return CKR_FUNCTION_REJECTED; +} + +static void +test_transport_fails (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_fails, rpc_finalize }; + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + rpc_initialized = 0; + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL); + assert (rv == CKR_FUNCTION_REJECTED); + assert_num_eq (0, rpc_initialized); + + p11_virtual_uninit (&mixin); +} + +static void +test_initialize_fails_on_server (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport, rpc_finalize }; + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + base.funcs.C_Initialize = mock_X_Initialize__fails; + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL); + assert (rv == CKR_FUNCTION_FAILED); + assert_num_eq (0, rpc_initialized); + + p11_virtual_uninit (&mixin); +} + +static CK_RV +rpc_transport_bad_parse (p11_rpc_client_vtable *vtable, + p11_buffer *request, + p11_buffer *response) +{ + int rc; + + assert_str_eq (vtable->data, "vtable-data"); + + /* Just zero bytes is an invalid message */ + rc = p11_buffer_reset (response, 2); + assert (rc >= 0); + + memset (response->data, 0, 2); + response->len = 2; + return CKR_OK; +} + +static void +test_transport_bad_parse (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_bad_parse, rpc_finalize }; + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + rpc_initialized = 0; + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + p11_kit_be_quiet (); + + rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL); + assert (rv == CKR_DEVICE_ERROR); + assert_num_eq (0, rpc_initialized); + + p11_message_loud (); + p11_virtual_uninit (&mixin); +} + +static CK_RV +rpc_transport_short_error (p11_rpc_client_vtable *vtable, + p11_buffer *request, + p11_buffer *response) +{ + int rc; + + unsigned char data[] = { + 0x00, 0x00, 0x00, 0x00, /* RPC_CALL_ERROR */ + 0x00, 0x00, 0x00, 0x01, 0x75, /* signature 'u' */ + 0x00, 0x01, /* short error */ + }; + + assert_str_eq (vtable->data, "vtable-data"); + + rc = p11_buffer_reset (response, sizeof (data)); + assert (rc >= 0); + + memcpy (response->data, data, sizeof (data)); + response->len = sizeof (data); + return CKR_OK; +} + +static void +test_transport_short_error (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_short_error, rpc_finalize }; + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + p11_kit_be_quiet (); + + rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL); + assert (rv == CKR_DEVICE_ERROR); + assert_num_eq (0, rpc_initialized); + + p11_message_loud (); + p11_virtual_uninit (&mixin); +} + +static CK_RV +rpc_transport_invalid_error (p11_rpc_client_vtable *vtable, + p11_buffer *request, + p11_buffer *response) +{ + int rc; + + unsigned char data[] = { + 0x00, 0x00, 0x00, 0x00, /* RPC_CALL_ERROR */ + 0x00, 0x00, 0x00, 0x01, 0x75, /* signature 'u' */ + 0x00, 0x00, 0x00, 0x00, /* a CKR_OK error*/ + 0x00, 0x00, 0x00, 0x00, + }; + + assert_str_eq (vtable->data, "vtable-data"); + + rc = p11_buffer_reset (response, sizeof (data)); + assert (rc >= 0); + memcpy (response->data, data, sizeof (data)); + response->len = sizeof (data); + return CKR_OK; +} + +static void +test_transport_invalid_error (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_invalid_error, rpc_finalize }; + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + p11_kit_be_quiet (); + + rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL); + assert (rv == CKR_DEVICE_ERROR); + assert_num_eq (0, rpc_initialized); + + p11_message_loud (); + p11_virtual_uninit (&mixin); +} + +static CK_RV +rpc_transport_wrong_response (p11_rpc_client_vtable *vtable, + p11_buffer *request, + p11_buffer *response) +{ + int rc; + + unsigned char data[] = { + 0x00, 0x00, 0x00, 0x02, /* RPC_CALL_C_Finalize */ + 0x00, 0x00, 0x00, 0x00, /* signature '' */ + }; + + assert_str_eq (vtable->data, "vtable-data"); + + rc = p11_buffer_reset (response, sizeof (data)); + assert (rc >= 0); + memcpy (response->data, data, sizeof (data)); + response->len = sizeof (data); + return CKR_OK; +} + +static void +test_transport_wrong_response (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_wrong_response, rpc_finalize }; + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + p11_kit_be_quiet (); + + rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL); + assert (rv == CKR_DEVICE_ERROR); + assert_num_eq (0, rpc_initialized); + + p11_message_loud (); + p11_virtual_uninit (&mixin); +} + +static CK_RV +rpc_transport_bad_contents (p11_rpc_client_vtable *vtable, + p11_buffer *request, + p11_buffer *response) +{ + int rc; + + unsigned char data[] = { + 0x00, 0x00, 0x00, 0x02, /* RPC_CALL_C_GetInfo */ + 0x00, 0x00, 0x00, 0x05, /* signature 'vsusv' */ + 'v', 's', 'u', 's', 'v', + 0x00, 0x00, 0x00, 0x00, /* invalid data */ + }; + + assert_str_eq (vtable->data, "vtable-data"); + + rc = p11_buffer_reset (response, sizeof (data)); + assert (rc >= 0); + memcpy (response->data, data, sizeof (data)); + response->len = sizeof (data); + return CKR_OK; +} + +static void +test_transport_bad_contents (void) +{ + p11_rpc_client_vtable vtable = { "vtable-data", rpc_initialize, rpc_transport_bad_contents, rpc_finalize }; + p11_virtual mixin; + bool ret; + CK_RV rv; + + /* Build up our own function list */ + p11_virtual_init (&base, &p11_virtual_base, &mock_module_no_slots, NULL); + + ret = p11_rpc_client_init (&mixin, &vtable); + assert_num_eq (true, ret); + + p11_kit_be_quiet (); + + rv = (mixin.funcs.C_Initialize) (&mixin.funcs, NULL); + assert (rv == CKR_DEVICE_ERROR); + assert_num_eq (0, rpc_initialized); + + p11_message_loud (); + p11_virtual_uninit (&mixin); +} + +static p11_rpc_client_vtable test_normal_vtable = { + NULL, + rpc_initialize, + rpc_transport, + rpc_finalize, +}; + +static p11_rpc_client_vtable test_device_removed_vtable = { + NULL, + rpc_initialize_device_removed, + rpc_transport, + rpc_finalize, +}; + +static void +mixin_free (void *data) +{ + p11_virtual *mixin = data; + p11_virtual_uninit (mixin); + free (mixin); +} + +static CK_FUNCTION_LIST_PTR +setup_test_rpc_module (p11_rpc_client_vtable *vtable, + CK_FUNCTION_LIST *module_template, + CK_SESSION_HANDLE *session) +{ + CK_FUNCTION_LIST *rpc_module; + p11_virtual *mixin; + CK_RV rv; + + /* Build up our own function list */ + p11_virtual_init (&base, &p11_virtual_base, module_template, NULL); + + mixin = calloc (1, sizeof (p11_virtual)); + assert (mixin != NULL); + + vtable->data = "vtable-data"; + if (!p11_rpc_client_init (mixin, vtable)) + assert_not_reached (); + + rpc_module = p11_virtual_wrap (mixin, mixin_free); + assert_ptr_not_null (rpc_module); + + rv = p11_kit_module_initialize (rpc_module); + assert (rv == CKR_OK); + + if (session) { + rv = (rpc_module->C_OpenSession) (MOCK_SLOT_ONE_ID, CKF_RW_SESSION | CKF_SERIAL_SESSION, + NULL, NULL, session); + assert (rv == CKR_OK); + } + + return rpc_module; +} + +static CK_FUNCTION_LIST * +setup_mock_module (CK_SESSION_HANDLE *session) +{ + return setup_test_rpc_module (&test_normal_vtable, &mock_module, session); +} + +static void +teardown_mock_module (CK_FUNCTION_LIST *rpc_module) +{ + p11_kit_module_finalize (rpc_module); + p11_virtual_unwrap (rpc_module); +} + +static void +test_get_info_stand_in (void) +{ + CK_FUNCTION_LIST_PTR rpc_module; + CK_INFO info; + CK_RV rv; + char *string; + + rpc_module = setup_test_rpc_module (&test_device_removed_vtable, + &mock_module_no_slots, NULL); + + rv = (rpc_module->C_GetInfo) (&info); + assert (rv == CKR_OK); + + assert_num_eq (CRYPTOKI_VERSION_MAJOR, info.cryptokiVersion.major); + assert_num_eq (CRYPTOKI_VERSION_MINOR, info.cryptokiVersion.minor); + string = p11_kit_space_strdup (info.manufacturerID, sizeof (info.manufacturerID)); + assert_str_eq ("p11-kit", string); + free (string); + string = p11_kit_space_strdup (info.libraryDescription, sizeof (info.libraryDescription)); + assert_str_eq ("p11-kit (no connection)", string); + free (string); + assert_num_eq (0, info.flags); + assert_num_eq (1, info.libraryVersion.major); + assert_num_eq (1, info.libraryVersion.minor); + + teardown_mock_module (rpc_module); +} + +static void +test_get_slot_list_no_device (void) +{ + CK_FUNCTION_LIST_PTR rpc_module; + CK_SLOT_ID slot_list[8]; + CK_ULONG count; + CK_RV rv; + + rpc_module = setup_test_rpc_module (&test_device_removed_vtable, + &mock_module_no_slots, NULL); + + rv = (rpc_module->C_GetSlotList) (CK_TRUE, NULL, &count); + assert (rv == CKR_OK); + assert_num_eq (0, count); + rv = (rpc_module->C_GetSlotList) (CK_FALSE, NULL, &count); + assert (rv == CKR_OK); + assert_num_eq (0, count); + + count = 8; + rv = (rpc_module->C_GetSlotList) (CK_TRUE, slot_list, &count); + assert (rv == CKR_OK); + assert_num_eq (0, count); + + count = 8; + rv = (rpc_module->C_GetSlotList) (CK_FALSE, slot_list, &count); + assert (rv == CKR_OK); + assert_num_eq (0, count); + + teardown_mock_module (rpc_module); +} + +static void * +invoke_in_thread (void *arg) +{ + CK_FUNCTION_LIST *rpc_module = arg; + CK_INFO info; + CK_RV rv; + + rv = (rpc_module->C_GetInfo) (&info); + assert_num_eq (rv, CKR_OK); + + assert (memcmp (info.manufacturerID, MOCK_INFO.manufacturerID, + sizeof (info.manufacturerID)) == 0); + + return NULL; +} + +static p11_mutex_t delay_mutex; + +static CK_RV +delayed_C_GetInfo (CK_INFO_PTR info) +{ + CK_RV rv; + + p11_sleep_ms (rand () % 100); + + p11_mutex_lock (&delay_mutex); + rv = mock_C_GetInfo (info); + p11_mutex_unlock (&delay_mutex); + + return rv; +} + +static void +test_simultaneous_functions (void) +{ + CK_FUNCTION_LIST real_module; + CK_FUNCTION_LIST *rpc_module; + const int num_threads = 128; + p11_thread_t threads[num_threads]; + int i, ret; + + p11_mutex_init (&delay_mutex); + + memcpy (&real_module, &mock_module_no_slots, sizeof (CK_FUNCTION_LIST)); + real_module.C_GetInfo = delayed_C_GetInfo; + + rpc_module = setup_test_rpc_module (&test_normal_vtable, + &real_module, NULL); + + /* Make the invoked function (above) wait */ + p11_mutex_lock (&delay_mutex); + + for (i = 0; i < num_threads; i++) { + ret = p11_thread_create (threads + i, invoke_in_thread, rpc_module); + assert_num_eq (0, ret); + } + + /* Let the invoked functions return */ + p11_mutex_unlock (&delay_mutex); + + for (i = 0; i < num_threads; i++) + p11_thread_join (threads[i]); + + teardown_mock_module (rpc_module); + p11_mutex_uninit (&delay_mutex); +} + +static void +test_fork_and_reinitialize (void) +{ + CK_FUNCTION_LIST *rpc_module; + CK_INFO info; + int status; + CK_RV rv; + pid_t pid; + int i; + + rpc_module = setup_test_rpc_module (&test_normal_vtable, + &mock_module_no_slots, NULL); + + pid = fork (); + assert_num_cmp (pid, >=, 0); + + /* The child */ + if (pid == 0) { + rv = (rpc_module->C_Initialize) (NULL); + assert_num_eq (CKR_OK, rv); + + for (i = 0; i < 32; i++) { + rv = (rpc_module->C_GetInfo) (&info); + assert_num_eq (CKR_OK, rv); + } + + rv = (rpc_module->C_Finalize) (NULL); + assert_num_eq (CKR_OK, rv); + + _exit (66); + } + + for (i = 0; i < 128; i++) { + rv = (rpc_module->C_GetInfo) (&info); + assert_num_eq (CKR_OK, rv); + } + + assert_num_eq (waitpid (pid, &status, 0), pid); + assert_num_eq (WEXITSTATUS (status), 66); + + teardown_mock_module (rpc_module); +} + +#include "test-mock.c" + +int +main (int argc, + char *argv[]) +{ + CK_MECHANISM_TYPE mechanisms[] = { + CKM_MOCK_CAPITALIZE, + CKM_MOCK_PREFIX, + CKM_MOCK_GENERATE, + CKM_MOCK_WRAP, + CKM_MOCK_DERIVE, + CKM_MOCK_COUNT, + 0, + }; + + mock_module_init (); + p11_library_init (); + + /* Override the mechanisms that the RPC mechanism will handle */ + p11_rpc_mechanisms_override_supported = mechanisms; + + p11_test (test_new_free, "/rpc/new-free"); + p11_test (test_uint16, "/rpc/uint16"); + p11_test (test_uint16_static, "/rpc/uint16-static"); + p11_test (test_uint32, "/rpc/uint32"); + p11_test (test_uint32_static, "/rpc/uint32-static"); + p11_test (test_uint64, "/rpc/uint64"); + p11_test (test_uint64_static, "/rpc/uint64-static"); + p11_test (test_byte_array, "/rpc/byte-array"); + p11_test (test_byte_array_null, "/rpc/byte-array-null"); + p11_test (test_byte_array_too_long, "/rpc/byte-array-too-long"); + p11_test (test_byte_array_static, "/rpc/byte-array-static"); + + p11_test (test_initialize_fails_on_client, "/rpc/initialize-fails-on-client"); + p11_test (test_initialize_fails_on_server, "/rpc/initialize-fails-on-server"); + p11_test (test_initialize, "/rpc/initialize"); + p11_test (test_not_initialized, "/rpc/not-initialized"); + p11_test (test_transport_fails, "/rpc/transport-fails"); + p11_test (test_transport_bad_parse, "/rpc/transport-bad-parse"); + p11_test (test_transport_short_error, "/rpc/transport-short-error"); + p11_test (test_transport_invalid_error, "/rpc/transport-invalid-error"); + p11_test (test_transport_wrong_response, "/rpc/transport-wrong-response"); + p11_test (test_transport_bad_contents, "/rpc/transport-bad-contents"); + p11_test (test_get_info_stand_in, "/rpc/get-info-stand-in"); + p11_test (test_get_slot_list_no_device, "/rpc/get-slot-list-no-device"); + p11_test (test_simultaneous_functions, "/rpc/simultaneous-functions"); + p11_test (test_fork_and_reinitialize, "/rpc/fork-and-reinitialize"); + + test_mock_add_tests ("/rpc"); + + return p11_test_run (argc, argv); +} |