1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3 * Copyright 2017, Fraunhofer SIT sponsored by Infineon Technologies AG
4 * All rights reserved.
5 *******************************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <stdbool.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "tss2_esys.h"
16
17 #include "test-esys.h"
18 #include "test-options.h"
19 #include "context-util.h"
20 #include "tss2-esys/esys_int.h"
21 #define LOGMODULE test
22 #include "util/log.h"
23
24 /** Define a proxy tcti that returns yielded on every second invocation
25 * thus the corresponding handling code in ESYS can be tested.
26 * The first invocation will be Tss2_Sys_StartUp.
27 */
28
29 TSS2_RC
30 (*transmit_hook) (const uint8_t *command_buffer, size_t command_size) = NULL;
31
32 #define TCTI_PROXY_MAGIC 0x5250584f0a000000ULL /* 'PROXY\0\0\0' */
33 #define TCTI_PROXY_VERSION 0x1
34
35 enum state {
36 forwarding,
37 intercepting
38 };
39
40 typedef struct {
41 uint64_t magic;
42 uint32_t version;
43 TSS2_TCTI_TRANSMIT_FCN transmit;
44 TSS2_TCTI_RECEIVE_FCN receive;
45 TSS2_RC (*finalize) (TSS2_TCTI_CONTEXT *tctiContext);
46 TSS2_RC (*cancel) (TSS2_TCTI_CONTEXT *tctiContext);
47 TSS2_RC (*getPollHandles) (TSS2_TCTI_CONTEXT *tctiContext,
48 TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles);
49 TSS2_RC (*setLocality) (TSS2_TCTI_CONTEXT *tctiContext, uint8_t locality);
50 TSS2_TCTI_CONTEXT *tctiInner;
51 enum state state;
52 } TSS2_TCTI_CONTEXT_PROXY;
53
54 static TSS2_TCTI_CONTEXT_PROXY*
tcti_proxy_cast(TSS2_TCTI_CONTEXT * ctx)55 tcti_proxy_cast (TSS2_TCTI_CONTEXT *ctx)
56 {
57 TSS2_TCTI_CONTEXT_PROXY *ctxi = (TSS2_TCTI_CONTEXT_PROXY*)ctx;
58 if (ctxi == NULL || ctxi->magic != TCTI_PROXY_MAGIC) {
59 LOG_ERROR("Bad tcti passed.");
60 return NULL;
61 }
62 return ctxi;
63 }
64
65 static TSS2_RC
tcti_proxy_transmit(TSS2_TCTI_CONTEXT * tctiContext,size_t command_size,const uint8_t * command_buffer)66 tcti_proxy_transmit(
67 TSS2_TCTI_CONTEXT *tctiContext,
68 size_t command_size,
69 const uint8_t *command_buffer
70 )
71 {
72 TSS2_RC rval;
73 TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext);
74
75 if (tcti_proxy->state == intercepting) {
76 return TSS2_RC_SUCCESS;
77 }
78
79 if (transmit_hook != NULL) {
80 rval = transmit_hook(command_buffer, command_size);
81 if (rval != TSS2_RC_SUCCESS) {
82 LOG_ERROR("transmit hook requested error");
83 return rval;
84 }
85 }
86
87 rval = Tss2_Tcti_Transmit(tcti_proxy->tctiInner, command_size,
88 command_buffer);
89 if (rval != TSS2_RC_SUCCESS) {
90 LOG_ERROR("Calling TCTI Transmit");
91 return rval;
92 }
93
94 return rval;
95 }
96
97 uint8_t yielded_response[] = {
98 0x80, 0x01, /* TPM_ST_NO_SESSION */
99 0x00, 0x00, 0x00, 0x0A, /* Response Size 10 */
100 0x00, 0x00, 0x09, 0x08 /* TPM_RC_YIELDED */
101 };
102
103 static TSS2_RC
tcti_proxy_receive(TSS2_TCTI_CONTEXT * tctiContext,size_t * response_size,uint8_t * response_buffer,int32_t timeout)104 tcti_proxy_receive(
105 TSS2_TCTI_CONTEXT *tctiContext,
106 size_t *response_size,
107 uint8_t *response_buffer,
108 int32_t timeout
109 )
110 {
111 TSS2_RC rval;
112 TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext);
113
114 if (tcti_proxy->state == intercepting) {
115 *response_size = sizeof(yielded_response);
116
117 if (response_buffer != NULL) {
118 memcpy(response_buffer, &yielded_response[0], sizeof(yielded_response));
119 tcti_proxy->state = forwarding;
120 }
121 return TSS2_RC_SUCCESS;
122 }
123
124 rval = Tss2_Tcti_Receive(tcti_proxy->tctiInner, response_size,
125 response_buffer, timeout);
126 if (rval != TSS2_RC_SUCCESS) {
127 LOG_ERROR("Calling TCTI Transmit");
128 return rval;
129 }
130
131 /* First read with response buffer == NULL is to get the size of the
132 * response. The subsequent read needs to be forwarded also */
133 if (response_buffer != NULL)
134 tcti_proxy->state = intercepting;
135
136 return rval;
137 }
138
139 static void
tcti_proxy_finalize(TSS2_TCTI_CONTEXT * tctiContext)140 tcti_proxy_finalize(
141 TSS2_TCTI_CONTEXT *tctiContext)
142 {
143 memset(tctiContext, 0, sizeof(TSS2_TCTI_CONTEXT_PROXY));
144 }
145
146 static TSS2_RC
tcti_proxy_initialize(TSS2_TCTI_CONTEXT * tctiContext,size_t * contextSize,TSS2_TCTI_CONTEXT * tctiInner)147 tcti_proxy_initialize(
148 TSS2_TCTI_CONTEXT *tctiContext,
149 size_t *contextSize,
150 TSS2_TCTI_CONTEXT *tctiInner)
151 {
152 TSS2_TCTI_CONTEXT_PROXY *tcti_proxy =
153 (TSS2_TCTI_CONTEXT_PROXY*) tctiContext;
154
155 if (tctiContext == NULL && contextSize == NULL) {
156 return TSS2_TCTI_RC_BAD_VALUE;
157 } else if (tctiContext == NULL) {
158 *contextSize = sizeof(*tcti_proxy);
159 return TSS2_RC_SUCCESS;
160 }
161
162 /* Init TCTI context */
163 memset(tcti_proxy, 0, sizeof(*tcti_proxy));
164 TSS2_TCTI_MAGIC (tctiContext) = TCTI_PROXY_MAGIC;
165 TSS2_TCTI_VERSION (tctiContext) = TCTI_PROXY_VERSION;
166 TSS2_TCTI_TRANSMIT (tctiContext) = tcti_proxy_transmit;
167 TSS2_TCTI_RECEIVE (tctiContext) = tcti_proxy_receive;
168 TSS2_TCTI_FINALIZE (tctiContext) = tcti_proxy_finalize;
169 TSS2_TCTI_CANCEL (tctiContext) = NULL;
170 TSS2_TCTI_GET_POLL_HANDLES (tctiContext) = NULL;
171 TSS2_TCTI_SET_LOCALITY (tctiContext) = NULL;
172 tcti_proxy->tctiInner = tctiInner;
173 tcti_proxy->state = forwarding;
174
175 return TSS2_RC_SUCCESS;
176 }
177
178 /**
179 * This program is a template for integration tests (ones that use the TCTI
180 * and the ESYS contexts / API directly). It does nothing more than parsing
181 * command line options that allow the caller (likely a script) to specify
182 * which TCTI to use for the test.
183 */
184 int
main(int argc,char * argv[])185 main(int argc, char *argv[])
186 {
187 TSS2_RC rc;
188 size_t tcti_size;
189 TSS2_TCTI_CONTEXT *tcti_context;
190 TSS2_TCTI_CONTEXT *tcti_inner;
191 ESYS_CONTEXT *esys_context;
192 TSS2_ABI_VERSION abiVersion =
193 { TSSWG_INTEROP, TSS_SAPI_FIRST_FAMILY, TSS_SAPI_FIRST_LEVEL,
194 TSS_SAPI_FIRST_VERSION };
195
196 int ret;
197 test_opts_t opts = {
198 .tcti_type = TCTI_DEFAULT,
199 .device_file = DEVICE_PATH_DEFAULT,
200 .socket_address = HOSTNAME_DEFAULT,
201 .socket_port = PORT_DEFAULT,
202 };
203
204 get_test_opts_from_env(&opts);
205 if (sanity_check_test_opts(&opts) != 0) {
206 LOG_ERROR("TPM Startup FAILED! Error in sanity check");
207 exit(1);
208 }
209 tcti_inner = tcti_init_from_opts(&opts);
210 if (tcti_inner == NULL) {
211 LOG_ERROR("TPM Startup FAILED! Error tcti init");
212 exit(1);
213 }
214 rc = tcti_proxy_initialize(NULL, &tcti_size, tcti_inner);
215 if (rc != TSS2_RC_SUCCESS) {
216 LOG_ERROR("tcti initialization FAILED! Response Code : 0x%x", rc);
217 return 1;
218 }
219 tcti_context = calloc(1, tcti_size);
220 if (tcti_inner == NULL) {
221 LOG_ERROR("TPM Startup FAILED! Error tcti init");
222 exit(1);
223 }
224 rc = tcti_proxy_initialize(tcti_context, &tcti_size, tcti_inner);
225 if (rc != TSS2_RC_SUCCESS) {
226 LOG_ERROR("tcti initialization FAILED! Response Code : 0x%x", rc);
227 return 1;
228 }
229 rc = Esys_Initialize(&esys_context, tcti_context, &abiVersion);
230 if (rc != TSS2_RC_SUCCESS) {
231 LOG_ERROR("Esys_Initialize FAILED! Response Code : 0x%x", rc);
232 return 1;
233 }
234 rc = Esys_Startup(esys_context, TPM2_SU_CLEAR);
235 if (rc != TSS2_RC_SUCCESS && rc != TPM2_RC_INITIALIZE) {
236 LOG_ERROR("Esys_Startup FAILED! Response Code : 0x%x", rc);
237 return 1;
238 }
239
240 rc = Esys_SetTimeout(esys_context, TSS2_TCTI_TIMEOUT_BLOCK);
241 if (rc != TSS2_RC_SUCCESS) {
242 LOG_ERROR("Esys_SetTimeout FAILED! Response Code : 0x%x", rc);
243 return 1;
244 }
245
246 ret = test_invoke_esys(esys_context);
247
248 Esys_Finalize(&esys_context);
249 tcti_teardown(tcti_inner);
250 tcti_teardown(tcti_context);
251 return ret;
252 }
253