aboutsummaryrefslogtreecommitdiff
path: root/test/unit/tcti-mssim.c
blob: ee1a04902eba84009a66b2dd97bde6895565acef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
/* SPDX-License-Identifier: BSD-2 */
/***********************************************************************;
 * Copyright (c) 2015 - 2018, Intel Corporation
 * All rights reserved.
 ***********************************************************************/

#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#include <setjmp.h>
#include <cmocka.h>

#include "tss2_tcti.h"
#include "tss2_tcti_mssim.h"

#include "tss2-tcti/tcti-common.h"
#include "tss2-tcti/tcti-mssim.h"
#include "util/key-value-parse.h"

/*
 * This function is defined in the tcti-mssim module but not exposed through
 * the header.
 */
TSS2_RC
mssim_kv_callback (const key_value_t *key_value,
                   void *user_data);
/*
 * This tests our ability to handle conf strings that have a port
 * component. In this case the 'conf_str_to_host_port' function
 * should set the 'port' parameter and so we check to be sure it's
 * set.
 */
static void
conf_str_to_host_port_success_test (void **state)
{
    TSS2_RC rc;
    char conf[] = "host=127.0.0.1,port=2321";
    mssim_conf_t mssim_conf = { 0 };

    rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
    assert_int_equal (rc, TSS2_RC_SUCCESS);
    assert_int_equal (mssim_conf.port, 2321);
    assert_string_equal (mssim_conf.host, "127.0.0.1");
}

/*
 * This tests our ability to handle conf strings that don't have the port
 * component of the URI. In this case the 'conf_str_to_host_port' function
 * should not touch the 'port' parameter and so we check to be sure it's
 * unchanged.
 */
#define NO_PORT_VALUE 646
static void
conf_str_to_host_port_no_port_test (void **state)
{
    TSS2_RC rc;
    char conf[] = "host=127.0.0.1";
    mssim_conf_t mssim_conf = {
        .host = "foo",
        .port = NO_PORT_VALUE,
    };

    rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
    assert_int_equal (rc, TSS2_RC_SUCCESS);
    assert_string_equal (mssim_conf.host, "127.0.0.1");
    assert_int_equal (mssim_conf.port, NO_PORT_VALUE);
}

/*
 * This tests our ability to handle conf strings that have an IPv6 address
 * and port component. In this case the 'conf_str_to_host_port' function
 * should set the 'hostname' parameter and so we check to be sure it's
 * set without the [] brackets.
 */
static void
conf_str_to_host_ipv6_port_success_test (void **state)
{
    TSS2_RC rc;
    char conf[] = "host=::1,port=2321";
    mssim_conf_t mssim_conf = { 0 };

    rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
    assert_int_equal (rc, TSS2_RC_SUCCESS);
    assert_int_equal (mssim_conf.port, 2321);
    assert_string_equal (mssim_conf.host, "::1");
}

/*
 * This tests our ability to handle conf strings that have an IPv6 address
 * but no port component. In this case the 'conf_str_to_host_port' function
 * should not touch the 'port' parameter and so we check to be sure it's
 * unchanged.
 */
static void
conf_str_to_host_ipv6_port_no_port_test (void **state)
{
    TSS2_RC rc;
    char conf[] = "host=::1";
    mssim_conf_t mssim_conf = { .port = NO_PORT_VALUE };

    rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
    assert_int_equal (rc, TSS2_RC_SUCCESS);
    assert_int_equal (mssim_conf.port, NO_PORT_VALUE);
    assert_string_equal (mssim_conf.host, "::1");
}

/*
 * The 'conf_str_to_host_port' function rejects ports over UINT16_MAX.
 */
static void
conf_str_to_host_port_invalid_port_large_test (void **state)
{
    TSS2_RC rc;
    char conf[] = "host=127.0.0.1,port=99999";
    mssim_conf_t mssim_conf = { 0 };

    rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
    assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE);
}
/* The 'conf_str_to_host_port' function rejects URIs with port == 0 */
static void
conf_str_to_host_port_invalid_port_0_test (void **state)
{
    TSS2_RC rc;
    char conf[] = "host=127.0.0.1,port=0";
    mssim_conf_t mssim_conf = { 0 };

    rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
    assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE);
}

/* 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 = Tss2_Tcti_Mssim_Init (NULL, NULL, NULL);
    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 = Tss2_Tcti_Mssim_Init (NULL, &tcti_size, NULL);
    assert_int_equal (ret, TSS2_RC_SUCCESS);
    assert_int_equal (tcti_size, sizeof (TSS2_TCTI_MSSIM_CONTEXT));
}
/*
 * 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 mock_type (int);
}
/*
 * 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_read (int sockfd,
             void *buf,
             size_t len)
{
    ssize_t  ret = mock_type (ssize_t);
    uint8_t *buf_in = mock_ptr_type (uint8_t*);

    memcpy (buf, buf_in, ret);
    return ret;
}
/*
 * Wrap the 'send' system call. The mock queue for this function must have an
 * integer to return as a response.
 */
ssize_t
__wrap_write (int sockfd,
              const void *buf,
              size_t len)

{
    return mock_type (TSS2_RC);
}
/*
 * 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
 * 'Tss2_Tcti_Mssim_Init'.
 */
static TSS2_TCTI_CONTEXT*
tcti_socket_init_from_conf (const char *conf)
{
    size_t tcti_size = 0;
    uint8_t recv_buf[4] = { 0 };
    TSS2_RC ret = TSS2_RC_SUCCESS;
    TSS2_TCTI_CONTEXT *ctx = NULL;

    printf ("%s: before first init\n", __func__);
    ret = Tss2_Tcti_Mssim_Init (NULL, &tcti_size, NULL);
    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 'platform commands are sent on initialization, 4 bytes sent for
     * each, 4 byte response received (all 0's) for each.
     */
    will_return (__wrap_write, 4);
    will_return (__wrap_read, 4);
    will_return (__wrap_read, recv_buf);
    will_return (__wrap_write, 4);
    will_return (__wrap_read, 4);
    will_return (__wrap_read, recv_buf);
    printf ("%s: before second_init\n", __func__);
    ret = Tss2_Tcti_Mssim_Init (ctx, &tcti_size, conf);
    printf ("%s: after second init\n", __func__);
    assert_int_equal (ret, TSS2_RC_SUCCESS);
    return ctx;
}

/*
 * This is a utility function to setup the "default" TCTI context.
 */
static int
tcti_socket_setup (void **state)
{
    printf ("%s: before tcti_socket_init_from_conf\n", __func__);
    *state = tcti_socket_init_from_conf ("host=127.0.0.1,port=666");
    printf ("%s: done\n", __func__);
    return 0;
}
static void
tcti_socket_init_null_conf_test (void **state)
{
    TSS2_TCTI_CONTEXT *ctx = tcti_socket_init_from_conf (NULL);
    assert_non_null (ctx);
    free (ctx);
}
/*
 * 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 ensures that the GetPollHandles function in the device TCTI
 * returns the expected value. Since this TCTI does not support async I/O
 * on account of limitations in the kernel it just returns the
 * NOT_IMPLEMENTED response code.
 */
static void
tcti_mssim_get_poll_handles_test (void **state)
{
    TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
    size_t num_handles = 5;
    TSS2_TCTI_POLL_HANDLE handles [5] = { 0 };
    TSS2_RC rc;

    rc = Tss2_Tcti_GetPollHandles (ctx, handles, &num_handles);
    assert_int_equal (rc, TSS2_TCTI_RC_NOT_IMPLEMENTED);
}
/*
 */
static void
tcti_socket_receive_null_size_test (void **state)
{
    TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
    TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
    TSS2_RC rc;

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    rc = Tss2_Tcti_Receive (ctx,
                            NULL, /* NULL 'size' parameter */
                            NULL,
                            TSS2_TCTI_TIMEOUT_BLOCK);
    assert_int_equal (rc, TSS2_TCTI_RC_BAD_REFERENCE);
    rc = Tss2_Tcti_Receive (ctx,
                            NULL, /* NULL 'size' parameter */
                            (uint8_t*)1, /* non-NULL buffer */
                            TSS2_TCTI_TIMEOUT_BLOCK);
    assert_int_equal (rc, TSS2_TCTI_RC_BAD_REFERENCE);
}
/*
 * 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_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
    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 };

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    /* receive response size */
    will_return (__wrap_read, 4);
    will_return (__wrap_read, &response_in [2]);
    /* receive tag */
    will_return (__wrap_read, 2);
    will_return (__wrap_read, response_in);
    /* receive size (again)  */
    will_return (__wrap_read, 4);
    will_return (__wrap_read, &response_in [2]);
    /* receive the rest of the command */
    will_return (__wrap_read, 0xc - sizeof (TPM2_ST) - sizeof (UINT32));
    will_return (__wrap_read, &response_in [6]);
    /* receive the 4 bytes of 0's appended by the simulator */
    will_return (__wrap_read, 4);
    will_return (__wrap_read, &response_in [12]);

    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);
}
/*
 */
static void
tcti_socket_receive_size_success_test (void **state)
{
    TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
    TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
    TSS2_RC rc = TSS2_RC_SUCCESS;
    size_t response_size = 0;
    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 };

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    /* receive response size */
    will_return (__wrap_read, 4);
    will_return (__wrap_read, &response_in [2]);
    rc = Tss2_Tcti_Receive (ctx, &response_size, NULL, TSS2_TCTI_TIMEOUT_BLOCK);

    assert_int_equal (rc, TSS2_RC_SUCCESS);
    assert_int_equal (response_size, 0xc);
    /* receive tag */
    will_return (__wrap_read, 2);
    will_return (__wrap_read, response_in);
    /* receive size (again)  */
    will_return (__wrap_read, 4);
    will_return (__wrap_read, &response_in [2]);
    /* receive the rest of the command */
    will_return (__wrap_read, 0xc - sizeof (TPM2_ST) - sizeof (UINT32));
    will_return (__wrap_read, &response_in [6]);
    /* receive the 4 bytes of 0's appended by the simulator */
    will_return (__wrap_read, 4);
    will_return (__wrap_read, &response_in [12]);

    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 causes the underlying 'read' call to return 0 / EOF when we
 * call the TCTI 'receive' function. In this case the TCTI should return an
 * IO error.
 */
static void
tcti_mssim_receive_eof_first_read_test (void **state)
{
    TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
    TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
    TSS2_RC rc;
    /* output buffer for response */
    uint8_t buf [TPM_HEADER_SIZE] = { 0 };
    size_t size = sizeof (buf);

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    will_return (__wrap_read, 0);
    will_return (__wrap_read, buf);
    rc = Tss2_Tcti_Receive (ctx,
                            &size,
                            buf,
                            TSS2_TCTI_TIMEOUT_BLOCK);
    assert_true (rc == TSS2_TCTI_RC_IO_ERROR);
}
/*
 * This test causes the underlying 'read' call to return EOF but only after
 * a successful read that gets us the response size. This results in the
 * an IO_ERROR RC being returned.
 */
static void
tcti_mssim_receive_eof_second_read_test (void **state)
{
    TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
    TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
    TSS2_RC rc;
    /* input response buffer */
    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 };
    /* output response buffer */
    uint8_t response_out [12] = { 0 };
    size_t size = sizeof (response_out);

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    /* setup response size for first read */
    will_return (__wrap_read, 4);
    will_return (__wrap_read, &response_in [2]);
    /* setup 0 for EOF on second read */
    will_return (__wrap_read, 0);
    will_return (__wrap_read, response_in);
    rc = Tss2_Tcti_Receive (ctx,
                            &size,
                            response_out,
                            TSS2_TCTI_TIMEOUT_BLOCK);
    assert_true (rc == TSS2_TCTI_RC_IO_ERROR);
}
/*
 * 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 TPM2_SEND_COMMAND code */
    will_return (__wrap_write, 4);
    /* send the locality for the command */
    will_return (__wrap_write, 1);
    /* send the number of bytes in command */
    will_return (__wrap_write, 4);
    /* send the command buffer */
    will_return (__wrap_write, 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 (conf_str_to_host_port_success_test),
        cmocka_unit_test (conf_str_to_host_port_no_port_test),
        cmocka_unit_test (conf_str_to_host_ipv6_port_success_test),
        cmocka_unit_test (conf_str_to_host_ipv6_port_no_port_test),
        cmocka_unit_test (conf_str_to_host_port_invalid_port_large_test),
        cmocka_unit_test (conf_str_to_host_port_invalid_port_0_test),
        cmocka_unit_test (tcti_socket_init_all_null_test),
        cmocka_unit_test (tcti_socket_init_size_test),
        cmocka_unit_test (tcti_socket_init_null_conf_test),
        cmocka_unit_test_setup_teardown (tcti_mssim_get_poll_handles_test,
                                         tcti_socket_setup,
                                         tcti_socket_teardown),
        cmocka_unit_test_setup_teardown (tcti_socket_receive_null_size_test,
                                         tcti_socket_setup,
                                         tcti_socket_teardown),
        cmocka_unit_test_setup_teardown (tcti_socket_receive_success_test,
                                  tcti_socket_setup,
                                  tcti_socket_teardown),
        cmocka_unit_test_setup_teardown (tcti_socket_receive_size_success_test,
                                  tcti_socket_setup,
                                  tcti_socket_teardown),
        cmocka_unit_test_setup_teardown (tcti_mssim_receive_eof_first_read_test,
                                         tcti_socket_setup,
                                         tcti_socket_teardown),
        cmocka_unit_test_setup_teardown (tcti_mssim_receive_eof_second_read_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);
}