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