1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2018 Intel Corporation
4  * All rights reserved.
5  */
6  /* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include <inttypes.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <windows.h>
18 #include <Tbs.h>
19 
20 #include "tss2_tcti.h"
21 #include "tss2_tcti_tbs.h"
22 
23 #include "tcti-common.h"
24 #include "tcti-tbs.h"
25 
26 #define LOGMODULE tcti
27 #include "util/log.h"
28 
29 /*
30  * This function wraps the "up-cast" of the opaque TCTI context type to the
31  * type for the TBS TCTI context. The only safe-guard we have to ensure
32  * this operation is possible is the magic number for the TBS TCTI context.
33  * If passed a NULL context, or the magic number check fails, this function
34  * will return NULL.
35  */
36 TSS2_TCTI_TBS_CONTEXT*
tcti_tbs_context_cast(TSS2_TCTI_CONTEXT * tcti_ctx)37 tcti_tbs_context_cast (TSS2_TCTI_CONTEXT *tcti_ctx)
38 {
39     if (tcti_ctx != NULL && TSS2_TCTI_MAGIC (tcti_ctx) == TCTI_TBS_MAGIC) {
40         return (TSS2_TCTI_TBS_CONTEXT*)tcti_ctx;
41     }
42     return NULL;
43 }
44 
45 /*
46  * This function down-casts the TBS TCTI context to the common context
47  * defined in the tcti-common module.
48  */
49 TSS2_TCTI_COMMON_CONTEXT*
tcti_tbs_down_cast(TSS2_TCTI_TBS_CONTEXT * tcti_tbs)50 tcti_tbs_down_cast (TSS2_TCTI_TBS_CONTEXT *tcti_tbs)
51 {
52     if (tcti_tbs == NULL) {
53         return NULL;
54     }
55     return &tcti_tbs->common;
56 }
57 
58 TSS2_RC
tcti_tbs_transmit(TSS2_TCTI_CONTEXT * tctiContext,size_t command_size,const uint8_t * command_buffer)59 tcti_tbs_transmit (
60     TSS2_TCTI_CONTEXT *tctiContext,
61     size_t command_size,
62     const uint8_t *command_buffer)
63 {
64     TSS2_TCTI_TBS_CONTEXT *tcti_tbs = tcti_tbs_context_cast (tctiContext);
65     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_tbs_down_cast (tcti_tbs);
66     TSS2_RC rc = TSS2_RC_SUCCESS;
67 
68     if (tcti_tbs == NULL) {
69         return TSS2_TCTI_RC_BAD_CONTEXT;
70     }
71     rc = tcti_common_transmit_checks (tcti_common, command_buffer);
72     if (rc != TSS2_RC_SUCCESS) {
73         return rc;
74     }
75 
76     LOGBLOB_DEBUG (command_buffer,
77                    command_size,
78                    "sending %zu byte command buffer:",
79                    command_size);
80 
81     memcpy (tcti_tbs->commandBuffer, command_buffer, command_size);
82     tcti_tbs->commandSize = command_size;
83 
84     tcti_common->state = TCTI_STATE_RECEIVE;
85     return TSS2_RC_SUCCESS;
86 }
87 
88 /*
89  * This receive function deviates from the spec a bit. Calling this function
90  * with a NULL 'response_buffer' parameter *should* result in the required size
91  * for the response buffer being returned to the caller. The required size for
92  * the response buffer is normally stored in the pcbResult parameter of
93  * the 'TBSip_Submit_Command' function by TBS. To avoid having to maintain
94  * a response buffer, we are passing the 'response_buffer' parameter directly to
95  * 'Tbsip_Submit_Command'; this means that in the case when 'response_buffer'
96  * is NULL, we would not be able to retreive the size without losing the response.
97  *
98  * Instead, if the caller queries the size, we return 4k just to be on the
99  * safe side. We do *not* however verify that the provided buffer is large
100  * enough to hold the full response (we can't). If the caller provides us with
101  * a buffer less than 4k we'll read as much of the response as we can given
102  * the size of the buffer. If the response size is larger than the provided
103  * buffer we print a warning. This allows "expert applications" to
104  * precalculate the required response buffer size for whatever commands they
105  * may send.
106  */
107 TSS2_RC
tcti_tbs_receive(TSS2_TCTI_CONTEXT * tctiContext,size_t * response_size,uint8_t * response_buffer,int32_t timeout)108 tcti_tbs_receive (
109     TSS2_TCTI_CONTEXT *tctiContext,
110     size_t *response_size,
111     uint8_t *response_buffer,
112     int32_t timeout)
113 {
114     TSS2_TCTI_TBS_CONTEXT *tcti_tbs = tcti_tbs_context_cast (tctiContext);
115     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_tbs_down_cast (tcti_tbs);
116     TSS2_RC rc = TSS2_RC_SUCCESS;
117     TBS_RESULT tbs_rc;
118     int original_size;
119 
120     if (tcti_tbs == NULL) {
121         return TSS2_TCTI_RC_BAD_CONTEXT;
122     }
123 
124     rc = tcti_common_receive_checks (tcti_common, response_size);
125     if (rc != TSS2_RC_SUCCESS) {
126         return rc;
127     }
128     if (timeout != TSS2_TCTI_TIMEOUT_BLOCK) {
129         LOG_WARNING ("The underlying IPC mechanism does not support "
130                      "asynchronous I/O. The 'timeout' parameter must be "
131                      "TSS2_TCTI_TIMEOUT_BLOCK");
132         return TSS2_TCTI_RC_BAD_VALUE;
133     }
134     if (response_buffer == NULL) {
135         LOG_DEBUG("Caller queried for size but our TCTI TBS implementation doesn't "
136                   "support this, Returning %d which is the max size for "
137                   "a response buffer.",
138                    TPM2_MAX_RESPONSE_SIZE);
139         *response_size = TPM2_MAX_RESPONSE_SIZE;
140         return TSS2_RC_SUCCESS;
141     }
142     if (*response_size < TPM2_MAX_RESPONSE_SIZE) {
143         LOG_INFO("Caller provided buffer that *may* not be large enough to "
144             "hold the response buffer.");
145     }
146 
147     original_size = *response_size;
148 
149     tbs_rc = Tbsip_Submit_Command (tcti_tbs->hContext,
150                                    TBS_COMMAND_LOCALITY_ZERO,
151                                    TBS_COMMAND_PRIORITY_NORMAL,
152                                    tcti_tbs->commandBuffer,
153                                    tcti_tbs->commandSize,
154                                    response_buffer,
155                                    (PUINT32) response_size);
156     if (tbs_rc != TBS_SUCCESS) {
157         LOG_ERROR ("Failed to submit command to TBS with error: 0x%x", tbs_rc);
158         rc = TSS2_TCTI_RC_IO_ERROR;
159         goto out;
160     }
161 
162     LOGBLOB_DEBUG (response_buffer, *response_size, "Response Received");
163 
164     if (original_size < *response_size) {
165         LOG_WARNING("TPM2 response size is larger than the provided "
166             "buffer: future use of this TCTI will likely fail.");
167         rc = TSS2_TCTI_RC_INSUFFICIENT_BUFFER;
168         goto out;
169     }
170 
171     rc = header_unmarshal (response_buffer, &tcti_common->header);
172     if (rc != TSS2_RC_SUCCESS) {
173         goto out;
174     }
175 
176     /*
177      * Executing code beyond this point transitions the state machine to
178      * TRANSMIT. Another call to this function will not be possible until
179      * another command is sent to the TPM.
180      */
181 out:
182     tcti_common->state = TCTI_STATE_TRANSMIT;
183     return rc;
184 }
185 
186 void
tcti_tbs_finalize(TSS2_TCTI_CONTEXT * tctiContext)187 tcti_tbs_finalize (
188     TSS2_TCTI_CONTEXT *tctiContext)
189 {
190     TSS2_TCTI_TBS_CONTEXT *tcti_tbs = tcti_tbs_context_cast (tctiContext);
191     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_tbs_down_cast (tcti_tbs);
192     TBS_RESULT tbs_rc;
193 
194     if (tcti_tbs == NULL) {
195         return;
196     }
197 
198     if (tcti_tbs->commandBuffer!= NULL) {
199         free (tcti_tbs->commandBuffer);
200         tcti_tbs->commandBuffer = NULL;
201     }
202 
203     tbs_rc = Tbsip_Context_Close (tcti_tbs->hContext);
204     if (tbs_rc != TBS_SUCCESS) {
205         LOG_WARNING ("Failed to close context with TBS error: 0x%x", tbs_rc);
206     }
207 
208     tcti_common->state = TCTI_STATE_FINAL;
209 }
210 
211 TSS2_RC
tcti_tbs_cancel(TSS2_TCTI_CONTEXT * tctiContext)212 tcti_tbs_cancel (
213     TSS2_TCTI_CONTEXT *tctiContext)
214 {
215     TBS_RESULT tbs_rc;
216     TSS2_RC rc = TSS2_RC_SUCCESS;
217     TSS2_TCTI_TBS_CONTEXT *tcti_tbs = tcti_tbs_context_cast (tctiContext);
218 
219     tbs_rc = Tbsip_Cancel_Commands (tcti_tbs->hContext);
220     if (tbs_rc != TBS_SUCCESS) {
221         LOG_WARNING ("Failed to cancel commands with TBS error: 0x%x", tbs_rc);
222         rc = TSS2_TCTI_RC_GENERAL_FAILURE;
223     }
224 
225     return rc;
226 }
227 
228 TSS2_RC
tcti_tbs_get_poll_handles(TSS2_TCTI_CONTEXT * tctiContext,TSS2_TCTI_POLL_HANDLE * handles,size_t * num_handles)229 tcti_tbs_get_poll_handles (
230     TSS2_TCTI_CONTEXT *tctiContext,
231     TSS2_TCTI_POLL_HANDLE *handles,
232     size_t *num_handles)
233 {
234     /* TBS doesn't support polling. */
235     (void)(tctiContext);
236     (void)(handles);
237     (void)(num_handles);
238     return TSS2_TCTI_RC_NOT_IMPLEMENTED;
239 }
240 
241 TSS2_RC
tcti_tbs_set_locality(TSS2_TCTI_CONTEXT * tctiContext,uint8_t locality)242 tcti_tbs_set_locality (
243     TSS2_TCTI_CONTEXT *tctiContext,
244     uint8_t locality)
245 {
246     /*
247      * TBS currently only supports locality 0
248      */
249     (void)(tctiContext);
250     (void)(locality);
251     return TSS2_TCTI_RC_NOT_IMPLEMENTED;
252 }
253 
254 TSS2_RC
Tss2_Tcti_Tbs_Init(TSS2_TCTI_CONTEXT * tctiContext,size_t * size,const char * conf)255 Tss2_Tcti_Tbs_Init (
256     TSS2_TCTI_CONTEXT *tctiContext,
257     size_t *size,
258     const char *conf)
259 {
260     TSS2_TCTI_TBS_CONTEXT *tcti_tbs;
261     TSS2_TCTI_COMMON_CONTEXT *tcti_common;
262     TBS_RESULT tbs_rc;
263     TBS_CONTEXT_PARAMS2 params;
264     TPM_DEVICE_INFO info;
265 
266     if (tctiContext == NULL) {
267         if (size == NULL) {
268             return TSS2_TCTI_RC_BAD_VALUE;
269         }
270         *size = sizeof (TSS2_TCTI_TBS_CONTEXT);
271         return TSS2_RC_SUCCESS;
272     }
273 
274     /* Init TCTI context */
275     TSS2_TCTI_MAGIC (tctiContext) = TCTI_TBS_MAGIC;
276     TSS2_TCTI_VERSION (tctiContext) = TCTI_VERSION;
277     TSS2_TCTI_TRANSMIT (tctiContext) = tcti_tbs_transmit;
278     TSS2_TCTI_RECEIVE (tctiContext) = tcti_tbs_receive;
279     TSS2_TCTI_FINALIZE (tctiContext) = tcti_tbs_finalize;
280     TSS2_TCTI_CANCEL (tctiContext) = tcti_tbs_cancel;
281     TSS2_TCTI_GET_POLL_HANDLES (tctiContext) = tcti_tbs_get_poll_handles;
282     TSS2_TCTI_SET_LOCALITY (tctiContext) = tcti_tbs_set_locality;
283     TSS2_TCTI_MAKE_STICKY (tctiContext) = tcti_make_sticky_not_implemented;
284     tcti_tbs = tcti_tbs_context_cast (tctiContext);
285     tcti_common = tcti_tbs_down_cast (tcti_tbs);
286     tcti_common->state = TCTI_STATE_TRANSMIT;
287 
288     memset (&tcti_common->header, 0, sizeof (tcti_common->header));
289     tcti_common->locality = 0;
290 
291     params.includeTpm20 = 1;
292     params.includeTpm12 = 0;
293     params.version = TBS_CONTEXT_VERSION_TWO;
294     tbs_rc = Tbsi_Context_Create ((PCTBS_CONTEXT_PARAMS)&params, &(tcti_tbs->hContext));
295     if (tbs_rc != TBS_SUCCESS) {
296         LOG_WARNING ("Failed to create context with TBS error: 0x%x", tbs_rc);
297         return TSS2_TCTI_RC_IO_ERROR;
298     }
299 
300     tbs_rc = Tbsi_GetDeviceInfo (sizeof (info), &info);
301     if (tbs_rc != TBS_SUCCESS) {
302         LOG_WARNING ("Failed to get device information with TBS error: 0x%x", tbs_rc);
303         Tbsip_Context_Close (tcti_tbs->hContext);
304         return TSS2_TCTI_RC_IO_ERROR;
305     }
306     if (info.tpmVersion != TPM_VERSION_20) {
307         LOG_WARNING ("Failed to create context, TPM version is incorrect");
308         Tbsip_Context_Close (tcti_tbs->hContext);
309         return TSS2_TCTI_RC_IO_ERROR;
310     }
311 
312     tcti_tbs->commandBuffer = malloc (sizeof (BYTE) * TPM2_MAX_COMMAND_SIZE);
313     if (tcti_tbs->commandBuffer == NULL) {
314         LOG_WARNING ("Failed to allocate memory for the result buffer when creating context");
315         Tbsip_Context_Close (tcti_tbs->hContext);
316         return TSS2_TCTI_RC_IO_ERROR;
317     }
318 
319     return TSS2_RC_SUCCESS;
320 }
321 
322 const TSS2_TCTI_INFO tss2_tcti_info = {
323     .version = TCTI_VERSION,
324     .name = "tcti-tbs",
325     .description = "TCTI module for communication with Windows TPM Base Services",
326     .config_help = "Configuration is not used",
327     .init = Tss2_Tcti_Tbs_Init,
328 };
329 
330 const TSS2_TCTI_INFO*
Tss2_Tcti_Info(void)331 Tss2_Tcti_Info (void)
332 {
333     return &tss2_tcti_info;
334 }
335