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