blob: 720e7c4b6817093948d6bf67186c42aae7b6f7a7 [file] [log] [blame]
Vadim Bendebury627afc22016-06-19 12:13:18 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
Frans Hendriks589eff72019-06-26 10:43:40 +02003 * Copyright (c) 2018 Eltan B.V.
Vadim Bendebury627afc22016-06-19 12:13:18 -07004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Aaron Durbinee049fa2017-03-25 00:38:45 -05008#include <commonlib/iobuf.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -07009#include <console/console.h>
10#include <stdlib.h>
11#include <string.h>
12
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020013#include "tss_marshaling.h"
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010014#include <security/tpm/tss/vendor/cr50/cr50.h>
Frans Hendriks589eff72019-06-26 10:43:40 +020015#include <security/tpm/tss.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -070016
Arthur Heymans0ca944b2019-11-20 19:51:06 +010017static uint16_t tpm_tag; /* Depends on the command type. */
Vadim Bendebury627afc22016-06-19 12:13:18 -070018
Aaron Durbinee049fa2017-03-25 00:38:45 -050019#define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b)
20#define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b)
21#define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b)
22#define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b)
23
24#define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b)
25#define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b)
26
27static int marshal_startup(struct obuf *ob, struct tpm2_startup *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070028{
Aaron Durbinee049fa2017-03-25 00:38:45 -050029 return obuf_write_be16(ob, cmd_body->startup_type);
Vadim Bendebury627afc22016-06-19 12:13:18 -070030}
31
Joel Kitching2e690ee2018-11-15 16:48:53 +080032static int marshal_shutdown(struct obuf *ob, struct tpm2_shutdown *cmd_body)
33{
34 return obuf_write_be16(ob, cmd_body->shutdown_type);
35}
36
Aaron Durbinee049fa2017-03-25 00:38:45 -050037static int marshal_get_capability(struct obuf *ob,
38 struct tpm2_get_capability *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070039{
Aaron Durbinee049fa2017-03-25 00:38:45 -050040 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070041
Aaron Durbinee049fa2017-03-25 00:38:45 -050042 rc |= obuf_write_be32(ob, cmd_body->capability);
43 rc |= obuf_write_be32(ob, cmd_body->property);
44 rc |= obuf_write_be32(ob, cmd_body->propertyCount);
Vadim Bendeburybc927102016-07-07 10:52:46 -070045
Aaron Durbinee049fa2017-03-25 00:38:45 -050046 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070047}
48
Aaron Durbinee049fa2017-03-25 00:38:45 -050049static int marshal_TPM2B(struct obuf *ob, TPM2B *data)
Vadim Bendebury627afc22016-06-19 12:13:18 -070050{
Aaron Durbinee049fa2017-03-25 00:38:45 -050051 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070052
Aaron Durbinee049fa2017-03-25 00:38:45 -050053 rc |= obuf_write_be16(ob, data->size);
54 rc |= obuf_write(ob, data->buffer, data->size);
Vadim Bendeburybc927102016-07-07 10:52:46 -070055
Aaron Durbinee049fa2017-03-25 00:38:45 -050056 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070057}
58
Aaron Durbinee049fa2017-03-25 00:38:45 -050059static int marshal_TPMA_NV(struct obuf *ob, TPMA_NV *nv)
Vadim Bendebury627afc22016-06-19 12:13:18 -070060{
Aaron Durbinee049fa2017-03-25 00:38:45 -050061 uint32_t v;
Vadim Bendebury627afc22016-06-19 12:13:18 -070062
Aaron Durbinee049fa2017-03-25 00:38:45 -050063 memcpy(&v, nv, sizeof(v));
64 return obuf_write_be32(ob, v);
Vadim Bendebury627afc22016-06-19 12:13:18 -070065}
66
Aaron Durbinee049fa2017-03-25 00:38:45 -050067static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, TPMS_NV_PUBLIC *nvpub)
Vadim Bendebury627afc22016-06-19 12:13:18 -070068{
Aaron Durbinee049fa2017-03-25 00:38:45 -050069 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070070
Aaron Durbinee049fa2017-03-25 00:38:45 -050071 rc |= marshal_TPM_HANDLE(ob, nvpub->nvIndex);
72 rc |= marshal_TPMI_ALG_HASH(ob, nvpub->nameAlg);
73 rc |= marshal_TPMA_NV(ob, &nvpub->attributes);
74 rc |= marshal_TPM2B(ob, &nvpub->authPolicy.b);
75 rc |= obuf_write_be16(ob, nvpub->dataSize);
Vadim Bendebury627afc22016-06-19 12:13:18 -070076
Aaron Durbinee049fa2017-03-25 00:38:45 -050077 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070078}
79
Aaron Durbinee049fa2017-03-25 00:38:45 -050080static int marshal_TPMT_HA(struct obuf *ob, TPMT_HA *tpmtha)
Vadim Bendebury627afc22016-06-19 12:13:18 -070081{
Aaron Durbinee049fa2017-03-25 00:38:45 -050082 int rc = 0;
83
84 rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg);
Frans Hendriksaa771cb2019-09-04 11:10:27 +020085 switch (tpmtha->hashAlg) {
86 case TPM_ALG_SHA1:
87 rc |= obuf_write(ob, tpmtha->digest.sha1,
Frans Hendriks7e220ca2019-06-28 10:18:22 +020088 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
Frans Hendriksaa771cb2019-09-04 11:10:27 +020089 break;
90 case TPM_ALG_SHA256:
91 rc |= obuf_write(ob, tpmtha->digest.sha256,
92 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
93 break;
94 case TPM_ALG_SM3_256:
95 rc |= obuf_write(ob, tpmtha->digest.sm3_256,
96 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
97 break;
98 case TPM_ALG_SHA384:
99 rc |= obuf_write(ob, tpmtha->digest.sha384,
100 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
101 break;
102 case TPM_ALG_SHA512:
103 rc |= obuf_write(ob, tpmtha->digest.sha512,
104 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
105 break;
106 default:
107 rc = -1;
108 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500109 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700110}
111
Aaron Durbinee049fa2017-03-25 00:38:45 -0500112static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
113 TPML_DIGEST_VALUES *dvalues)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700114{
115 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500116 int rc = 0;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700117
Aaron Durbinee049fa2017-03-25 00:38:45 -0500118 rc |= obuf_write_be32(ob, dvalues->count);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700119 for (i = 0; i < dvalues->count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500120 rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
121
122 return rc;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700123}
124
Aaron Durbinee049fa2017-03-25 00:38:45 -0500125static int marshal_session_header(struct obuf *ob,
126 struct tpm2_session_header *session_header)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700127{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500128 int rc = 0;
129 struct obuf ob_sz;
130 size_t prev_written;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700131
Aaron Durbinee049fa2017-03-25 00:38:45 -0500132 /* Snapshot current location to place size of header. */
133 if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
134 return -1;
Vadim Bendeburybc927102016-07-07 10:52:46 -0700135
Aaron Durbinee049fa2017-03-25 00:38:45 -0500136 /* Write a size placeholder. */
137 rc |= obuf_write_be32(ob, 0);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700138
Aaron Durbinee049fa2017-03-25 00:38:45 -0500139 /* Keep track of session header data size by tracking num written. */
140 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700141
Aaron Durbinee049fa2017-03-25 00:38:45 -0500142 rc |= obuf_write_be32(ob, session_header->session_handle);
143 rc |= obuf_write_be16(ob, session_header->nonce_size);
144 rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
145 rc |= obuf_write_be8(ob, session_header->session_attrs);
146 rc |= obuf_write_be16(ob, session_header->auth_size);
147 rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700148
Aaron Durbinee049fa2017-03-25 00:38:45 -0500149 /* Fill back in proper size of session header. */
150 rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700151
Aaron Durbinee049fa2017-03-25 00:38:45 -0500152 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700153}
154
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700155/*
156 * Common session header can include one or two handles and an empty
157 * session_header structure.
158 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500159static int marshal_common_session_header(struct obuf *ob,
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700160 const uint32_t *handles,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500161 size_t handle_count)
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700162{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500163 size_t i;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700164 struct tpm2_session_header session_header;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500165 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700166
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100167 tpm_tag = TPM_ST_SESSIONS;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700168
169 for (i = 0; i < handle_count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500170 rc |= marshal_TPM_HANDLE(ob, handles[i]);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700171
172 memset(&session_header, 0, sizeof(session_header));
173 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500174 rc |= marshal_session_header(ob, &session_header);
175
176 return rc;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700177}
178
Aaron Durbinee049fa2017-03-25 00:38:45 -0500179static int marshal_nv_define_space(struct obuf *ob,
180 struct tpm2_nv_define_space_cmd *nvd_in)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700181{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700182 const uint32_t handle[] = { TPM_RH_PLATFORM };
Aaron Durbinee049fa2017-03-25 00:38:45 -0500183 struct obuf ob_sz;
184 size_t prev_written;
185 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700186
Aaron Durbinee049fa2017-03-25 00:38:45 -0500187 rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
188 rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700189
Aaron Durbinee049fa2017-03-25 00:38:45 -0500190 /* Snapshot current location to place size field. */
191 if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
192 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700193
Aaron Durbinee049fa2017-03-25 00:38:45 -0500194 /* Put placeholder for size */
195 rc |= obuf_write_be16(ob, 0);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700196
Aaron Durbinee049fa2017-03-25 00:38:45 -0500197 /* Keep track of nv define space data size by tracking num written. */
198 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700199
Aaron Durbinee049fa2017-03-25 00:38:45 -0500200 rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
201 rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700202
Aaron Durbinee049fa2017-03-25 00:38:45 -0500203 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700204}
205
Aaron Durbinee049fa2017-03-25 00:38:45 -0500206static int marshal_nv_write(struct obuf *ob,
207 struct tpm2_nv_write_cmd *command_body)
208{
209 int rc = 0;
210 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
211
212 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
213 rc |= marshal_TPM2B(ob, &command_body->data.b);
214 rc |= obuf_write_be16(ob, command_body->offset);
215
216 return rc;
217}
218
219static int marshal_nv_write_lock(struct obuf *ob,
220 struct tpm2_nv_write_lock_cmd *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700221{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700222 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700223
Aaron Durbinee049fa2017-03-25 00:38:45 -0500224 return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700225}
226
Aaron Durbinee049fa2017-03-25 00:38:45 -0500227static int marshal_pcr_extend(struct obuf *ob,
228 struct tpm2_pcr_extend_cmd *command_body)
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700229{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500230 int rc = 0;
231 uint32_t handles[] = { command_body->pcrHandle };
232
233 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
234 rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
235
236 return rc;
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700237}
238
Aaron Durbinee049fa2017-03-25 00:38:45 -0500239static int marshal_nv_read(struct obuf *ob,
240 struct tpm2_nv_read_cmd *command_body)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700241{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500242 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700243 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700244
Aaron Durbinee049fa2017-03-25 00:38:45 -0500245 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
246 rc |= obuf_write_be16(ob, command_body->size);
247 rc |= obuf_write_be16(ob, command_body->offset);
248
249 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700250}
251
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200252/* TPM2_Clear command does not require parameters. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500253static int marshal_clear(struct obuf *ob)
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700254{
255 const uint32_t handle[] = { TPM_RH_PLATFORM };
256
Aaron Durbinee049fa2017-03-25 00:38:45 -0500257 return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700258}
259
Aaron Durbinee049fa2017-03-25 00:38:45 -0500260static int marshal_selftest(struct obuf *ob,
261 struct tpm2_self_test *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700262{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500263 return obuf_write_be8(ob, command_body->yes_no);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700264}
265
Aaron Durbinee049fa2017-03-25 00:38:45 -0500266static int marshal_hierarchy_control(struct obuf *ob,
267 struct tpm2_hierarchy_control_cmd *command_body)
Aaron Durbinf56c7782017-01-10 17:44:42 -0600268{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500269 int rc = 0;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600270 struct tpm2_session_header session_header;
271
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100272 tpm_tag = TPM_ST_SESSIONS;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600273
Aaron Durbinee049fa2017-03-25 00:38:45 -0500274 rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600275 memset(&session_header, 0, sizeof(session_header));
276 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500277 rc |= marshal_session_header(ob, &session_header);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600278
Aaron Durbinee049fa2017-03-25 00:38:45 -0500279 rc |= marshal_TPM_HANDLE(ob, command_body->enable);
280 rc |= obuf_write_be8(ob, command_body->state);
281
282 return rc;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600283}
284
Aaron Durbinee049fa2017-03-25 00:38:45 -0500285static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
Aaron Durbineeb77372017-03-08 11:23:11 -0600286{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500287 int rc = 0;
288 uint16_t *sub_command = command_body;
Aaron Durbineeb77372017-03-08 11:23:11 -0600289
290 switch (*sub_command) {
Keith Shorte0f34002019-02-05 16:15:10 -0700291 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
292 /* The 16-bit timeout parameter is optional for the
293 * IMMEDIATE_RESET command. However in coreboot, the timeout
294 * parameter must be specified.
295 */
296 rc |= obuf_write_be16(ob, sub_command[0]);
297 rc |= obuf_write_be16(ob, sub_command[1]);
298 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600299 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500300 rc |= obuf_write_be16(ob, *sub_command);
Aaron Durbineeb77372017-03-08 11:23:11 -0600301 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700302 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500303 rc |= obuf_write_be16(ob, sub_command[0]);
304 rc |= obuf_write_be16(ob, sub_command[1]);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700305 break;
Keith Shorte371d422019-01-11 07:52:32 -0700306 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
307 rc |= obuf_write_be16(ob, *sub_command);
308 break;
Keith Shorte0f34002019-02-05 16:15:10 -0700309 case TPM2_CR50_SUB_CMD_TPM_MODE:
310 /* The Cr50 TPM_MODE command supports an optional parameter.
311 * When the parameter is present the Cr50 will attempt to change
312 * the TPM state (enable or disable) and returns the new state
313 * in the response. When the parameter is absent, the Cr50
314 * returns the current TPM state.
315 *
316 * coreboot currently only uses the TPM get capability and does
317 * not set a new TPM state with the Cr50.
318 */
319 rc |= obuf_write_be16(ob, *sub_command);
320 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600321 default:
322 /* Unsupported subcommand. */
323 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
324 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500325 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600326 break;
327 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500328 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600329}
330
Aaron Durbinee049fa2017-03-25 00:38:45 -0500331int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700332{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500333 struct obuf ob_hdr;
334 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
335 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700336
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100337 tpm_tag = TPM_ST_NO_SESSIONS;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700338
Aaron Durbinee049fa2017-03-25 00:38:45 -0500339 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
340 return -1;
341
342 /* Write TPM command header with placeholder field values. */
343 rc |= obuf_write_be16(ob, 0);
344 rc |= obuf_write_be32(ob, 0);
345 rc |= obuf_write_be32(ob, command);
346
347 if (rc != 0)
348 return rc;
349
Vadim Bendebury627afc22016-06-19 12:13:18 -0700350 switch (command) {
351 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500352 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700353 break;
354
Joel Kitching2e690ee2018-11-15 16:48:53 +0800355 case TPM2_Shutdown:
356 rc |= marshal_shutdown(ob, tpm_command_body);
357 break;
358
Vadim Bendebury627afc22016-06-19 12:13:18 -0700359 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500360 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700361 break;
362
363 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500364 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700365 break;
366
367 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500368 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700369 break;
370
371 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500372 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700373 break;
374
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700375 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500376 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700377 break;
378
Vadim Bendebury627afc22016-06-19 12:13:18 -0700379 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500380 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700381 break;
382
Aaron Durbinf56c7782017-01-10 17:44:42 -0600383 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500384 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600385 break;
386
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700387 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500388 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700389 break;
390
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700391 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500392 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700393 break;
394
Aaron Durbineeb77372017-03-08 11:23:11 -0600395 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500396 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600397 break;
398
Vadim Bendebury627afc22016-06-19 12:13:18 -0700399 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700400 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
401 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500402 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700403 }
404
Aaron Durbinee049fa2017-03-25 00:38:45 -0500405 if (rc != 0)
406 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700407
Aaron Durbinee049fa2017-03-25 00:38:45 -0500408 /* Fix up the command header with known values. */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100409 rc |= obuf_write_be16(&ob_hdr, tpm_tag);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500410 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700411
Aaron Durbinee049fa2017-03-25 00:38:45 -0500412 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700413}
414
Aaron Durbinee049fa2017-03-25 00:38:45 -0500415static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700416 struct get_cap_response *gcr)
417{
418 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500419 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700420
Aaron Durbinee049fa2017-03-25 00:38:45 -0500421 rc |= ibuf_read_be8(ib, &gcr->more_data);
422 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700423
Aaron Durbinee049fa2017-03-25 00:38:45 -0500424 if (rc != 0)
425 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700426
427 switch (gcr->cd.capability) {
428 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500429 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
430 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700431 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
432 (gcr->cd.data.tpmProperties.tpmProperty)) {
433 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
434 __FILE__, __func__, __LINE__,
435 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500436 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700437 }
438 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
439 TPMS_TAGGED_PROPERTY *pp;
440
441 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500442 rc |= unmarshal_TPM_PT(ib, &pp->property);
443 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700444 }
445 break;
Frans Hendriks589eff72019-06-26 10:43:40 +0200446 case TPM_CAP_PCRS:
447 if (ibuf_read_be32(ib, &gcr->cd.data.assignedPCR.count))
448 return -1;
449 if (gcr->cd.data.assignedPCR.count >
450 ARRAY_SIZE(gcr->cd.data.assignedPCR.pcrSelections)) {
451 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
452 __FILE__, __func__, __LINE__,
453 gcr->cd.data.assignedPCR.count);
454 return -1;
455 }
456 for (i = 0; i < gcr->cd.data.assignedPCR.count; i++) {
457 TPMS_PCR_SELECTION *pp =
458 &gcr->cd.data.assignedPCR.pcrSelections[i];
459 rc |= ibuf_read(ib, pp, sizeof(TPMS_PCR_SELECTION));
460 }
461 break;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700462 default:
463 printk(BIOS_ERR,
464 "%s:%d - unable to unmarshal capability response",
465 __func__, __LINE__);
466 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500467 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700468 break;
469 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500470
471 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700472}
473
Aaron Durbinee049fa2017-03-25 00:38:45 -0500474static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700475 TPM2B_MAX_NV_BUFFER *nv_buffer)
476{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500477 if (ibuf_read_be16(ib, &nv_buffer->t.size))
478 return -1;
479
480 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
481
482 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700483 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500484 "size mismatch: expected %d, remaining %zd\n",
485 __func__, __LINE__, nv_buffer->t.size,
486 ibuf_remaining(ib));
487 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700488 }
489
Aaron Durbinee049fa2017-03-25 00:38:45 -0500490 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700491}
492
Aaron Durbinee049fa2017-03-25 00:38:45 -0500493static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700494{
495 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500496 if (ibuf_read_be32(ib, &nvr->params_size))
497 return -1;
498
499 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
500 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700501
502 if (nvr->params_size !=
503 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
504 printk(BIOS_ERR,
505 "%s:%d - parameter/buffer %d/%d size mismatch",
506 __func__, __LINE__, nvr->params_size,
507 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500508 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700509 }
510
Vadim Bendebury627afc22016-06-19 12:13:18 -0700511 /*
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100512 * Let's ignore the authorization section. It should be 5 bytes total,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700513 * just confirm that this is the case and report any discrepancy.
514 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500515 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700516 printk(BIOS_ERR,
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100517 "%s:%d - unexpected authorization section size %zd\n",
Aaron Durbinee049fa2017-03-25 00:38:45 -0500518 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700519
Aaron Durbinee049fa2017-03-25 00:38:45 -0500520 ibuf_oob_drain(ib, ibuf_remaining(ib));
521
522 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700523}
524
Aaron Durbinee049fa2017-03-25 00:38:45 -0500525static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700526 struct vendor_command_response *vcr)
527{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500528 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
529 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700530
531 switch (vcr->vc_subcommand) {
Keith Shorte0f34002019-02-05 16:15:10 -0700532 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
533 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700534 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
535 break;
536 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500537 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Keith Shorte371d422019-01-11 07:52:32 -0700538 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
539 return ibuf_read_be8(ib, &vcr->recovery_button_state);
Keith Shorte0f34002019-02-05 16:15:10 -0700540 case TPM2_CR50_SUB_CMD_TPM_MODE:
541 return ibuf_read_be8(ib, &vcr->tpm_mode);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700542 default:
543 printk(BIOS_ERR,
544 "%s:%d - unsupported vendor command %#04x!\n",
545 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500546 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700547 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500548
549 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700550}
551
Aaron Durbinee049fa2017-03-25 00:38:45 -0500552struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700553{
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100554 static struct tpm2_response tpm2_static_resp;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500555 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700556
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100557 rc |= ibuf_read_be16(ib, &tpm2_static_resp.hdr.tpm_tag);
558 rc |= ibuf_read_be32(ib, &tpm2_static_resp.hdr.tpm_size);
559 rc |= unmarshal_TPM_CC(ib, &tpm2_static_resp.hdr.tpm_code);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500560
561 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700562 return NULL;
563
Aaron Durbinee049fa2017-03-25 00:38:45 -0500564 if (ibuf_remaining(ib) == 0) {
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100565 if (tpm2_static_resp.hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700566 printk(BIOS_ERR,
567 "%s: size mismatch in response to command %#x\n",
568 __func__, command);
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100569 return &tpm2_static_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700570 }
571
572 switch (command) {
573 case TPM2_Startup:
Joel Kitching2e690ee2018-11-15 16:48:53 +0800574 case TPM2_Shutdown:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700575 break;
576
577 case TPM2_GetCapability:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100578 rc |= unmarshal_get_capability(ib, &tpm2_static_resp.gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700579 break;
580
581 case TPM2_NV_Read:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100582 rc |= unmarshal_nv_read(ib, &tpm2_static_resp.nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700583 break;
584
Aaron Durbinf56c7782017-01-10 17:44:42 -0600585 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700586 case TPM2_Clear:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700587 case TPM2_NV_DefineSpace:
588 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700589 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700590 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700591 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500592 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700593 break;
594
Aaron Durbineeb77372017-03-08 11:23:11 -0600595 case TPM2_CR50_VENDOR_COMMAND:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100596 rc |= unmarshal_vendor_command(ib, &tpm2_static_resp.vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600597 break;
598
Vadim Bendebury627afc22016-06-19 12:13:18 -0700599 default:
600 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500601 size_t i;
602 size_t sz_left;
603 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700604
605 printk(BIOS_INFO, "%s:%d:"
606 "Request to unmarshal unexpected command %#x,"
607 " code %#x",
608 __func__, __LINE__, command,
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100609 tpm2_static_resp.hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700610
Aaron Durbinee049fa2017-03-25 00:38:45 -0500611 sz_left = ibuf_remaining(ib);
612 data = ibuf_oob_drain(ib, sz_left);
613
614 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700615 if (!(i % 16))
616 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500617 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700618 }
619 }
620 printk(BIOS_INFO, "\n");
621 return NULL;
622 }
623
Aaron Durbinee049fa2017-03-25 00:38:45 -0500624 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700625 printk(BIOS_INFO,
626 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500627 " failed to parse (%zd)\n",
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100628 __func__, __LINE__, tpm2_static_resp.hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500629 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700630 return NULL;
631 }
Richard Spiegel248c60a2018-08-07 09:24:14 -0700632 if (rc)
633 printk(BIOS_WARNING, "Warning: %s had one or more failures.\n",
634 __func__);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700635
636 /* The entire message have been parsed. */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100637 return &tpm2_static_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700638}