1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /***********************************************************************;
3 * Copyright (c) 2015 - 2018, Intel Corporation
4 * All rights reserved.
5 ***********************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <inttypes.h>
12 #include <string.h>
13
14 #include "tss2_tpm2_types.h"
15 #include "tss2_mu.h"
16 #include "sysapi_util.h"
17 #include "util/tss2_endian.h"
18 #define LOGMODULE sys
19 #include "util/log.h"
20
Tss2_Sys_ExecuteAsync(TSS2_SYS_CONTEXT * sysContext)21 TSS2_RC Tss2_Sys_ExecuteAsync(TSS2_SYS_CONTEXT *sysContext)
22 {
23 _TSS2_SYS_CONTEXT_BLOB *ctx = syscontext_cast(sysContext);
24 TSS2_RC rval;
25
26 if (!ctx)
27 return TSS2_SYS_RC_BAD_REFERENCE;
28
29 if (ctx->previousStage != CMD_STAGE_PREPARE)
30 return TSS2_SYS_RC_BAD_SEQUENCE;
31
32 rval = Tss2_Tcti_Transmit(ctx->tctiContext,
33 HOST_TO_BE_32(req_header_from_cxt(ctx)->commandSize),
34 ctx->cmdBuffer);
35 if (rval)
36 return rval;
37
38 /* Keep a copy of the cmd header to be able reissue the command
39 * after receiving a TPM error
40 */
41 memcpy(ctx->cmd_header, ctx->cmdBuffer, sizeof(ctx->cmd_header));
42
43 ctx->previousStage = CMD_STAGE_SEND_COMMAND;
44
45 return rval;
46 }
47
Tss2_Sys_ExecuteFinish(TSS2_SYS_CONTEXT * sysContext,int32_t timeout)48 TSS2_RC Tss2_Sys_ExecuteFinish(TSS2_SYS_CONTEXT *sysContext, int32_t timeout)
49 {
50 _TSS2_SYS_CONTEXT_BLOB *ctx = syscontext_cast(sysContext);
51 TSS2_RC rval;
52 size_t response_size = 0;
53
54 if (!ctx)
55 return TSS2_SYS_RC_BAD_REFERENCE;
56
57 if (ctx->previousStage != CMD_STAGE_SEND_COMMAND)
58 return TSS2_SYS_RC_BAD_SEQUENCE;
59
60 /*
61 * Call tcti_receive with NULL response buffer to get the actual size
62 * of the response. If we can read the response in multiple chunks
63 * then the tcti should read the response header first and give us
64 * the acctual size. If not it should set the response size to the
65 * maximum possible size.
66 */
67 rval = Tss2_Tcti_Receive(ctx->tctiContext, &response_size,
68 NULL, timeout);
69 if (rval)
70 return rval;
71
72 if (response_size < sizeof(TPM20_Header_Out)) {
73 ctx->previousStage = CMD_STAGE_PREPARE;
74 return TSS2_SYS_RC_INSUFFICIENT_RESPONSE;
75 }
76 if (response_size > ctx->maxCmdSize) {
77 ctx->previousStage = CMD_STAGE_PREPARE;
78 LOG_ERROR("Response size to big: %zu > %u", response_size, ctx->maxCmdSize);
79 return TSS2_SYS_RC_INSUFFICIENT_CONTEXT;
80 }
81
82 /* Then call receive again with the response buffer to read the response */
83 rval = Tss2_Tcti_Receive(ctx->tctiContext, &response_size,
84 ctx->cmdBuffer, timeout);
85 if (rval == TSS2_TCTI_RC_INSUFFICIENT_BUFFER) {
86 LOG_ERROR("TCTI: Insufficient Buffer.");
87 return TSS2_SYS_RC_INSUFFICIENT_CONTEXT;
88 }
89
90 if (rval)
91 return rval;
92
93 /*
94 * Unmarshal the tag, response size, and response code as soon
95 * as possible. Later processing code should get this data from
96 * the TPM20_Header_Out in the context structure. No need to
97 * unmarshal this stuff again.
98 */
99 ctx->nextData = 0;
100
101 rval = Tss2_MU_TPM2_ST_Unmarshal(ctx->cmdBuffer,
102 ctx->maxCmdSize,
103 &ctx->nextData,
104 &ctx->rsp_header.tag);
105 if (rval) {
106 LOG_ERROR("Unmarshaling response tag. RC=%" PRIx32, rval);
107 return rval;
108 }
109
110 if (ctx->rsp_header.tag != TPM2_ST_SESSIONS &&
111 ctx->rsp_header.tag != TPM2_ST_NO_SESSIONS) {
112 if (ctx->rsp_header.tag == TPM2_ST_RSP_COMMAND) {
113 LOG_ERROR("Unsupported device. The device is a TPM 1.2");
114 return TSS2_SYS_RC_GENERAL_FAILURE;
115 } else {
116 LOG_ERROR("Malformed reponse: Invalid tag in response header: %" PRIx16,
117 ctx->rsp_header.tag);
118 return TSS2_SYS_RC_MALFORMED_RESPONSE;
119 }
120 }
121
122 rval = Tss2_MU_UINT32_Unmarshal(ctx->cmdBuffer,
123 ctx->maxCmdSize,
124 &ctx->nextData,
125 &ctx->rsp_header.responseSize);
126 if (rval)
127 return rval;
128
129 if (ctx->rsp_header.responseSize > ctx->maxCmdSize) {
130 return TSS2_SYS_RC_MALFORMED_RESPONSE;
131 }
132
133 rval = Tss2_MU_UINT32_Unmarshal(ctx->cmdBuffer,
134 ctx->maxCmdSize,
135 &ctx->nextData,
136 &ctx->rsp_header.responseCode);
137 if (rval)
138 return rval;
139
140 rval = ctx->rsp_header.responseCode;
141
142 /* If didn't receive enough response bytes, reset SAPI state machine to
143 * CMD_STAGE_PREPARE. There's nothing else we can do for current command.
144 */
145 if (ctx->rsp_header.responseSize < sizeof(TPM20_Header_Out)) {
146 ctx->previousStage = CMD_STAGE_PREPARE;
147 return TSS2_SYS_RC_INSUFFICIENT_RESPONSE;
148 }
149
150 /* If we received a TPM error then reset SAPI state machine to
151 * CMD_STAGE_PREPARE, and restore the command header so the command
152 * can be reissued without going through the usual *_prepare stage.
153 */
154 if (rval && rval != TPM2_RC_INITIALIZE) {
155 ctx->previousStage = CMD_STAGE_PREPARE;
156 memcpy(ctx->cmdBuffer, ctx->cmd_header, sizeof(ctx->cmd_header));
157 return rval;
158 }
159
160 ctx->previousStage = CMD_STAGE_RECEIVE_RESPONSE;
161 return rval;
162 }
163
Tss2_Sys_Execute(TSS2_SYS_CONTEXT * sysContext)164 TSS2_RC Tss2_Sys_Execute(TSS2_SYS_CONTEXT *sysContext)
165 {
166 TSS2_RC rval;
167
168 if (!sysContext)
169 return TSS2_SYS_RC_BAD_REFERENCE;
170
171 rval = Tss2_Sys_ExecuteAsync(sysContext);
172 if (rval)
173 return rval;
174
175 return Tss2_Sys_ExecuteFinish(sysContext, TSS2_TCTI_TIMEOUT_BLOCK);
176 }
177