[go: nahoru, domu]

blob: 2e21bf30b91f5742bb87ff241a2d51b1d8d221e0 [file] [log] [blame]
//**********************************************************************;
// Copyright (c) 2017 Intel Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 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 HOLDER 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.
//**********************************************************************;
#include <inttypes.h>
#include <stdio.h>
#include <stdbool.h>
#include <setjmp.h>
#include <cmocka.h>
#include "sapi/tpm20.h"
#include "sysapi/include/tcti_util.h"
#include "tcti/logging.h"
#include "tcti/tcti_socket.h"
/* When passed all NULL values ensure that we get back the expected RC. */
static void
tcti_socket_init_all_null_test (void **state)
{
TSS2_RC rc;
rc = InitSocketTcti (NULL, NULL, NULL, 0);
assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE);
}
/*
* Determine the size of a TCTI context structure. Requires calling the
* initialization function for the device TCTI with the first parameter
* (the TCTI context) NULL.
*/
static void
tcti_socket_init_size_test (void **state)
{
size_t tcti_size = 0;
TSS2_RC ret = TSS2_RC_SUCCESS;
ret = InitSocketTcti (NULL, &tcti_size, NULL, 0);
assert_int_equal (ret, TSS2_RC_SUCCESS);
assert_int_equal (tcti_size, sizeof (TSS2_TCTI_CONTEXT_INTEL));
}
/*
* When passed a non-NULL context blob and size the config structure must
* also be non-NULL. No way to initialize the TCTI otherwise.
*/
static void
tcti_socket_init_null_config_test (void **state)
{
size_t tcti_size;
TSS2_RC rc;
TSS2_TCTI_CONTEXT *tcti_context = (TSS2_TCTI_CONTEXT*)1;
rc = InitSocketTcti (tcti_context, &tcti_size, NULL, 0);
assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE);
}
/*
* Wrap the 'connect' system call. The mock queue for this function must have
* an integer to return as a response.
*/
int
__wrap_connect (int sockfd,
const struct sockaddr *addr,
socklen_t addrlen)
{
return (int)mock ();
}
/*
* Wrap the 'recv' system call. The mock queue for this function must have an
* integer return value (the number of byts recv'd), as well as a pointer to
* a buffer to copy data from to return to the caller.
*/
ssize_t
__wrap_recv (int sockfd,
void *buf,
size_t len,
int flags)
{
ssize_t ret = (ssize_t)mock ();
uint8_t *buf_in = (uint8_t*)mock ();
memcpy (buf, buf_in, ret);
return ret;
}
/*
* Wrap the 'select' system call. The mock queue for this function must have
* an integer to return as a response (the # of fds ready to be read /
* written).
*/
int
__wrap_select (int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout)
{
return (int)mock ();
}
/*
* Wrap the 'send' system call. The mock queue for this function must have an
* integer to return as a response.
*/
ssize_t
__wrap_send (int sockfd,
const void *buf,
size_t len,
int flags)
{
return (TSS2_RC)mock ();
}
/*
* This is a utility function used by other tests to setup a TCTI context. It
* effectively wraps the init / allocate / init pattern as well as priming the
* mock functions necessary for a the successful call to 'InitSocketTcti'.
*/
static TSS2_TCTI_CONTEXT*
tcti_socket_init_from_conf (TCTI_SOCKET_CONF *conf)
{
size_t tcti_size = 0;
uint8_t recv_buf[4] = { 0 };
TSS2_RC ret = TSS2_RC_SUCCESS;
TSS2_TCTI_CONTEXT *ctx = NULL;
ret = InitSocketTcti (NULL, &tcti_size, NULL, 0);
assert_true (ret == TSS2_RC_SUCCESS);
ctx = calloc (1, tcti_size);
assert_non_null (ctx);
/*
* two calls to connect, one for the data socket, one for the command
* socket
*/
will_return (__wrap_connect, 0);
will_return (__wrap_connect, 0);
/*
* two 'PlatformCommands are sent on initialization, 4 bytes sent for
* each, 4 byte response received (all 0's) for each.
*/
will_return (__wrap_send, 4);
will_return (__wrap_recv, 4);
will_return (__wrap_recv, recv_buf);
will_return (__wrap_send, 4);
will_return (__wrap_recv, 4);
will_return (__wrap_recv, recv_buf);
ret = InitSocketTcti (ctx, &tcti_size, conf, 0);
assert_int_equal (ret, TSS2_RC_SUCCESS);
return ctx;
}
/* begin tcti_socket_init_log */
/*
* This test configures the socket TCTI with a logging callback and some user
* data. It checks to be sure that the initialization function sets the
* internal data in the TCTI to use / point to this data accordingly.
*/
int
tcti_socket_init_log_callback (void *data,
printf_type type,
const char *format,
...)
{
return 0;
}
static void
tcti_socket_init_log_test (void **state)
{
uint8_t my_data = 0x9;
TSS2_TCTI_CONTEXT *ctx = NULL;
TCTI_SOCKET_CONF conf = {
"localhost", 666, tcti_socket_init_log_callback, NULL, &my_data
};
ctx = tcti_socket_init_from_conf (&conf);
assert_true (TCTI_LOG_CALLBACK (ctx) == tcti_socket_init_log_callback);
assert_int_equal (*(uint8_t*)TCTI_LOG_DATA (ctx), my_data);
if (ctx)
free (ctx);
}
/* end tcti_socket_init_log */
/* begin tcti_socket_init_buff_log */
/*
* This test configures the socket TCTI with the buffer logging callback and
* some user data. It checks to be sure that the initialization function sets
* the internal data in the TCTI to use / point to this data accordingly.
*/
int
tcti_socket_init_log_buffer_callback (void *data,
printf_type type,
uint8_t *buffer,
uint32_t length)
{
return 0;
}
static void
tcti_socket_init_log_buffer_test (void **state)
{
uint8_t my_data = 0x9;
TSS2_TCTI_CONTEXT *ctx = NULL;
TCTI_SOCKET_CONF conf = {
"localhost", 666, NULL, tcti_socket_init_log_buffer_callback, &my_data
};
ctx = tcti_socket_init_from_conf (&conf);
assert_true (TCTI_LOG_BUFFER_CALLBACK (ctx) == tcti_socket_init_log_buffer_callback);
assert_int_equal (*(uint8_t*)TCTI_LOG_DATA (ctx), my_data);
if (ctx)
free (ctx);
}
/* end tcti_socket_init_log */
/* begin tcti_socket_log_called_test */
/*
* This test configures the socket TCTI with a logging callback and some user
* data. It then invokes the logging function and checks to be sure that the
* supplied user data is changed in the expected way.
*/
int
tcti_socket_log_called_callback (void *data,
printf_type type,
const char *format,
...)
{
*(bool*)data = true;
return 0;
}
static void
tcti_socket_log_called_test (void **state)
{
bool called = false;
TSS2_TCTI_CONTEXT *ctx = NULL;
TCTI_SOCKET_CONF conf = {
"localhost", 666, tcti_socket_log_called_callback, NULL, &called
};
ctx = tcti_socket_init_from_conf (&conf);
TCTI_LOG (ctx, NO_PREFIX, "test log call");
if (ctx)
free (ctx);
assert_true (called);
}
/* end tcti_socket_init_log */
/* begin tcti_socket_log_buffer_called_test */
/*
* This test configures the socket TCTI with the buffer logging callback and
* some user data. It checks to be sure that when invoked, the buffer logging
* callback sets the user data to a known value.
*/
int
tcti_socket_log_buffer_called_callback (void *data,
printf_type type,
uint8_t *buffer,
uint32_t length)
{
*(bool*)data = true;
return 0;
}
static void
tcti_socket_log_buffer_called_test (void **state)
{
bool called = false;
TSS2_TCTI_CONTEXT *ctx = NULL;
TCTI_SOCKET_CONF conf = {
"localhost", 666, NULL, tcti_socket_log_buffer_called_callback, &called
};
ctx = tcti_socket_init_from_conf (&conf);
TCTI_LOG_BUFFER (ctx, NO_PREFIX, NULL, 0);
if (ctx)
free (ctx);
assert_true (called);
}
/* end tcti_socket_init_log */
/*
* This is a utility function to setup the "default" TCTI context.
*/
static int
tcti_socket_setup (void **state)
{
TSS2_TCTI_CONTEXT *ctx = NULL;
TCTI_SOCKET_CONF conf = {
.hostname = "localhost",
.port = 666,
.logCallback = NULL,
.logBufferCallback = NULL,
.logData = NULL
};
ctx = tcti_socket_init_from_conf (&conf);
*state = ctx;
return 0;
}
/*
* This is a utility function to teardown a TCTI context allocated by the
* tcti_socket_setup function.
*/
static int
tcti_socket_teardown (void **state)
{
TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
tss2_tcti_finalize (ctx);
free (ctx);
return 0;
}
/*
* This test exercises the successful code path through the receive function.
*/
static void
tcti_socket_receive_success_test (void **state)
{
TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
TSS2_RC rc = TSS2_RC_SUCCESS;
size_t response_size = 0xc;
uint8_t response_in [] = { 0x80, 0x02,
0x00, 0x00, 0x00, 0x0c,
0x00, 0x00, 0x00, 0x00,
0x01, 0x02,
/* simulator appends 4 bytes of 0's to every response */
0x00, 0x00, 0x00, 0x00 };
uint8_t response_out [12] = { 0 };
uint8_t platform_command_recv [4] = { 0 };
/* select returns 1 fd ready for recv-ing */
will_return (__wrap_select, 1);
/* receive response size */
will_return (__wrap_recv, 4);
will_return (__wrap_recv, &response_in [2]);
/* receive tag */
will_return (__wrap_recv, 2);
will_return (__wrap_recv, response_in);
/* receive size (again) */
will_return (__wrap_recv, 4);
will_return (__wrap_recv, &response_in [2]);
/* receive the rest of the command */
will_return (__wrap_recv, 0xc - sizeof (TPM_ST) - sizeof (UINT32));
will_return (__wrap_recv, &response_in [6]);
/* receive the 4 bytes of 0's appended by the simulator */
will_return (__wrap_recv, 4);
will_return (__wrap_recv, &response_in [12]);
/* platform command sends 4 bytes and receives the same */
will_return (__wrap_send, 4);
will_return (__wrap_recv, 4);
will_return (__wrap_recv, platform_command_recv);
rc = tss2_tcti_receive (ctx, &response_size, response_out, TSS2_TCTI_TIMEOUT_BLOCK);
assert_int_equal (rc, TSS2_RC_SUCCESS);
assert_memory_equal (response_in, response_out, response_size);
}
/*
* This test exercises the successful code path through the transmit function.
*/
static void
tcti_socket_transmit_success_test (void **state)
{
TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
TSS2_RC rc = TSS2_RC_SUCCESS;
uint8_t command [] = { 0x80, 0x02,
0x00, 0x00, 0x00, 0x0c,
0x00, 0x00, 0x00, 0x00,
0x01, 0x02 };
size_t command_size = sizeof (command);
/* send the TPM_SEND_COMMAND code */
will_return (__wrap_send, 4);
/* send the locality for the command */
will_return (__wrap_send, 1);
/* send the number of bytes in command */
will_return (__wrap_send, 4);
/* send the command buffer */
will_return (__wrap_send, 0xc);
rc = tss2_tcti_transmit (ctx, command_size, command);
assert_int_equal (rc, TSS2_RC_SUCCESS);
}
int
main (int argc,
char *argv[])
{
const struct CMUnitTest tests[] = {
cmocka_unit_test (tcti_socket_init_all_null_test),
cmocka_unit_test (tcti_socket_init_size_test),
cmocka_unit_test (tcti_socket_init_null_config_test),
cmocka_unit_test (tcti_socket_init_log_test),
cmocka_unit_test (tcti_socket_init_log_buffer_test),
cmocka_unit_test (tcti_socket_log_called_test),
cmocka_unit_test (tcti_socket_log_buffer_called_test),
cmocka_unit_test_setup_teardown (tcti_socket_receive_success_test,
tcti_socket_setup,
tcti_socket_teardown),
cmocka_unit_test_setup_teardown (tcti_socket_transmit_success_test,
tcti_socket_setup,
tcti_socket_teardown)
};
return cmocka_run_group_tests (tests, NULL, NULL);
}