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 responseSize = 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 #ifdef TCTI_PARTIAL_READ
61 /*
62 * First call receive with NULL as the response buffer to
63 * get the size of the response
64 */
65 rval = Tss2_Tcti_Receive(ctx->tctiContext, &responseSize,
66 NULL, timeout);
67 if (rval)
68 return rval;
69
70 if (responseSize < sizeof(TPM20_Header_Out)) {
71 ctx->previousStage = CMD_STAGE_PREPARE;
72 return TSS2_SYS_RC_INSUFFICIENT_RESPONSE;
73 }
74 if (responseSize > ctx->maxCmdSize) {
75 ctx->previousStage = CMD_STAGE_PREPARE;
76 return TSS2_SYS_RC_INSUFFICIENT_CONTEXT;
77 }
78 #else
79 /* For none partial reads set the size to maxCmdSize */
80 responseSize = ctx->maxCmdSize;
81 #endif
82
83 /*
84 * Then call receive again with the response buffer to read the response
85 */
86 rval = Tss2_Tcti_Receive(ctx->tctiContext, &responseSize,
87 ctx->cmdBuffer, timeout);
88 if (rval == TSS2_TCTI_RC_INSUFFICIENT_BUFFER)
89 return TSS2_SYS_RC_INSUFFICIENT_CONTEXT;
90
91 if (rval)
92 return rval;
93
94 /*
95 * Unmarshal the tag, response size, and response code as soon
96 * as possible. Later processing code should get this data from
97 * the TPM20_Header_Out in the context structure. No need to
98 * unmarshal this stuff again.
99 */
100 ctx->nextData = 0;
101
102 rval = Tss2_MU_TPM2_ST_Unmarshal(ctx->cmdBuffer,
103 ctx->maxCmdSize,
104 &ctx->nextData,
105 &ctx->rsp_header.tag);
106 if (rval) {
107 LOG_ERROR("Unmarshaling response tag. RC=%" PRIx32, rval);
108 return rval;
109 }
110
111 if (ctx->rsp_header.tag != TPM2_ST_SESSIONS &&
112 ctx->rsp_header.tag != TPM2_ST_NO_SESSIONS) {
113 if (ctx->rsp_header.tag == TPM2_ST_RSP_COMMAND) {
114 LOG_ERROR("Unsupported device. The device is a TPM 1.2");
115 return TSS2_SYS_RC_GENERAL_FAILURE;
116 } else {
117 LOG_ERROR("Malformed reponse: Invalid tag in response header: %" PRIx16,
118 ctx->rsp_header.tag);
119 return TSS2_SYS_RC_MALFORMED_RESPONSE;
120 }
121 }
122
123 rval = Tss2_MU_UINT32_Unmarshal(ctx->cmdBuffer,
124 ctx->maxCmdSize,
125 &ctx->nextData,
126 &ctx->rsp_header.responseSize);
127 if (rval)
128 return rval;
129
130 if (ctx->rsp_header.responseSize > ctx->maxCmdSize) {
131 return TSS2_SYS_RC_MALFORMED_RESPONSE;
132 }
133
134 rval = Tss2_MU_UINT32_Unmarshal(ctx->cmdBuffer,
135 ctx->maxCmdSize,
136 &ctx->nextData,
137 &ctx->rsp_header.responseCode);
138 if (rval)
139 return rval;
140
141 rval = ctx->rsp_header.responseCode;
142
143 /* If didn't receive enough response bytes, reset SAPI state machine to
144 * CMD_STAGE_PREPARE. There's nothing else we can do for current command.
145 */
146 if (ctx->rsp_header.responseSize < sizeof(TPM20_Header_Out)) {
147 ctx->previousStage = CMD_STAGE_PREPARE;
148 return TSS2_SYS_RC_INSUFFICIENT_RESPONSE;
149 }
150
151 /* If we received a TPM error then reset SAPI state machine to
152 * CMD_STAGE_PREPARE, and restore the command header so the command
153 * can be reissued without going through the usual *_prepare stage.
154 */
155 if (rval && rval != TPM2_RC_INITIALIZE) {
156 ctx->previousStage = CMD_STAGE_PREPARE;
157 memcpy(ctx->cmdBuffer, ctx->cmd_header, sizeof(ctx->cmd_header));
158 return rval;
159 }
160
161 ctx->previousStage = CMD_STAGE_RECEIVE_RESPONSE;
162 return rval;
163 }
164
Tss2_Sys_Execute(TSS2_SYS_CONTEXT * sysContext)165 TSS2_RC Tss2_Sys_Execute(TSS2_SYS_CONTEXT *sysContext)
166 {
167 TSS2_RC rval;
168
169 if (!sysContext)
170 return TSS2_SYS_RC_BAD_REFERENCE;
171
172 rval = Tss2_Sys_ExecuteAsync(sysContext);
173 if (rval)
174 return rval;
175
176 return Tss2_Sys_ExecuteFinish(sysContext, TSS2_TCTI_TIMEOUT_BLOCK);
177 }
178