1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /***********************************************************************;
3 * Copyright (c) 2015 - 2018, Intel Corporation
4 * All rights reserved.
5 ***********************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <inttypes.h>
12 #include <limits.h>
13 #include <stdio.h>
14 #include <stdbool.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include <setjmp.h>
19 #include <cmocka.h>
20
21 #include "tss2_tcti.h"
22 #include "tss2_tcti_mssim.h"
23
24 #include "tss2-tcti/tcti-common.h"
25 #include "tss2-tcti/tcti-mssim.h"
26 #include "util/key-value-parse.h"
27
28 /*
29 * This function is defined in the tcti-mssim module but not exposed through
30 * the header.
31 */
32 TSS2_RC
33 mssim_kv_callback (const key_value_t *key_value,
34 void *user_data);
35 /*
36 * This tests our ability to handle conf strings that have a port
37 * component. In this case the 'conf_str_to_host_port' function
38 * should set the 'port' parameter and so we check to be sure it's
39 * set.
40 */
41 static void
conf_str_to_host_port_success_test(void ** state)42 conf_str_to_host_port_success_test (void **state)
43 {
44 TSS2_RC rc;
45 char conf[] = "host=127.0.0.1,port=2321";
46 mssim_conf_t mssim_conf = { 0 };
47
48 rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
49 assert_int_equal (rc, TSS2_RC_SUCCESS);
50 assert_int_equal (mssim_conf.port, 2321);
51 assert_string_equal (mssim_conf.host, "127.0.0.1");
52 }
53
54 /*
55 * This tests our ability to handle conf strings that don't have the port
56 * component of the URI. In this case the 'conf_str_to_host_port' function
57 * should not touch the 'port' parameter and so we check to be sure it's
58 * unchanged.
59 */
60 #define NO_PORT_VALUE 646
61 static void
conf_str_to_host_port_no_port_test(void ** state)62 conf_str_to_host_port_no_port_test (void **state)
63 {
64 TSS2_RC rc;
65 char conf[] = "host=127.0.0.1";
66 mssim_conf_t mssim_conf = {
67 .host = "foo",
68 .port = NO_PORT_VALUE,
69 };
70
71 rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
72 assert_int_equal (rc, TSS2_RC_SUCCESS);
73 assert_string_equal (mssim_conf.host, "127.0.0.1");
74 assert_int_equal (mssim_conf.port, NO_PORT_VALUE);
75 }
76
77 /*
78 * This tests our ability to handle conf strings that have an IPv6 address
79 * and port component. In this case the 'conf_str_to_host_port' function
80 * should set the 'hostname' parameter and so we check to be sure it's
81 * set without the [] brackets.
82 */
83 static void
conf_str_to_host_ipv6_port_success_test(void ** state)84 conf_str_to_host_ipv6_port_success_test (void **state)
85 {
86 TSS2_RC rc;
87 char conf[] = "host=::1,port=2321";
88 mssim_conf_t mssim_conf = { 0 };
89
90 rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
91 assert_int_equal (rc, TSS2_RC_SUCCESS);
92 assert_int_equal (mssim_conf.port, 2321);
93 assert_string_equal (mssim_conf.host, "::1");
94 }
95
96 /*
97 * This tests our ability to handle conf strings that have an IPv6 address
98 * but no port component. In this case the 'conf_str_to_host_port' function
99 * should not touch the 'port' parameter and so we check to be sure it's
100 * unchanged.
101 */
102 static void
conf_str_to_host_ipv6_port_no_port_test(void ** state)103 conf_str_to_host_ipv6_port_no_port_test (void **state)
104 {
105 TSS2_RC rc;
106 char conf[] = "host=::1";
107 mssim_conf_t mssim_conf = { .port = NO_PORT_VALUE };
108
109 rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
110 assert_int_equal (rc, TSS2_RC_SUCCESS);
111 assert_int_equal (mssim_conf.port, NO_PORT_VALUE);
112 assert_string_equal (mssim_conf.host, "::1");
113 }
114
115 /*
116 * The 'conf_str_to_host_port' function rejects ports over UINT16_MAX.
117 */
118 static void
conf_str_to_host_port_invalid_port_large_test(void ** state)119 conf_str_to_host_port_invalid_port_large_test (void **state)
120 {
121 TSS2_RC rc;
122 char conf[] = "host=127.0.0.1,port=99999";
123 mssim_conf_t mssim_conf = { 0 };
124
125 rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
126 assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE);
127 }
128 /* The 'conf_str_to_host_port' function rejects URIs with port == 0 */
129 static void
conf_str_to_host_port_invalid_port_0_test(void ** state)130 conf_str_to_host_port_invalid_port_0_test (void **state)
131 {
132 TSS2_RC rc;
133 char conf[] = "host=127.0.0.1,port=0";
134 mssim_conf_t mssim_conf = { 0 };
135
136 rc = parse_key_value_string (conf, mssim_kv_callback, &mssim_conf);
137 assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE);
138 }
139
140 /* When passed all NULL values ensure that we get back the expected RC. */
141 static void
tcti_socket_init_all_null_test(void ** state)142 tcti_socket_init_all_null_test (void **state)
143 {
144 TSS2_RC rc;
145
146 rc = Tss2_Tcti_Mssim_Init (NULL, NULL, NULL);
147 assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE);
148 }
149 /*
150 * Determine the size of a TCTI context structure. Requires calling the
151 * initialization function for the device TCTI with the first parameter
152 * (the TCTI context) NULL.
153 */
154 static void
tcti_socket_init_size_test(void ** state)155 tcti_socket_init_size_test (void **state)
156 {
157 size_t tcti_size = 0;
158 TSS2_RC ret = TSS2_RC_SUCCESS;
159
160 ret = Tss2_Tcti_Mssim_Init (NULL, &tcti_size, NULL);
161 assert_int_equal (ret, TSS2_RC_SUCCESS);
162 assert_int_equal (tcti_size, sizeof (TSS2_TCTI_MSSIM_CONTEXT));
163 }
164 /*
165 * Wrap the 'connect' system call. The mock queue for this function must have
166 * an integer to return as a response.
167 */
168 int
__wrap_connect(int sockfd,const struct sockaddr * addr,socklen_t addrlen)169 __wrap_connect (int sockfd,
170 const struct sockaddr *addr,
171 socklen_t addrlen)
172 {
173 return mock_type (int);
174 }
175 /*
176 * Wrap the 'recv' system call. The mock queue for this function must have an
177 * integer return value (the number of byts recv'd), as well as a pointer to
178 * a buffer to copy data from to return to the caller.
179 */
180 ssize_t
__wrap_read(int sockfd,void * buf,size_t len)181 __wrap_read (int sockfd,
182 void *buf,
183 size_t len)
184 {
185 ssize_t ret = mock_type (ssize_t);
186 uint8_t *buf_in = mock_ptr_type (uint8_t*);
187
188 memcpy (buf, buf_in, ret);
189 return ret;
190 }
191 /*
192 * Wrap the 'send' system call. The mock queue for this function must have an
193 * integer to return as a response.
194 */
195 ssize_t
__wrap_write(int sockfd,const void * buf,size_t len)196 __wrap_write (int sockfd,
197 const void *buf,
198 size_t len)
199
200 {
201 return mock_type (TSS2_RC);
202 }
203 /*
204 * This is a utility function used by other tests to setup a TCTI context. It
205 * effectively wraps the init / allocate / init pattern as well as priming the
206 * mock functions necessary for a the successful call to
207 * 'Tss2_Tcti_Mssim_Init'.
208 */
209 static TSS2_TCTI_CONTEXT*
tcti_socket_init_from_conf(const char * conf)210 tcti_socket_init_from_conf (const char *conf)
211 {
212 size_t tcti_size = 0;
213 uint8_t recv_buf[4] = { 0 };
214 TSS2_RC ret = TSS2_RC_SUCCESS;
215 TSS2_TCTI_CONTEXT *ctx = NULL;
216
217 printf ("%s: before first init\n", __func__);
218 ret = Tss2_Tcti_Mssim_Init (NULL, &tcti_size, NULL);
219 assert_true (ret == TSS2_RC_SUCCESS);
220 ctx = calloc (1, tcti_size);
221 assert_non_null (ctx);
222 /*
223 * two calls to connect, one for the data socket, one for the command
224 * socket
225 */
226 will_return (__wrap_connect, 0);
227 will_return (__wrap_connect, 0);
228 /*
229 * two 'platform commands are sent on initialization, 4 bytes sent for
230 * each, 4 byte response received (all 0's) for each.
231 */
232 will_return (__wrap_write, 4);
233 will_return (__wrap_read, 4);
234 will_return (__wrap_read, recv_buf);
235 will_return (__wrap_write, 4);
236 will_return (__wrap_read, 4);
237 will_return (__wrap_read, recv_buf);
238 printf ("%s: before second_init\n", __func__);
239 ret = Tss2_Tcti_Mssim_Init (ctx, &tcti_size, conf);
240 printf ("%s: after second init\n", __func__);
241 assert_int_equal (ret, TSS2_RC_SUCCESS);
242 return ctx;
243 }
244
245 /*
246 * This is a utility function to setup the "default" TCTI context.
247 */
248 static int
tcti_socket_setup(void ** state)249 tcti_socket_setup (void **state)
250 {
251 printf ("%s: before tcti_socket_init_from_conf\n", __func__);
252 *state = tcti_socket_init_from_conf ("host=127.0.0.1,port=666");
253 printf ("%s: done\n", __func__);
254 return 0;
255 }
256 static void
tcti_socket_init_null_conf_test(void ** state)257 tcti_socket_init_null_conf_test (void **state)
258 {
259 TSS2_TCTI_CONTEXT *ctx = tcti_socket_init_from_conf (NULL);
260 assert_non_null (ctx);
261 free (ctx);
262 }
263 /*
264 * This is a utility function to teardown a TCTI context allocated by the
265 * tcti_socket_setup function.
266 */
267 static int
tcti_socket_teardown(void ** state)268 tcti_socket_teardown (void **state)
269 {
270 TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
271
272 Tss2_Tcti_Finalize (ctx);
273 free (ctx);
274 return 0;
275 }
276 /*
277 * This test ensures that the GetPollHandles function in the device TCTI
278 * returns the expected value. Since this TCTI does not support async I/O
279 * on account of limitations in the kernel it just returns the
280 * NOT_IMPLEMENTED response code.
281 */
282 static void
tcti_mssim_get_poll_handles_test(void ** state)283 tcti_mssim_get_poll_handles_test (void **state)
284 {
285 TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
286 size_t num_handles = 5;
287 TSS2_TCTI_POLL_HANDLE handles [5] = { 0 };
288 TSS2_RC rc;
289
290 rc = Tss2_Tcti_GetPollHandles (ctx, handles, &num_handles);
291 assert_int_equal (rc, TSS2_TCTI_RC_NOT_IMPLEMENTED);
292 }
293 /*
294 */
295 static void
tcti_socket_receive_null_size_test(void ** state)296 tcti_socket_receive_null_size_test (void **state)
297 {
298 TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
299 TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
300 TSS2_RC rc;
301
302 /* Keep state machine check in `receive` from returning error. */
303 tcti_common->state = TCTI_STATE_RECEIVE;
304 rc = Tss2_Tcti_Receive (ctx,
305 NULL, /* NULL 'size' parameter */
306 NULL,
307 TSS2_TCTI_TIMEOUT_BLOCK);
308 assert_int_equal (rc, TSS2_TCTI_RC_BAD_REFERENCE);
309 rc = Tss2_Tcti_Receive (ctx,
310 NULL, /* NULL 'size' parameter */
311 (uint8_t*)1, /* non-NULL buffer */
312 TSS2_TCTI_TIMEOUT_BLOCK);
313 assert_int_equal (rc, TSS2_TCTI_RC_BAD_REFERENCE);
314 }
315 /*
316 * This test exercises the successful code path through the receive function.
317 */
318 static void
tcti_socket_receive_success_test(void ** state)319 tcti_socket_receive_success_test (void **state)
320 {
321 TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
322 TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
323 TSS2_RC rc = TSS2_RC_SUCCESS;
324 size_t response_size = 0xc;
325 uint8_t response_in [] = { 0x80, 0x02,
326 0x00, 0x00, 0x00, 0x0c,
327 0x00, 0x00, 0x00, 0x00,
328 0x01, 0x02,
329 /* simulator appends 4 bytes of 0's to every response */
330 0x00, 0x00, 0x00, 0x00 };
331 uint8_t response_out [12] = { 0 };
332
333 /* Keep state machine check in `receive` from returning error. */
334 tcti_common->state = TCTI_STATE_RECEIVE;
335 /* receive response size */
336 will_return (__wrap_read, 4);
337 will_return (__wrap_read, &response_in [2]);
338 /* receive tag */
339 will_return (__wrap_read, 2);
340 will_return (__wrap_read, response_in);
341 /* receive size (again) */
342 will_return (__wrap_read, 4);
343 will_return (__wrap_read, &response_in [2]);
344 /* receive the rest of the command */
345 will_return (__wrap_read, 0xc - sizeof (TPM2_ST) - sizeof (UINT32));
346 will_return (__wrap_read, &response_in [6]);
347 /* receive the 4 bytes of 0's appended by the simulator */
348 will_return (__wrap_read, 4);
349 will_return (__wrap_read, &response_in [12]);
350
351 rc = Tss2_Tcti_Receive (ctx, &response_size, response_out, TSS2_TCTI_TIMEOUT_BLOCK);
352 assert_int_equal (rc, TSS2_RC_SUCCESS);
353 assert_memory_equal (response_in, response_out, response_size);
354 }
355 /*
356 */
357 static void
tcti_socket_receive_size_success_test(void ** state)358 tcti_socket_receive_size_success_test (void **state)
359 {
360 TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
361 TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
362 TSS2_RC rc = TSS2_RC_SUCCESS;
363 size_t response_size = 0;
364 uint8_t response_in [] = { 0x80, 0x02,
365 0x00, 0x00, 0x00, 0x0c,
366 0x00, 0x00, 0x00, 0x00,
367 0x01, 0x02,
368 /* simulator appends 4 bytes of 0's to every response */
369 0x00, 0x00, 0x00, 0x00 };
370 uint8_t response_out [12] = { 0 };
371
372 /* Keep state machine check in `receive` from returning error. */
373 tcti_common->state = TCTI_STATE_RECEIVE;
374 /* receive response size */
375 will_return (__wrap_read, 4);
376 will_return (__wrap_read, &response_in [2]);
377 rc = Tss2_Tcti_Receive (ctx, &response_size, NULL, TSS2_TCTI_TIMEOUT_BLOCK);
378
379 assert_int_equal (rc, TSS2_RC_SUCCESS);
380 assert_int_equal (response_size, 0xc);
381 /* receive tag */
382 will_return (__wrap_read, 2);
383 will_return (__wrap_read, response_in);
384 /* receive size (again) */
385 will_return (__wrap_read, 4);
386 will_return (__wrap_read, &response_in [2]);
387 /* receive the rest of the command */
388 will_return (__wrap_read, 0xc - sizeof (TPM2_ST) - sizeof (UINT32));
389 will_return (__wrap_read, &response_in [6]);
390 /* receive the 4 bytes of 0's appended by the simulator */
391 will_return (__wrap_read, 4);
392 will_return (__wrap_read, &response_in [12]);
393
394 rc = Tss2_Tcti_Receive (ctx, &response_size, response_out, TSS2_TCTI_TIMEOUT_BLOCK);
395 assert_int_equal (rc, TSS2_RC_SUCCESS);
396 assert_memory_equal (response_in, response_out, response_size);
397 }
398 /*
399 * This test causes the underlying 'read' call to return 0 / EOF when we
400 * call the TCTI 'receive' function. In this case the TCTI should return an
401 * IO error.
402 */
403 static void
tcti_mssim_receive_eof_first_read_test(void ** state)404 tcti_mssim_receive_eof_first_read_test (void **state)
405 {
406 TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
407 TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
408 TSS2_RC rc;
409 /* output buffer for response */
410 uint8_t buf [TPM_HEADER_SIZE] = { 0 };
411 size_t size = sizeof (buf);
412
413 /* Keep state machine check in `receive` from returning error. */
414 tcti_common->state = TCTI_STATE_RECEIVE;
415 will_return (__wrap_read, 0);
416 will_return (__wrap_read, buf);
417 rc = Tss2_Tcti_Receive (ctx,
418 &size,
419 buf,
420 TSS2_TCTI_TIMEOUT_BLOCK);
421 assert_true (rc == TSS2_TCTI_RC_IO_ERROR);
422 }
423 /*
424 * This test causes the underlying 'read' call to return EOF but only after
425 * a successful read that gets us the response size. This results in the
426 * an IO_ERROR RC being returned.
427 */
428 static void
tcti_mssim_receive_eof_second_read_test(void ** state)429 tcti_mssim_receive_eof_second_read_test (void **state)
430 {
431 TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
432 TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_common_context_cast (ctx);
433 TSS2_RC rc;
434 /* input response buffer */
435 uint8_t response_in [] = { 0x80, 0x02,
436 0x00, 0x00, 0x00, 0x0c,
437 0x00, 0x00, 0x00, 0x00,
438 0x01, 0x02,
439 /* simulator appends 4 bytes of 0's to every response */
440 0x00, 0x00, 0x00, 0x00 };
441 /* output response buffer */
442 uint8_t response_out [12] = { 0 };
443 size_t size = sizeof (response_out);
444
445 /* Keep state machine check in `receive` from returning error. */
446 tcti_common->state = TCTI_STATE_RECEIVE;
447 /* setup response size for first read */
448 will_return (__wrap_read, 4);
449 will_return (__wrap_read, &response_in [2]);
450 /* setup 0 for EOF on second read */
451 will_return (__wrap_read, 0);
452 will_return (__wrap_read, response_in);
453 rc = Tss2_Tcti_Receive (ctx,
454 &size,
455 response_out,
456 TSS2_TCTI_TIMEOUT_BLOCK);
457 assert_true (rc == TSS2_TCTI_RC_IO_ERROR);
458 }
459 /*
460 * This test exercises the successful code path through the transmit function.
461 */
462 static void
tcti_socket_transmit_success_test(void ** state)463 tcti_socket_transmit_success_test (void **state)
464 {
465 TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*)*state;
466 TSS2_RC rc = TSS2_RC_SUCCESS;
467 uint8_t command [] = { 0x80, 0x02,
468 0x00, 0x00, 0x00, 0x0c,
469 0x00, 0x00, 0x00, 0x00,
470 0x01, 0x02 };
471 size_t command_size = sizeof (command);
472
473 /* send the TPM2_SEND_COMMAND code */
474 will_return (__wrap_write, 4);
475 /* send the locality for the command */
476 will_return (__wrap_write, 1);
477 /* send the number of bytes in command */
478 will_return (__wrap_write, 4);
479 /* send the command buffer */
480 will_return (__wrap_write, 0xc);
481 rc = Tss2_Tcti_Transmit (ctx, command_size, command);
482 assert_int_equal (rc, TSS2_RC_SUCCESS);
483 }
484
485 int
main(int argc,char * argv[])486 main (int argc,
487 char *argv[])
488 {
489 const struct CMUnitTest tests[] = {
490 cmocka_unit_test (conf_str_to_host_port_success_test),
491 cmocka_unit_test (conf_str_to_host_port_no_port_test),
492 cmocka_unit_test (conf_str_to_host_ipv6_port_success_test),
493 cmocka_unit_test (conf_str_to_host_ipv6_port_no_port_test),
494 cmocka_unit_test (conf_str_to_host_port_invalid_port_large_test),
495 cmocka_unit_test (conf_str_to_host_port_invalid_port_0_test),
496 cmocka_unit_test (tcti_socket_init_all_null_test),
497 cmocka_unit_test (tcti_socket_init_size_test),
498 cmocka_unit_test (tcti_socket_init_null_conf_test),
499 cmocka_unit_test_setup_teardown (tcti_mssim_get_poll_handles_test,
500 tcti_socket_setup,
501 tcti_socket_teardown),
502 cmocka_unit_test_setup_teardown (tcti_socket_receive_null_size_test,
503 tcti_socket_setup,
504 tcti_socket_teardown),
505 cmocka_unit_test_setup_teardown (tcti_socket_receive_success_test,
506 tcti_socket_setup,
507 tcti_socket_teardown),
508 cmocka_unit_test_setup_teardown (tcti_socket_receive_size_success_test,
509 tcti_socket_setup,
510 tcti_socket_teardown),
511 cmocka_unit_test_setup_teardown (tcti_mssim_receive_eof_first_read_test,
512 tcti_socket_setup,
513 tcti_socket_teardown),
514 cmocka_unit_test_setup_teardown (tcti_mssim_receive_eof_second_read_test,
515 tcti_socket_setup,
516 tcti_socket_teardown),
517 cmocka_unit_test_setup_teardown (tcti_socket_transmit_success_test,
518 tcti_socket_setup,
519 tcti_socket_teardown)
520 };
521 return cmocka_run_group_tests (tests, NULL, NULL);
522 }
523