1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2017, Intel Corporation
4 * All rights reserved.
5 */
6 #include <glib.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9
10 #include <setjmp.h>
11 #include <cmocka.h>
12
13 #include "tpm2-header.h"
14 #include "tpm2-response.h"
15 #include "util.h"
16
17 #define HANDLE_TEST 0xdeadbeef
18 #define HANDLE_TYPE 0xde
19
20 typedef struct {
21 Tpm2Response *response;
22 guint8 *buffer;
23 size_t buffer_size;
24 Connection *connection;
25 } test_data_t;
26 /*
27 * This function does all of the setup required to run a test *except*
28 * for instantiating the Tpm2Response object.
29 */
30 static int
tpm2_response_setup_base(void ** state)31 tpm2_response_setup_base (void **state)
32 {
33 test_data_t *data = NULL;
34 gint client_fd;
35 HandleMap *handle_map;
36 GIOStream *iostream;
37
38 data = calloc (1, sizeof (test_data_t));
39 /* allocate a buffer large enough to hold a TPM2 header and a handle */
40 data->buffer_size = TPM_RESPONSE_HEADER_SIZE + sizeof (TPM2_HANDLE);
41 data->buffer = calloc (1, data->buffer_size);
42 handle_map = handle_map_new (TPM2_HT_TRANSIENT, MAX_ENTRIES_DEFAULT);
43 iostream = create_connection_iostream (&client_fd);
44 data->connection = connection_new (iostream, 0, handle_map);
45 g_object_unref (handle_map);
46 g_object_unref (iostream);
47
48 *state = data;
49 return 0;
50 }
51 /*
52 * This function sets up all required test data with a Tpm2Response
53 * object that has no attributes set.
54 */
55 static int
tpm2_response_setup(void ** state)56 tpm2_response_setup (void **state)
57 {
58 test_data_t *data;
59
60 tpm2_response_setup_base (state);
61 data = (test_data_t*)*state;
62 data->response = tpm2_response_new (data->connection,
63 data->buffer,
64 data->buffer_size,
65 (TPMA_CC){ 0, });
66 return 0;
67 }
68 /*
69 * This function sets up all required test data with a Tpm2Response
70 * object that has attributes indicating the response has a handle
71 * in it.
72 */
73 static int
tpm2_response_setup_with_handle(void ** state)74 tpm2_response_setup_with_handle (void **state)
75 {
76 test_data_t *data;
77 TPMA_CC attributes = 1 << 28;
78
79 tpm2_response_setup_base (state);
80 data = (test_data_t*)*state;
81 data->buffer_size = TPM_RESPONSE_HEADER_SIZE + sizeof (TPM2_HANDLE);
82 data->response = tpm2_response_new (data->connection,
83 data->buffer,
84 data->buffer_size,
85 attributes);
86 set_response_size (data->buffer, data->buffer_size);
87 data->buffer [TPM_RESPONSE_HEADER_SIZE] = 0xde;
88 data->buffer [TPM_RESPONSE_HEADER_SIZE + 1] = 0xad;
89 data->buffer [TPM_RESPONSE_HEADER_SIZE + 2] = 0xbe;
90 data->buffer [TPM_RESPONSE_HEADER_SIZE + 3] = 0xef;
91 return 0;
92 }
93 /**
94 * Tear down all of the data from the setup function. We don't have to
95 * free the data buffer (data->buffer) since the Tpm2Response frees it as
96 * part of its finalize function.
97 */
98 static int
tpm2_response_teardown(void ** state)99 tpm2_response_teardown (void **state)
100 {
101 test_data_t *data = (test_data_t*)*state;
102
103 g_object_unref (data->connection);
104 g_object_unref (data->response);
105 free (data);
106 return 0;
107 }
108 /**
109 * Here we check to be sure that the object instantiated in the setup
110 * function is actually the type that we expect. This is a test to be sure
111 * the type is registered properly with the type system.
112 */
113 static void
tpm2_response_type_test(void ** state)114 tpm2_response_type_test (void **state)
115 {
116 test_data_t *data = (test_data_t*)*state;
117
118 assert_true (G_IS_OBJECT (data->response));
119 assert_true (IS_TPM2_RESPONSE (data->response));
120 }
121 /**
122 * In the setup function we save a reference to the Connection object
123 * instantiated as well as passing it into the Tpm2Response object. Here we
124 * check to be sure that the Connection object returned by the Tpm2Response
125 * object is the same one that we passed it.
126 */
127 static void
tpm2_response_get_connection_test(void ** state)128 tpm2_response_get_connection_test (void **state)
129 {
130 test_data_t *data = (test_data_t*)*state;
131 Connection *connection;
132
133 connection = tpm2_response_get_connection (data->response);
134 assert_int_equal (data->connection, connection);
135 g_object_unref (connection);
136 }
137 /**
138 * In the setup function we passed the Tpm2Response object a data buffer.
139 * Here we check to be sure it passes the same one back to us when we ask
140 * for it.
141 */
142 static void
tpm2_response_get_buffer_test(void ** state)143 tpm2_response_get_buffer_test (void **state)
144 {
145 test_data_t *data = (test_data_t*)*state;
146
147 assert_int_equal (data->buffer, tpm2_response_get_buffer (data->response));
148 }
149 /**
150 * Here we retrieve the data buffer from the Tpm2Response and manually set
151 * the tag part of the response buffer to TPM2_ST_SESSIONS in network byte
152 * order (aka big endian). We then use the tpm2_response_get_tag function
153 * to retrieve this data and we compare it to TPM2_ST_SESSIONS to be sure we
154 * got the value in host byte order.
155 */
156 static void
tpm2_response_get_tag_test(void ** state)157 tpm2_response_get_tag_test (void **state)
158 {
159 test_data_t *data = (test_data_t*)*state;
160 guint8 *buffer = tpm2_response_get_buffer (data->response);
161 TPM2_ST tag_ret;
162
163 /* this is TPM2_ST_SESSIONS in network byte order */
164 buffer[0] = 0x80;
165 buffer[1] = 0x02;
166
167 tag_ret = tpm2_response_get_tag (data->response);
168 assert_int_equal (tag_ret, TPM2_ST_SESSIONS);
169 }
170 /**
171 * Again we're getting the response buffer from the Tpm2Response object
172 * but this time we're setting the additional size field (uint32) to 0x6
173 * in big endian format. We then use the tpm2_response_get_size function
174 * to get this value back and we compare it to 0x6 to be sure it's returned
175 * in host byte order.
176 */
177 static void
tpm2_response_get_size_test(void ** state)178 tpm2_response_get_size_test (void **state)
179 {
180 test_data_t *data = (test_data_t*)*state;
181 guint8 *buffer = tpm2_response_get_buffer (data->response);
182 guint32 size_ret = 0;
183
184 /* this is TPM2_ST_SESSIONS in network byte order */
185 buffer[0] = 0x80;
186 buffer[1] = 0x02;
187 buffer[2] = 0x00;
188 buffer[3] = 0x00;
189 buffer[4] = 0x00;
190 buffer[5] = 0x06;
191
192 size_ret = tpm2_response_get_size (data->response);
193 assert_int_equal (0x6, size_ret);
194 }
195 /**
196 * Again we're getting the response buffer from the Tpm2Response object
197 * but this time we're setting the additional response code field (TPM_RC)
198 * to a known value in big endian format. We then use tpm2_response_get_code
199 * to retrieve the RC and compare it to the appropriate constant to be sure
200 * it's sent back to us in host byte order.
201 */
202 static void
tpm2_response_get_code_test(void ** state)203 tpm2_response_get_code_test (void **state)
204 {
205 test_data_t *data = (test_data_t*)*state;
206 guint8 *buffer = tpm2_response_get_buffer (data->response);
207 TPM2_CC response_code;
208
209 /**
210 * This is TPM2_ST_SESSIONS + a size of 0x0a + the response code for
211 * GetCapability in network byte order
212 */
213 buffer[0] = 0x80;
214 buffer[1] = 0x02;
215 buffer[2] = 0x00;
216 buffer[3] = 0x00;
217 buffer[4] = 0x00;
218 buffer[5] = 0x0a;
219 buffer[6] = 0x00;
220 buffer[7] = 0x00;
221 buffer[8] = 0x01;
222 buffer[9] = 0x00;
223
224 response_code = tpm2_response_get_code (data->response);
225 assert_int_equal (response_code, TPM2_RC_INITIALIZE);
226 }
227 /**
228 * This is a setup function for testing the "short-cut" constructor for the
229 * Tpm2Response object that creates the response buffer with the provided RC.
230 */
231 static int
tpm2_response_new_rc_setup(void ** state)232 tpm2_response_new_rc_setup (void **state)
233 {
234 test_data_t *data = NULL;
235 gint client_fd;
236 GIOStream *iostream;
237 HandleMap *handle_map;
238
239 data = calloc (1, sizeof (test_data_t));
240 /* allocate a buffer large enough to hold a TPM2 header */
241 handle_map = handle_map_new (TPM2_HT_TRANSIENT, MAX_ENTRIES_DEFAULT);
242 iostream = create_connection_iostream (&client_fd);
243 data->connection = connection_new (iostream, 0, handle_map);
244 g_object_unref (handle_map);
245 g_object_unref (iostream);
246 data->response = tpm2_response_new_rc (data->connection, TPM2_RC_BINDING);
247
248 *state = data;
249 return 0;
250 }
251 /**
252 * The tpm2_response_new_rc sets the TPM2_ST_NO_SESSIONS tag for us since
253 * it's just returning an RC and cannot have connections. Here we check to be
254 * sure we can retrieve this tag and that's it's returned in host byte order.
255 */
256 static void
tpm2_response_new_rc_tag_test(void ** state)257 tpm2_response_new_rc_tag_test (void **state)
258 {
259 test_data_t *data = (test_data_t*)*state;
260 TPM2_ST tag = 0;
261
262 tag = tpm2_response_get_tag (data->response);
263 assert_int_equal (tag, TPM2_ST_NO_SESSIONS);
264 }
265 /**
266 * The tpm2_response_new_rc sets the size to the appropriate
267 * TPM_RESPONSE_HEADER size (which is 10 bytes) for us since the response
268 * buffer is just a header. Here we check to be sure that we get this value
269 * back in the proper host byte order.
270 */
271 static void
tpm2_response_new_rc_size_test(void ** state)272 tpm2_response_new_rc_size_test (void **state)
273 {
274 test_data_t *data = (test_data_t*)*state;
275 guint32 size = 0;
276
277 size = tpm2_response_get_size (data->response);
278 assert_int_equal (size, TPM_RESPONSE_HEADER_SIZE);
279 }
280 /**
281 * The tpm2_response_new_rc sets the response code to whatever RC is passed
282 * as a parameter. In the paired setup function we passed it TPM2_RC_BINDING.
283 * This function ensures that we get the same value back from the
284 * tpm2_response_get_code function in the proper host byte order.
285 */
286 static void
tpm2_response_new_rc_code_test(void ** state)287 tpm2_response_new_rc_code_test (void **state)
288 {
289 test_data_t *data = (test_data_t*)*state;
290 TSS2_RC rc = TPM2_RC_SUCCESS;
291
292 rc = tpm2_response_get_code (data->response);
293 assert_int_equal (rc, TPM2_RC_BINDING);
294 }
295 /**
296 * The tpm2_response_new_rc takes a connection as a parameter. We save a
297 * reference to this in the test_data_t structure. Here we ensure that the
298 * tpm2_response_get_connection function returns the same connection to us.
299 */
300 static void
tpm2_response_new_rc_connection_test(void ** state)301 tpm2_response_new_rc_connection_test (void **state)
302 {
303 test_data_t *data = (test_data_t*)*state;
304 Connection *connection = data->connection;
305
306 assert_int_equal (connection, tpm2_response_get_connection (data->response));
307 }
308 /*
309 * This test ensures that a tpm2_response_has_handle reports the
310 * actual value in the TPMA_CC attributes field when the rHandle bit
311 * in the attributes is *not* set.
312 */
313 static void
tpm2_response_no_handle_test(void ** state)314 tpm2_response_no_handle_test (void **state)
315 {
316 test_data_t *data = (test_data_t*)*state;
317 gboolean has_handle;
318
319 has_handle = tpm2_response_has_handle (data->response);
320 assert_false (has_handle);
321 }
322 /*
323 * This test ensures that a tpm2_response_has_handle reports the
324 * actual value in the TPMA_CC attributes field when the rHandle bit
325 * in the attributes *is* set.
326 */
327 static void
tpm2_response_has_handle_test(void ** state)328 tpm2_response_has_handle_test (void **state)
329 {
330 test_data_t *data = (test_data_t*)*state;
331 gboolean has_handle = FALSE;
332
333 has_handle = tpm2_response_has_handle (data->response);
334 assert_true (has_handle);
335 }
336 /*
337 * This tests the Tpm2Response objects ability to return the handle that
338 * we set in the setup function.
339 */
340 static void
tpm2_response_get_handle_test(void ** state)341 tpm2_response_get_handle_test (void **state)
342 {
343 test_data_t *data = (test_data_t*)*state;
344 TPM2_HANDLE handle;
345
346 handle = tpm2_response_get_handle (data->response);
347 assert_int_equal (handle, HANDLE_TEST);
348 }
349 /*
350 * This tests the Tpm2Response object's ability detect an attempt to read
351 * beyond the end of its internal buffer. We fake this by changing the
352 * buffer_size field manually and then trying to access the handle.
353 */
354 static void
tpm2_response_get_handle_no_handle_test(void ** state)355 tpm2_response_get_handle_no_handle_test (void **state)
356 {
357 test_data_t *data = (test_data_t*)*state;
358 TPM2_HANDLE handle;
359
360 data->response->buffer_size = TPM_HEADER_SIZE;
361 handle = tpm2_response_get_handle (data->response);
362 assert_int_equal (handle, 0);
363 }
364 /*
365 * This tests the Tpm2Response objects ability to return the handle type
366 * from the handle we set in the setup function.
367 */
368 static void
tpm2_response_get_handle_type_test(void ** state)369 tpm2_response_get_handle_type_test (void **state)
370 {
371 test_data_t *data = (test_data_t*)*state;
372 TPM2_HT handle_type;
373
374 handle_type = tpm2_response_get_handle_type (data->response);
375 assert_int_equal (handle_type, HANDLE_TYPE);
376 }
377 /*
378 * This tests the Tpm2Response objects ability to set the response handle
379 * field. We do this by first setting the handle to some value and then
380 * querying the Tpm2Response object for the handle. The value returned
381 * should be the handle that we set in the previous call.
382 */
383 static void
tpm2_response_set_handle_test(void ** state)384 tpm2_response_set_handle_test (void **state)
385 {
386 test_data_t *data = (test_data_t*)*state;
387 TPM2_HANDLE handle_in = 0x80fffffe, handle_out = 0;
388
389 tpm2_response_set_handle (data->response, handle_in);
390 handle_out = tpm2_response_get_handle (data->response);
391
392 assert_int_equal (handle_in, handle_out);
393 }
394 /*
395 * This tests the Tpm2Response object's ability detect an attempt to write
396 * beyond the end of its internal buffer. We fake this by changing the
397 * buffer_size field manually and then trying to set the handle.
398 */
399 static void
tpm2_response_set_handle_no_handle_test(void ** state)400 tpm2_response_set_handle_no_handle_test (void **state)
401 {
402 test_data_t *data = (test_data_t*)*state;
403 TPM2_HANDLE handle_in = 0x80fffffe, handle_out = 0;
404
405 data->response->buffer_size = TPM_HEADER_SIZE;
406 tpm2_response_set_handle (data->response, handle_in);
407 handle_out = tpm2_response_get_handle (data->response);
408
409 assert_int_equal (handle_out, 0);
410 }
411 gint
main(void)412 main (void)
413 {
414 const struct CMUnitTest tests[] = {
415 cmocka_unit_test_setup_teardown (tpm2_response_type_test,
416 tpm2_response_setup,
417 tpm2_response_teardown),
418 cmocka_unit_test_setup_teardown (tpm2_response_get_connection_test,
419 tpm2_response_setup,
420 tpm2_response_teardown),
421 cmocka_unit_test_setup_teardown (tpm2_response_get_buffer_test,
422 tpm2_response_setup,
423 tpm2_response_teardown),
424 cmocka_unit_test_setup_teardown (tpm2_response_get_tag_test,
425 tpm2_response_setup,
426 tpm2_response_teardown),
427 cmocka_unit_test_setup_teardown (tpm2_response_get_size_test,
428 tpm2_response_setup,
429 tpm2_response_teardown),
430 cmocka_unit_test_setup_teardown (tpm2_response_get_code_test,
431 tpm2_response_setup,
432 tpm2_response_teardown),
433 cmocka_unit_test_setup_teardown (tpm2_response_new_rc_tag_test,
434 tpm2_response_new_rc_setup,
435 tpm2_response_teardown),
436 cmocka_unit_test_setup_teardown (tpm2_response_new_rc_size_test,
437 tpm2_response_new_rc_setup,
438 tpm2_response_teardown),
439 cmocka_unit_test_setup_teardown (tpm2_response_new_rc_code_test,
440 tpm2_response_new_rc_setup,
441 tpm2_response_teardown),
442 cmocka_unit_test_setup_teardown (tpm2_response_new_rc_connection_test,
443 tpm2_response_new_rc_setup,
444 tpm2_response_teardown),
445 cmocka_unit_test_setup_teardown (tpm2_response_no_handle_test,
446 tpm2_response_setup,
447 tpm2_response_teardown),
448 cmocka_unit_test_setup_teardown (tpm2_response_has_handle_test,
449 tpm2_response_setup_with_handle,
450 tpm2_response_teardown),
451 cmocka_unit_test_setup_teardown (tpm2_response_get_handle_test,
452 tpm2_response_setup_with_handle,
453 tpm2_response_teardown),
454 cmocka_unit_test_setup_teardown (tpm2_response_get_handle_no_handle_test,
455 tpm2_response_setup_with_handle,
456 tpm2_response_teardown),
457 cmocka_unit_test_setup_teardown (tpm2_response_get_handle_type_test,
458 tpm2_response_setup_with_handle,
459 tpm2_response_teardown),
460 cmocka_unit_test_setup_teardown (tpm2_response_set_handle_test,
461 tpm2_response_setup_with_handle,
462 tpm2_response_teardown),
463 cmocka_unit_test_setup_teardown (tpm2_response_set_handle_no_handle_test,
464 tpm2_response_setup_with_handle,
465 tpm2_response_teardown),
466 };
467 return cmocka_run_group_tests (tests, NULL, NULL);
468 }
469