aboutsummaryrefslogtreecommitdiff
path: root/test/unit/tcti-device.c
blob: 52ee4e5e29f01b14520afb8a87043e10ff41b1d7 (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
/* SPDX-License-Identifier: BSD-2 */
/***********************************************************************
 * Copyright (c) 2017-2018, Intel Corporation
 *
 * All rights reserved.
 ***********************************************************************/
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>

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

#include "tss2_mu.h"
#include "tss2_tcti_device.h"

#include "tss2-tcti/tcti-common.h"
#include "tss2-tcti/tcti-device.h"

/*
 * Size of the TPM2 buffer used in these tests. In some cases this will be
 * the command sent (transmit tests) and in others it's used as the response
 * buffer returned by the TCTI. The only field used by the TCTI is the size
 * field.
 */
#define BUF_SIZE 20
static uint8_t tpm2_buf [BUF_SIZE] = {
    0x80, 0x02, /* TAG */
    0x00, 0x00, 0x00, 0x14, /* size (BUF_SIZE) */
    0x00, 0x00, 0x00, 0x00, /* rc (success) */
    0xde, 0xad, 0xbe, 0xef, /* junk data */
    0xca, 0xfe, 0xba, 0xbe,
    0xfe, 0xef
};
/**
 * When passed all NULL values ensure that we get back the expected RC
 * indicating bad values.
 */
static void
tcti_device_init_all_null_test (void **state)
{
    TSS2_RC rc;

    rc = Tss2_Tcti_Device_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_device_init_size_test (void **state)
{
    size_t tcti_size = 0;
    TSS2_RC ret = TSS2_RC_SUCCESS;

    ret = Tss2_Tcti_Device_Init (NULL, &tcti_size, NULL);
    assert_int_equal (ret, TSS2_RC_SUCCESS);
}
/* wrap functions for read & write required to test receive / transmit */
ssize_t
__wrap_read (int fd, void *buf, size_t count)
{
    ssize_t ret = mock_type (ssize_t);
    uint8_t *buf_in = mock_type (uint8_t*);

    memcpy (buf, buf_in, ret);
    return ret;
}
ssize_t
__wrap_write (int fd, const void *buffer, size_t buffer_size)
{
    ssize_t ret = mock_type (ssize_t);
    uint8_t *buf_out = mock_type (uint8_t*);

    memcpy (buf_out, buffer, ret);
    return ret;
}

int
__wrap_poll (struct pollfd *fds, nfds_t nfds, int timeout)
{
    int ret = mock_type (int);

    fds->revents = fds->events;
    return ret;
}

/* Setup functions to create the context for the device TCTI */
static int
tcti_device_setup (void **state)
{
    size_t tcti_size = 0;
    TSS2_RC ret = TSS2_RC_SUCCESS;
    TSS2_TCTI_CONTEXT *ctx = NULL;

    ret = Tss2_Tcti_Device_Init (NULL, &tcti_size, NULL);
    assert_true (ret == TSS2_RC_SUCCESS);
    ctx = calloc (1, tcti_size);
    assert_non_null (ctx);
    ret = Tss2_Tcti_Device_Init (ctx, &tcti_size, "/dev/null");
    assert_true (ret == TSS2_RC_SUCCESS);

    *state = ctx;
    return 0;
}

static int
tcti_device_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_device_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);
#ifdef TCTI_ASYNC
    assert_int_equal (rc, TSS2_RC_SUCCESS);
    assert_int_equal (num_handles, 1);
#else
    assert_int_equal (rc, TSS2_TCTI_RC_NOT_IMPLEMENTED);
#endif
}
/*
 */
static void
tcti_device_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);
}
/*
 * A test case for a successful call to the receive function. This requires
 * that the context and the command buffer be valid (including the size
 * field being set appropriately). The result should be an RC indicating
 * success and the size parameter be updated to reflect the size of the
 * data received.
 */
static void
tcti_device_receive_success (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_out [BUF_SIZE + 5] = { 0 };
    size_t size = BUF_SIZE + 5;

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    will_return (__wrap_poll, 1);
    will_return (__wrap_read, BUF_SIZE);
    will_return (__wrap_read, tpm2_buf);
    rc = Tss2_Tcti_Receive (ctx,
                            &size,
                            buf_out,
                            TSS2_TCTI_TIMEOUT_BLOCK);
    assert_true (rc == TSS2_RC_SUCCESS);
    assert_int_equal (BUF_SIZE, size);
    assert_memory_equal (tpm2_buf, buf_out, size);
}
/*
 * Ensure that when the 'read' results in an EOF, we get a response code
 * indicating as much. EOF happens if / when the device driver kills our
 * connection.
 */
static void
tcti_device_receive_eof_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_out [BUF_SIZE + 5] = { 0 };
    size_t size = BUF_SIZE + 5;

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    will_return (__wrap_poll, 1);
    will_return (__wrap_read, 0);
    will_return (__wrap_read, tpm2_buf);
    rc = Tss2_Tcti_Receive (ctx,
                            &size,
                            buf_out,
                            TSS2_TCTI_TIMEOUT_BLOCK);
    assert_int_equal (rc, TSS2_TCTI_RC_NO_CONNECTION);
}
/*
 * This is a weird test: The device TCTI can't read the header for the
 * response buffer separately from the body. This means it can't know the size
 * of the response before reading the whole thing. In the event that the caller
 * provides a buffer that isn't large enough to hold the full response the TCTI
 * will just read as much data as the buffer will hold. Subsequent interactions
 * with the kernel driver will likely result in an error.
 */
static void
tcti_device_receive_buffer_lt_response (void **state)
{
    TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
    TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
    TSS2_RC rc;
    uint8_t buf_out [BUF_SIZE] = { 0 };
    /* set size to lt the size in the header of the TPM2 response buffer */
    size_t size = BUF_SIZE - 1;

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    will_return (__wrap_poll, 1);
    will_return (__wrap_read, size);
    will_return (__wrap_read, tpm2_buf);
    rc = Tss2_Tcti_Receive (ctx,
                            &size,
                            buf_out,
                            TSS2_TCTI_TIMEOUT_BLOCK);
    assert_int_equal (rc, TSS2_TCTI_RC_GENERAL_FAILURE);
}
/*
 * A test case for a successful call to the transmit function. This requires
 * that the context and the cmmand buffer be valid. The only indication of
 * success is the RC.
 */
static void
tcti_device_transmit_success (void **state)
{
    TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
    TSS2_RC rc;
    /* output buffer for response */
    uint8_t buf_out [BUF_SIZE] = { 0 };

    will_return (__wrap_write, BUF_SIZE);
    will_return (__wrap_write, buf_out);
    rc = Tss2_Tcti_Transmit (ctx,
                             BUF_SIZE,
                             tpm2_buf);
    assert_true (rc == TSS2_RC_SUCCESS);
    assert_memory_equal (tpm2_buf, buf_out, BUF_SIZE);
}
/*
 * A test case for a successful poll
 */
static void
tcti_device_poll_success (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_out [BUF_SIZE] = { 0 };
    size_t size = BUF_SIZE;

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    will_return (__wrap_poll, 1);
    will_return (__wrap_read, BUF_SIZE);
    will_return (__wrap_read, tpm2_buf);

    rc = Tss2_Tcti_Receive (ctx,
                            &size,
                            buf_out,
                            TSS2_TCTI_TIMEOUT_BLOCK);

    assert_true (rc == TSS2_RC_SUCCESS);
    assert_int_equal (BUF_SIZE, size);
    assert_memory_equal (tpm2_buf, buf_out, size);
}
/*
 * A test case for poll timeout
 */
static void
tcti_device_poll_timeout (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_out [BUF_SIZE] = { 0 };
    size_t size = BUF_SIZE;

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    will_return (__wrap_poll, 0);

    rc = Tss2_Tcti_Receive (ctx,
                            &size,
                            buf_out,
                            TSS2_TCTI_TIMEOUT_BLOCK);

    assert_true (rc == TSS2_TCTI_RC_TRY_AGAIN);
}
/*
 * A test case for poll io-error
 */
static void
tcti_device_poll_io_error (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_out [BUF_SIZE] = { 0 };
    size_t size = BUF_SIZE;

    /* Keep state machine check in `receive` from returning error. */
    tcti_common->state = TCTI_STATE_RECEIVE;
    will_return (__wrap_poll, -1);

    rc = Tss2_Tcti_Receive (ctx,
                            &size,
                            buf_out,
                            TSS2_TCTI_TIMEOUT_BLOCK);

    assert_true (rc == TSS2_TCTI_RC_IO_ERROR);
}

int
main(int argc, char* argv[])
{
    const struct CMUnitTest tests[] = {
        cmocka_unit_test (tcti_device_init_all_null_test),
        cmocka_unit_test(tcti_device_init_size_test),
        cmocka_unit_test_setup_teardown (tcti_device_get_poll_handles_test,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_receive_null_size_test,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_receive_success,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_receive_eof_test,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_receive_buffer_lt_response,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_transmit_success,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_transmit_success,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_poll_success,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_poll_timeout,
                                         tcti_device_setup,
                                         tcti_device_teardown),
        cmocka_unit_test_setup_teardown (tcti_device_poll_io_error,
                                         tcti_device_setup,
                                         tcti_device_teardown),
    };
    return cmocka_run_group_tests (tests, NULL, NULL);
}