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)¶ms, &(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