blob: ec3cd8b4b299b14af051259a5e6319a9c723f1b5 [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
Victor Prupisf7060202016-08-19 10:45:04 -07008#include <arch/early_variables.h>
Aaron Durbinee049fa2017-03-25 00:38:45 -05009#include <commonlib/iobuf.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -070010#include <console/console.h>
11#include <stdlib.h>
12#include <string.h>
13
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020014#include "tss_marshaling.h"
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010015#include <security/tpm/tss/vendor/cr50/cr50.h>
Frans Hendriks589eff72019-06-26 10:43:40 +020016#include <security/tpm/tss.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -070017
Victor Prupisf7060202016-08-19 10:45:04 -070018static uint16_t tpm_tag CAR_GLOBAL; /* Depends on the command type. */
Vadim Bendebury627afc22016-06-19 12:13:18 -070019
Aaron Durbinee049fa2017-03-25 00:38:45 -050020#define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b)
21#define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b)
22#define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b)
23#define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b)
24
25#define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b)
26#define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b)
27
28static int marshal_startup(struct obuf *ob, struct tpm2_startup *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070029{
Aaron Durbinee049fa2017-03-25 00:38:45 -050030 return obuf_write_be16(ob, cmd_body->startup_type);
Vadim Bendebury627afc22016-06-19 12:13:18 -070031}
32
Joel Kitching2e690ee2018-11-15 16:48:53 +080033static int marshal_shutdown(struct obuf *ob, struct tpm2_shutdown *cmd_body)
34{
35 return obuf_write_be16(ob, cmd_body->shutdown_type);
36}
37
Aaron Durbinee049fa2017-03-25 00:38:45 -050038static int marshal_get_capability(struct obuf *ob,
39 struct tpm2_get_capability *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070040{
Aaron Durbinee049fa2017-03-25 00:38:45 -050041 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070042
Aaron Durbinee049fa2017-03-25 00:38:45 -050043 rc |= obuf_write_be32(ob, cmd_body->capability);
44 rc |= obuf_write_be32(ob, cmd_body->property);
45 rc |= obuf_write_be32(ob, cmd_body->propertyCount);
Vadim Bendeburybc927102016-07-07 10:52:46 -070046
Aaron Durbinee049fa2017-03-25 00:38:45 -050047 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070048}
49
Aaron Durbinee049fa2017-03-25 00:38:45 -050050static int marshal_TPM2B(struct obuf *ob, TPM2B *data)
Vadim Bendebury627afc22016-06-19 12:13:18 -070051{
Aaron Durbinee049fa2017-03-25 00:38:45 -050052 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070053
Aaron Durbinee049fa2017-03-25 00:38:45 -050054 rc |= obuf_write_be16(ob, data->size);
55 rc |= obuf_write(ob, data->buffer, data->size);
Vadim Bendeburybc927102016-07-07 10:52:46 -070056
Aaron Durbinee049fa2017-03-25 00:38:45 -050057 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070058}
59
Aaron Durbinee049fa2017-03-25 00:38:45 -050060static int marshal_TPMA_NV(struct obuf *ob, TPMA_NV *nv)
Vadim Bendebury627afc22016-06-19 12:13:18 -070061{
Aaron Durbinee049fa2017-03-25 00:38:45 -050062 uint32_t v;
Vadim Bendebury627afc22016-06-19 12:13:18 -070063
Aaron Durbinee049fa2017-03-25 00:38:45 -050064 memcpy(&v, nv, sizeof(v));
65 return obuf_write_be32(ob, v);
Vadim Bendebury627afc22016-06-19 12:13:18 -070066}
67
Aaron Durbinee049fa2017-03-25 00:38:45 -050068static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, TPMS_NV_PUBLIC *nvpub)
Vadim Bendebury627afc22016-06-19 12:13:18 -070069{
Aaron Durbinee049fa2017-03-25 00:38:45 -050070 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070071
Aaron Durbinee049fa2017-03-25 00:38:45 -050072 rc |= marshal_TPM_HANDLE(ob, nvpub->nvIndex);
73 rc |= marshal_TPMI_ALG_HASH(ob, nvpub->nameAlg);
74 rc |= marshal_TPMA_NV(ob, &nvpub->attributes);
75 rc |= marshal_TPM2B(ob, &nvpub->authPolicy.b);
76 rc |= obuf_write_be16(ob, nvpub->dataSize);
Vadim Bendebury627afc22016-06-19 12:13:18 -070077
Aaron Durbinee049fa2017-03-25 00:38:45 -050078 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070079}
80
Aaron Durbinee049fa2017-03-25 00:38:45 -050081static int marshal_TPMT_HA(struct obuf *ob, TPMT_HA *tpmtha)
Vadim Bendebury627afc22016-06-19 12:13:18 -070082{
Aaron Durbinee049fa2017-03-25 00:38:45 -050083 int rc = 0;
84
85 rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg);
86 rc |= obuf_write(ob, tpmtha->digest.sha256,
Frans Hendriks7e220ca2019-06-28 10:18:22 +020087 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
Aaron Durbinee049fa2017-03-25 00:38:45 -050088
89 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070090}
91
Aaron Durbinee049fa2017-03-25 00:38:45 -050092static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
93 TPML_DIGEST_VALUES *dvalues)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070094{
95 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -050096 int rc = 0;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070097
Aaron Durbinee049fa2017-03-25 00:38:45 -050098 rc |= obuf_write_be32(ob, dvalues->count);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070099 for (i = 0; i < dvalues->count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500100 rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
101
102 return rc;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700103}
104
Aaron Durbinee049fa2017-03-25 00:38:45 -0500105static int marshal_session_header(struct obuf *ob,
106 struct tpm2_session_header *session_header)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700107{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500108 int rc = 0;
109 struct obuf ob_sz;
110 size_t prev_written;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700111
Aaron Durbinee049fa2017-03-25 00:38:45 -0500112 /* Snapshot current location to place size of header. */
113 if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
114 return -1;
Vadim Bendeburybc927102016-07-07 10:52:46 -0700115
Aaron Durbinee049fa2017-03-25 00:38:45 -0500116 /* Write a size placeholder. */
117 rc |= obuf_write_be32(ob, 0);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700118
Aaron Durbinee049fa2017-03-25 00:38:45 -0500119 /* Keep track of session header data size by tracking num written. */
120 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700121
Aaron Durbinee049fa2017-03-25 00:38:45 -0500122 rc |= obuf_write_be32(ob, session_header->session_handle);
123 rc |= obuf_write_be16(ob, session_header->nonce_size);
124 rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
125 rc |= obuf_write_be8(ob, session_header->session_attrs);
126 rc |= obuf_write_be16(ob, session_header->auth_size);
127 rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700128
Aaron Durbinee049fa2017-03-25 00:38:45 -0500129 /* Fill back in proper size of session header. */
130 rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700131
Aaron Durbinee049fa2017-03-25 00:38:45 -0500132 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700133}
134
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700135/*
136 * Common session header can include one or two handles and an empty
137 * session_header structure.
138 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500139static int marshal_common_session_header(struct obuf *ob,
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700140 const uint32_t *handles,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500141 size_t handle_count)
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700142{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500143 size_t i;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700144 struct tpm2_session_header session_header;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500145 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700146
Victor Prupisf7060202016-08-19 10:45:04 -0700147 car_set_var(tpm_tag, TPM_ST_SESSIONS);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700148
149 for (i = 0; i < handle_count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500150 rc |= marshal_TPM_HANDLE(ob, handles[i]);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700151
152 memset(&session_header, 0, sizeof(session_header));
153 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500154 rc |= marshal_session_header(ob, &session_header);
155
156 return rc;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700157}
158
Aaron Durbinee049fa2017-03-25 00:38:45 -0500159static int marshal_nv_define_space(struct obuf *ob,
160 struct tpm2_nv_define_space_cmd *nvd_in)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700161{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700162 const uint32_t handle[] = { TPM_RH_PLATFORM };
Aaron Durbinee049fa2017-03-25 00:38:45 -0500163 struct obuf ob_sz;
164 size_t prev_written;
165 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700166
Aaron Durbinee049fa2017-03-25 00:38:45 -0500167 rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
168 rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700169
Aaron Durbinee049fa2017-03-25 00:38:45 -0500170 /* Snapshot current location to place size field. */
171 if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
172 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700173
Aaron Durbinee049fa2017-03-25 00:38:45 -0500174 /* Put placeholder for size */
175 rc |= obuf_write_be16(ob, 0);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700176
Aaron Durbinee049fa2017-03-25 00:38:45 -0500177 /* Keep track of nv define space data size by tracking num written. */
178 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700179
Aaron Durbinee049fa2017-03-25 00:38:45 -0500180 rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
181 rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700182
Aaron Durbinee049fa2017-03-25 00:38:45 -0500183 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700184}
185
Aaron Durbinee049fa2017-03-25 00:38:45 -0500186static int marshal_nv_write(struct obuf *ob,
187 struct tpm2_nv_write_cmd *command_body)
188{
189 int rc = 0;
190 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
191
192 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
193 rc |= marshal_TPM2B(ob, &command_body->data.b);
194 rc |= obuf_write_be16(ob, command_body->offset);
195
196 return rc;
197}
198
199static int marshal_nv_write_lock(struct obuf *ob,
200 struct tpm2_nv_write_lock_cmd *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700201{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700202 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700203
Aaron Durbinee049fa2017-03-25 00:38:45 -0500204 return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700205}
206
Aaron Durbinee049fa2017-03-25 00:38:45 -0500207static int marshal_pcr_extend(struct obuf *ob,
208 struct tpm2_pcr_extend_cmd *command_body)
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700209{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500210 int rc = 0;
211 uint32_t handles[] = { command_body->pcrHandle };
212
213 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
214 rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
215
216 return rc;
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700217}
218
Aaron Durbinee049fa2017-03-25 00:38:45 -0500219static int marshal_nv_read(struct obuf *ob,
220 struct tpm2_nv_read_cmd *command_body)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700221{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500222 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700223 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700224
Aaron Durbinee049fa2017-03-25 00:38:45 -0500225 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
226 rc |= obuf_write_be16(ob, command_body->size);
227 rc |= obuf_write_be16(ob, command_body->offset);
228
229 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700230}
231
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200232/* TPM2_Clear command does not require parameters. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500233static int marshal_clear(struct obuf *ob)
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700234{
235 const uint32_t handle[] = { TPM_RH_PLATFORM };
236
Aaron Durbinee049fa2017-03-25 00:38:45 -0500237 return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700238}
239
Aaron Durbinee049fa2017-03-25 00:38:45 -0500240static int marshal_selftest(struct obuf *ob,
241 struct tpm2_self_test *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700242{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500243 return obuf_write_be8(ob, command_body->yes_no);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700244}
245
Aaron Durbinee049fa2017-03-25 00:38:45 -0500246static int marshal_hierarchy_control(struct obuf *ob,
247 struct tpm2_hierarchy_control_cmd *command_body)
Aaron Durbinf56c7782017-01-10 17:44:42 -0600248{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500249 int rc = 0;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600250 struct tpm2_session_header session_header;
251
252 car_set_var(tpm_tag, TPM_ST_SESSIONS);
253
Aaron Durbinee049fa2017-03-25 00:38:45 -0500254 rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600255 memset(&session_header, 0, sizeof(session_header));
256 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500257 rc |= marshal_session_header(ob, &session_header);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600258
Aaron Durbinee049fa2017-03-25 00:38:45 -0500259 rc |= marshal_TPM_HANDLE(ob, command_body->enable);
260 rc |= obuf_write_be8(ob, command_body->state);
261
262 return rc;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600263}
264
Aaron Durbinee049fa2017-03-25 00:38:45 -0500265static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
Aaron Durbineeb77372017-03-08 11:23:11 -0600266{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500267 int rc = 0;
268 uint16_t *sub_command = command_body;
Aaron Durbineeb77372017-03-08 11:23:11 -0600269
270 switch (*sub_command) {
Keith Shorte0f34002019-02-05 16:15:10 -0700271 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
272 /* The 16-bit timeout parameter is optional for the
273 * IMMEDIATE_RESET command. However in coreboot, the timeout
274 * parameter must be specified.
275 */
276 rc |= obuf_write_be16(ob, sub_command[0]);
277 rc |= obuf_write_be16(ob, sub_command[1]);
278 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600279 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500280 rc |= obuf_write_be16(ob, *sub_command);
Aaron Durbineeb77372017-03-08 11:23:11 -0600281 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700282 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500283 rc |= obuf_write_be16(ob, sub_command[0]);
284 rc |= obuf_write_be16(ob, sub_command[1]);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700285 break;
Keith Shorte371d422019-01-11 07:52:32 -0700286 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
287 rc |= obuf_write_be16(ob, *sub_command);
288 break;
Keith Shorte0f34002019-02-05 16:15:10 -0700289 case TPM2_CR50_SUB_CMD_TPM_MODE:
290 /* The Cr50 TPM_MODE command supports an optional parameter.
291 * When the parameter is present the Cr50 will attempt to change
292 * the TPM state (enable or disable) and returns the new state
293 * in the response. When the parameter is absent, the Cr50
294 * returns the current TPM state.
295 *
296 * coreboot currently only uses the TPM get capability and does
297 * not set a new TPM state with the Cr50.
298 */
299 rc |= obuf_write_be16(ob, *sub_command);
300 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600301 default:
302 /* Unsupported subcommand. */
303 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
304 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500305 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600306 break;
307 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500308 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600309}
310
Aaron Durbinee049fa2017-03-25 00:38:45 -0500311int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700312{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500313 struct obuf ob_hdr;
314 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
315 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700316
Victor Prupisf7060202016-08-19 10:45:04 -0700317 car_set_var(tpm_tag, TPM_ST_NO_SESSIONS);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700318
Aaron Durbinee049fa2017-03-25 00:38:45 -0500319 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
320 return -1;
321
322 /* Write TPM command header with placeholder field values. */
323 rc |= obuf_write_be16(ob, 0);
324 rc |= obuf_write_be32(ob, 0);
325 rc |= obuf_write_be32(ob, command);
326
327 if (rc != 0)
328 return rc;
329
Vadim Bendebury627afc22016-06-19 12:13:18 -0700330 switch (command) {
331 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500332 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700333 break;
334
Joel Kitching2e690ee2018-11-15 16:48:53 +0800335 case TPM2_Shutdown:
336 rc |= marshal_shutdown(ob, tpm_command_body);
337 break;
338
Vadim Bendebury627afc22016-06-19 12:13:18 -0700339 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500340 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700341 break;
342
343 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500344 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700345 break;
346
347 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500348 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700349 break;
350
351 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500352 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700353 break;
354
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700355 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500356 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700357 break;
358
Vadim Bendebury627afc22016-06-19 12:13:18 -0700359 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500360 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700361 break;
362
Aaron Durbinf56c7782017-01-10 17:44:42 -0600363 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500364 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600365 break;
366
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700367 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500368 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700369 break;
370
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700371 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500372 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700373 break;
374
Aaron Durbineeb77372017-03-08 11:23:11 -0600375 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500376 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600377 break;
378
Vadim Bendebury627afc22016-06-19 12:13:18 -0700379 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700380 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
381 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500382 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700383 }
384
Aaron Durbinee049fa2017-03-25 00:38:45 -0500385 if (rc != 0)
386 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700387
Aaron Durbinee049fa2017-03-25 00:38:45 -0500388 /* Fix up the command header with known values. */
389 rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag));
390 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700391
Aaron Durbinee049fa2017-03-25 00:38:45 -0500392 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700393}
394
Aaron Durbinee049fa2017-03-25 00:38:45 -0500395static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700396 struct get_cap_response *gcr)
397{
398 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500399 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700400
Aaron Durbinee049fa2017-03-25 00:38:45 -0500401 rc |= ibuf_read_be8(ib, &gcr->more_data);
402 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700403
Aaron Durbinee049fa2017-03-25 00:38:45 -0500404 if (rc != 0)
405 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700406
407 switch (gcr->cd.capability) {
408 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500409 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
410 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700411 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
412 (gcr->cd.data.tpmProperties.tpmProperty)) {
413 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
414 __FILE__, __func__, __LINE__,
415 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500416 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700417 }
418 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
419 TPMS_TAGGED_PROPERTY *pp;
420
421 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500422 rc |= unmarshal_TPM_PT(ib, &pp->property);
423 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700424 }
425 break;
Frans Hendriks589eff72019-06-26 10:43:40 +0200426 case TPM_CAP_PCRS:
427 if (ibuf_read_be32(ib, &gcr->cd.data.assignedPCR.count))
428 return -1;
429 if (gcr->cd.data.assignedPCR.count >
430 ARRAY_SIZE(gcr->cd.data.assignedPCR.pcrSelections)) {
431 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
432 __FILE__, __func__, __LINE__,
433 gcr->cd.data.assignedPCR.count);
434 return -1;
435 }
436 for (i = 0; i < gcr->cd.data.assignedPCR.count; i++) {
437 TPMS_PCR_SELECTION *pp =
438 &gcr->cd.data.assignedPCR.pcrSelections[i];
439 rc |= ibuf_read(ib, pp, sizeof(TPMS_PCR_SELECTION));
440 }
441 break;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700442 default:
443 printk(BIOS_ERR,
444 "%s:%d - unable to unmarshal capability response",
445 __func__, __LINE__);
446 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500447 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700448 break;
449 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500450
451 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700452}
453
Aaron Durbinee049fa2017-03-25 00:38:45 -0500454static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700455 TPM2B_MAX_NV_BUFFER *nv_buffer)
456{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500457 if (ibuf_read_be16(ib, &nv_buffer->t.size))
458 return -1;
459
460 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
461
462 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700463 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500464 "size mismatch: expected %d, remaining %zd\n",
465 __func__, __LINE__, nv_buffer->t.size,
466 ibuf_remaining(ib));
467 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700468 }
469
Aaron Durbinee049fa2017-03-25 00:38:45 -0500470 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700471}
472
Aaron Durbinee049fa2017-03-25 00:38:45 -0500473static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700474{
475 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500476 if (ibuf_read_be32(ib, &nvr->params_size))
477 return -1;
478
479 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
480 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700481
482 if (nvr->params_size !=
483 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
484 printk(BIOS_ERR,
485 "%s:%d - parameter/buffer %d/%d size mismatch",
486 __func__, __LINE__, nvr->params_size,
487 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500488 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700489 }
490
Vadim Bendebury627afc22016-06-19 12:13:18 -0700491 /*
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100492 * Let's ignore the authorization section. It should be 5 bytes total,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700493 * just confirm that this is the case and report any discrepancy.
494 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500495 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700496 printk(BIOS_ERR,
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100497 "%s:%d - unexpected authorization section size %zd\n",
Aaron Durbinee049fa2017-03-25 00:38:45 -0500498 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700499
Aaron Durbinee049fa2017-03-25 00:38:45 -0500500 ibuf_oob_drain(ib, ibuf_remaining(ib));
501
502 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700503}
504
Aaron Durbinee049fa2017-03-25 00:38:45 -0500505static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700506 struct vendor_command_response *vcr)
507{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500508 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
509 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700510
511 switch (vcr->vc_subcommand) {
Keith Shorte0f34002019-02-05 16:15:10 -0700512 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
513 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700514 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
515 break;
516 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500517 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Keith Shorte371d422019-01-11 07:52:32 -0700518 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
519 return ibuf_read_be8(ib, &vcr->recovery_button_state);
Keith Shorte0f34002019-02-05 16:15:10 -0700520 case TPM2_CR50_SUB_CMD_TPM_MODE:
521 return ibuf_read_be8(ib, &vcr->tpm_mode);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700522 default:
523 printk(BIOS_ERR,
524 "%s:%d - unsupported vendor command %#04x!\n",
525 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500526 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700527 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500528
529 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700530}
531
Aaron Durbinee049fa2017-03-25 00:38:45 -0500532struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700533{
Duncan Laurie4a560762016-09-01 16:09:43 -0700534 static struct tpm2_response tpm2_static_resp CAR_GLOBAL;
535 struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500536 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700537
Aaron Durbinee049fa2017-03-25 00:38:45 -0500538 rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag);
539 rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size);
540 rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code);
541
542 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700543 return NULL;
544
Aaron Durbinee049fa2017-03-25 00:38:45 -0500545 if (ibuf_remaining(ib) == 0) {
546 if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700547 printk(BIOS_ERR,
548 "%s: size mismatch in response to command %#x\n",
549 __func__, command);
Duncan Laurie4a560762016-09-01 16:09:43 -0700550 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700551 }
552
553 switch (command) {
554 case TPM2_Startup:
Joel Kitching2e690ee2018-11-15 16:48:53 +0800555 case TPM2_Shutdown:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700556 break;
557
558 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500559 rc |= unmarshal_get_capability(ib, &tpm2_resp->gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700560 break;
561
562 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500563 rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700564 break;
565
Aaron Durbinf56c7782017-01-10 17:44:42 -0600566 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700567 case TPM2_Clear:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700568 case TPM2_NV_DefineSpace:
569 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700570 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700571 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700572 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500573 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700574 break;
575
Aaron Durbineeb77372017-03-08 11:23:11 -0600576 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500577 rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600578 break;
579
Vadim Bendebury627afc22016-06-19 12:13:18 -0700580 default:
581 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500582 size_t i;
583 size_t sz_left;
584 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700585
586 printk(BIOS_INFO, "%s:%d:"
587 "Request to unmarshal unexpected command %#x,"
588 " code %#x",
589 __func__, __LINE__, command,
Duncan Laurie4a560762016-09-01 16:09:43 -0700590 tpm2_resp->hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700591
Aaron Durbinee049fa2017-03-25 00:38:45 -0500592 sz_left = ibuf_remaining(ib);
593 data = ibuf_oob_drain(ib, sz_left);
594
595 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700596 if (!(i % 16))
597 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500598 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700599 }
600 }
601 printk(BIOS_INFO, "\n");
602 return NULL;
603 }
604
Aaron Durbinee049fa2017-03-25 00:38:45 -0500605 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700606 printk(BIOS_INFO,
607 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500608 " failed to parse (%zd)\n",
Duncan Laurie4a560762016-09-01 16:09:43 -0700609 __func__, __LINE__, tpm2_resp->hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500610 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700611 return NULL;
612 }
Richard Spiegel248c60a2018-08-07 09:24:14 -0700613 if (rc)
614 printk(BIOS_WARNING, "Warning: %s had one or more failures.\n",
615 __func__);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700616
617 /* The entire message have been parsed. */
Duncan Laurie4a560762016-09-01 16:09:43 -0700618 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700619}