blob: 21da73a885a030e838dca510a9bbb8e647e864e3 [file] [log] [blame]
Vadim Bendebury627afc22016-06-19 12:13:18 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Victor Prupisf7060202016-08-19 10:45:04 -07007#include <arch/early_variables.h>
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>
Vadim Bendebury627afc22016-06-19 12:13:18 -070015
Victor Prupisf7060202016-08-19 10:45:04 -070016static uint16_t tpm_tag CAR_GLOBAL; /* Depends on the command type. */
Vadim Bendebury627afc22016-06-19 12:13:18 -070017
Aaron Durbinee049fa2017-03-25 00:38:45 -050018#define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b)
19#define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b)
20#define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b)
21#define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b)
22
23#define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b)
24#define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b)
25
26static int marshal_startup(struct obuf *ob, struct tpm2_startup *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070027{
Aaron Durbinee049fa2017-03-25 00:38:45 -050028 return obuf_write_be16(ob, cmd_body->startup_type);
Vadim Bendebury627afc22016-06-19 12:13:18 -070029}
30
Joel Kitching2e690ee2018-11-15 16:48:53 +080031static int marshal_shutdown(struct obuf *ob, struct tpm2_shutdown *cmd_body)
32{
33 return obuf_write_be16(ob, cmd_body->shutdown_type);
34}
35
Aaron Durbinee049fa2017-03-25 00:38:45 -050036static int marshal_get_capability(struct obuf *ob,
37 struct tpm2_get_capability *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070038{
Aaron Durbinee049fa2017-03-25 00:38:45 -050039 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070040
Aaron Durbinee049fa2017-03-25 00:38:45 -050041 rc |= obuf_write_be32(ob, cmd_body->capability);
42 rc |= obuf_write_be32(ob, cmd_body->property);
43 rc |= obuf_write_be32(ob, cmd_body->propertyCount);
Vadim Bendeburybc927102016-07-07 10:52:46 -070044
Aaron Durbinee049fa2017-03-25 00:38:45 -050045 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070046}
47
Aaron Durbinee049fa2017-03-25 00:38:45 -050048static int marshal_TPM2B(struct obuf *ob, TPM2B *data)
Vadim Bendebury627afc22016-06-19 12:13:18 -070049{
Aaron Durbinee049fa2017-03-25 00:38:45 -050050 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070051
Aaron Durbinee049fa2017-03-25 00:38:45 -050052 rc |= obuf_write_be16(ob, data->size);
53 rc |= obuf_write(ob, data->buffer, data->size);
Vadim Bendeburybc927102016-07-07 10:52:46 -070054
Aaron Durbinee049fa2017-03-25 00:38:45 -050055 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070056}
57
Aaron Durbinee049fa2017-03-25 00:38:45 -050058static int marshal_TPMA_NV(struct obuf *ob, TPMA_NV *nv)
Vadim Bendebury627afc22016-06-19 12:13:18 -070059{
Aaron Durbinee049fa2017-03-25 00:38:45 -050060 uint32_t v;
Vadim Bendebury627afc22016-06-19 12:13:18 -070061
Aaron Durbinee049fa2017-03-25 00:38:45 -050062 memcpy(&v, nv, sizeof(v));
63 return obuf_write_be32(ob, v);
Vadim Bendebury627afc22016-06-19 12:13:18 -070064}
65
Aaron Durbinee049fa2017-03-25 00:38:45 -050066static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, TPMS_NV_PUBLIC *nvpub)
Vadim Bendebury627afc22016-06-19 12:13:18 -070067{
Aaron Durbinee049fa2017-03-25 00:38:45 -050068 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070069
Aaron Durbinee049fa2017-03-25 00:38:45 -050070 rc |= marshal_TPM_HANDLE(ob, nvpub->nvIndex);
71 rc |= marshal_TPMI_ALG_HASH(ob, nvpub->nameAlg);
72 rc |= marshal_TPMA_NV(ob, &nvpub->attributes);
73 rc |= marshal_TPM2B(ob, &nvpub->authPolicy.b);
74 rc |= obuf_write_be16(ob, nvpub->dataSize);
Vadim Bendebury627afc22016-06-19 12:13:18 -070075
Aaron Durbinee049fa2017-03-25 00:38:45 -050076 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070077}
78
Aaron Durbinee049fa2017-03-25 00:38:45 -050079static int marshal_TPMT_HA(struct obuf *ob, TPMT_HA *tpmtha)
Vadim Bendebury627afc22016-06-19 12:13:18 -070080{
Aaron Durbinee049fa2017-03-25 00:38:45 -050081 int rc = 0;
82
83 rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg);
84 rc |= obuf_write(ob, tpmtha->digest.sha256,
85 sizeof(tpmtha->digest.sha256));
86
87 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070088}
89
Aaron Durbinee049fa2017-03-25 00:38:45 -050090static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
91 TPML_DIGEST_VALUES *dvalues)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070092{
93 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -050094 int rc = 0;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070095
Aaron Durbinee049fa2017-03-25 00:38:45 -050096 rc |= obuf_write_be32(ob, dvalues->count);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070097 for (i = 0; i < dvalues->count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -050098 rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
99
100 return rc;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700101}
102
Aaron Durbinee049fa2017-03-25 00:38:45 -0500103static int marshal_session_header(struct obuf *ob,
104 struct tpm2_session_header *session_header)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700105{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500106 int rc = 0;
107 struct obuf ob_sz;
108 size_t prev_written;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700109
Aaron Durbinee049fa2017-03-25 00:38:45 -0500110 /* Snapshot current location to place size of header. */
111 if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
112 return -1;
Vadim Bendeburybc927102016-07-07 10:52:46 -0700113
Aaron Durbinee049fa2017-03-25 00:38:45 -0500114 /* Write a size placeholder. */
115 rc |= obuf_write_be32(ob, 0);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700116
Aaron Durbinee049fa2017-03-25 00:38:45 -0500117 /* Keep track of session header data size by tracking num written. */
118 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700119
Aaron Durbinee049fa2017-03-25 00:38:45 -0500120 rc |= obuf_write_be32(ob, session_header->session_handle);
121 rc |= obuf_write_be16(ob, session_header->nonce_size);
122 rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
123 rc |= obuf_write_be8(ob, session_header->session_attrs);
124 rc |= obuf_write_be16(ob, session_header->auth_size);
125 rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700126
Aaron Durbinee049fa2017-03-25 00:38:45 -0500127 /* Fill back in proper size of session header. */
128 rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700129
Aaron Durbinee049fa2017-03-25 00:38:45 -0500130 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700131}
132
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700133/*
134 * Common session header can include one or two handles and an empty
135 * session_header structure.
136 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500137static int marshal_common_session_header(struct obuf *ob,
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700138 const uint32_t *handles,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500139 size_t handle_count)
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700140{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500141 size_t i;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700142 struct tpm2_session_header session_header;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500143 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700144
Victor Prupisf7060202016-08-19 10:45:04 -0700145 car_set_var(tpm_tag, TPM_ST_SESSIONS);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700146
147 for (i = 0; i < handle_count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500148 rc |= marshal_TPM_HANDLE(ob, handles[i]);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700149
150 memset(&session_header, 0, sizeof(session_header));
151 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500152 rc |= marshal_session_header(ob, &session_header);
153
154 return rc;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700155}
156
Aaron Durbinee049fa2017-03-25 00:38:45 -0500157static int marshal_nv_define_space(struct obuf *ob,
158 struct tpm2_nv_define_space_cmd *nvd_in)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700159{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700160 const uint32_t handle[] = { TPM_RH_PLATFORM };
Aaron Durbinee049fa2017-03-25 00:38:45 -0500161 struct obuf ob_sz;
162 size_t prev_written;
163 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700164
Aaron Durbinee049fa2017-03-25 00:38:45 -0500165 rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
166 rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700167
Aaron Durbinee049fa2017-03-25 00:38:45 -0500168 /* Snapshot current location to place size field. */
169 if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
170 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700171
Aaron Durbinee049fa2017-03-25 00:38:45 -0500172 /* Put placeholder for size */
173 rc |= obuf_write_be16(ob, 0);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700174
Aaron Durbinee049fa2017-03-25 00:38:45 -0500175 /* Keep track of nv define space data size by tracking num written. */
176 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700177
Aaron Durbinee049fa2017-03-25 00:38:45 -0500178 rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
179 rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700180
Aaron Durbinee049fa2017-03-25 00:38:45 -0500181 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700182}
183
Aaron Durbinee049fa2017-03-25 00:38:45 -0500184static int marshal_nv_write(struct obuf *ob,
185 struct tpm2_nv_write_cmd *command_body)
186{
187 int rc = 0;
188 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
189
190 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
191 rc |= marshal_TPM2B(ob, &command_body->data.b);
192 rc |= obuf_write_be16(ob, command_body->offset);
193
194 return rc;
195}
196
197static int marshal_nv_write_lock(struct obuf *ob,
198 struct tpm2_nv_write_lock_cmd *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700199{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700200 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700201
Aaron Durbinee049fa2017-03-25 00:38:45 -0500202 return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700203}
204
Aaron Durbinee049fa2017-03-25 00:38:45 -0500205static int marshal_pcr_extend(struct obuf *ob,
206 struct tpm2_pcr_extend_cmd *command_body)
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700207{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500208 int rc = 0;
209 uint32_t handles[] = { command_body->pcrHandle };
210
211 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
212 rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
213
214 return rc;
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700215}
216
Aaron Durbinee049fa2017-03-25 00:38:45 -0500217static int marshal_nv_read(struct obuf *ob,
218 struct tpm2_nv_read_cmd *command_body)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700219{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500220 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700221 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700222
Aaron Durbinee049fa2017-03-25 00:38:45 -0500223 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
224 rc |= obuf_write_be16(ob, command_body->size);
225 rc |= obuf_write_be16(ob, command_body->offset);
226
227 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700228}
229
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200230/* TPM2_Clear command does not require parameters. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500231static int marshal_clear(struct obuf *ob)
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700232{
233 const uint32_t handle[] = { TPM_RH_PLATFORM };
234
Aaron Durbinee049fa2017-03-25 00:38:45 -0500235 return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700236}
237
Aaron Durbinee049fa2017-03-25 00:38:45 -0500238static int marshal_selftest(struct obuf *ob,
239 struct tpm2_self_test *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700240{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500241 return obuf_write_be8(ob, command_body->yes_no);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700242}
243
Aaron Durbinee049fa2017-03-25 00:38:45 -0500244static int marshal_hierarchy_control(struct obuf *ob,
245 struct tpm2_hierarchy_control_cmd *command_body)
Aaron Durbinf56c7782017-01-10 17:44:42 -0600246{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500247 int rc = 0;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600248 struct tpm2_session_header session_header;
249
250 car_set_var(tpm_tag, TPM_ST_SESSIONS);
251
Aaron Durbinee049fa2017-03-25 00:38:45 -0500252 rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600253 memset(&session_header, 0, sizeof(session_header));
254 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500255 rc |= marshal_session_header(ob, &session_header);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600256
Aaron Durbinee049fa2017-03-25 00:38:45 -0500257 rc |= marshal_TPM_HANDLE(ob, command_body->enable);
258 rc |= obuf_write_be8(ob, command_body->state);
259
260 return rc;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600261}
262
Aaron Durbinee049fa2017-03-25 00:38:45 -0500263static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
Aaron Durbineeb77372017-03-08 11:23:11 -0600264{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500265 int rc = 0;
266 uint16_t *sub_command = command_body;
Aaron Durbineeb77372017-03-08 11:23:11 -0600267
268 switch (*sub_command) {
Keith Shorte0f34002019-02-05 16:15:10 -0700269 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
270 /* The 16-bit timeout parameter is optional for the
271 * IMMEDIATE_RESET command. However in coreboot, the timeout
272 * parameter must be specified.
273 */
274 rc |= obuf_write_be16(ob, sub_command[0]);
275 rc |= obuf_write_be16(ob, sub_command[1]);
276 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600277 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500278 rc |= obuf_write_be16(ob, *sub_command);
Aaron Durbineeb77372017-03-08 11:23:11 -0600279 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700280 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500281 rc |= obuf_write_be16(ob, sub_command[0]);
282 rc |= obuf_write_be16(ob, sub_command[1]);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700283 break;
Keith Shorte371d422019-01-11 07:52:32 -0700284 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
285 rc |= obuf_write_be16(ob, *sub_command);
286 break;
Keith Shorte0f34002019-02-05 16:15:10 -0700287 case TPM2_CR50_SUB_CMD_TPM_MODE:
288 /* The Cr50 TPM_MODE command supports an optional parameter.
289 * When the parameter is present the Cr50 will attempt to change
290 * the TPM state (enable or disable) and returns the new state
291 * in the response. When the parameter is absent, the Cr50
292 * returns the current TPM state.
293 *
294 * coreboot currently only uses the TPM get capability and does
295 * not set a new TPM state with the Cr50.
296 */
297 rc |= obuf_write_be16(ob, *sub_command);
298 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600299 default:
300 /* Unsupported subcommand. */
301 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
302 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500303 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600304 break;
305 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500306 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600307}
308
Aaron Durbinee049fa2017-03-25 00:38:45 -0500309int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700310{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500311 struct obuf ob_hdr;
312 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
313 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700314
Victor Prupisf7060202016-08-19 10:45:04 -0700315 car_set_var(tpm_tag, TPM_ST_NO_SESSIONS);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700316
Aaron Durbinee049fa2017-03-25 00:38:45 -0500317 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
318 return -1;
319
320 /* Write TPM command header with placeholder field values. */
321 rc |= obuf_write_be16(ob, 0);
322 rc |= obuf_write_be32(ob, 0);
323 rc |= obuf_write_be32(ob, command);
324
325 if (rc != 0)
326 return rc;
327
Vadim Bendebury627afc22016-06-19 12:13:18 -0700328 switch (command) {
329 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500330 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700331 break;
332
Joel Kitching2e690ee2018-11-15 16:48:53 +0800333 case TPM2_Shutdown:
334 rc |= marshal_shutdown(ob, tpm_command_body);
335 break;
336
Vadim Bendebury627afc22016-06-19 12:13:18 -0700337 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500338 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700339 break;
340
341 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500342 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700343 break;
344
345 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500346 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700347 break;
348
349 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500350 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700351 break;
352
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700353 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500354 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700355 break;
356
Vadim Bendebury627afc22016-06-19 12:13:18 -0700357 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500358 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700359 break;
360
Aaron Durbinf56c7782017-01-10 17:44:42 -0600361 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500362 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600363 break;
364
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700365 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500366 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700367 break;
368
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700369 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500370 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700371 break;
372
Aaron Durbineeb77372017-03-08 11:23:11 -0600373 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500374 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600375 break;
376
Vadim Bendebury627afc22016-06-19 12:13:18 -0700377 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700378 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
379 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500380 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700381 }
382
Aaron Durbinee049fa2017-03-25 00:38:45 -0500383 if (rc != 0)
384 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700385
Aaron Durbinee049fa2017-03-25 00:38:45 -0500386 /* Fix up the command header with known values. */
387 rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag));
388 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700389
Aaron Durbinee049fa2017-03-25 00:38:45 -0500390 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700391}
392
Aaron Durbinee049fa2017-03-25 00:38:45 -0500393static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700394 struct get_cap_response *gcr)
395{
396 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500397 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700398
Aaron Durbinee049fa2017-03-25 00:38:45 -0500399 rc |= ibuf_read_be8(ib, &gcr->more_data);
400 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700401
Aaron Durbinee049fa2017-03-25 00:38:45 -0500402 if (rc != 0)
403 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700404
405 switch (gcr->cd.capability) {
406 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500407 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
408 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700409 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
410 (gcr->cd.data.tpmProperties.tpmProperty)) {
411 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
412 __FILE__, __func__, __LINE__,
413 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500414 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700415 }
416 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
417 TPMS_TAGGED_PROPERTY *pp;
418
419 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500420 rc |= unmarshal_TPM_PT(ib, &pp->property);
421 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700422 }
423 break;
424 default:
425 printk(BIOS_ERR,
426 "%s:%d - unable to unmarshal capability response",
427 __func__, __LINE__);
428 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500429 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700430 break;
431 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500432
433 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700434}
435
Aaron Durbinee049fa2017-03-25 00:38:45 -0500436static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700437 TPM2B_MAX_NV_BUFFER *nv_buffer)
438{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500439 if (ibuf_read_be16(ib, &nv_buffer->t.size))
440 return -1;
441
442 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
443
444 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700445 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500446 "size mismatch: expected %d, remaining %zd\n",
447 __func__, __LINE__, nv_buffer->t.size,
448 ibuf_remaining(ib));
449 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700450 }
451
Aaron Durbinee049fa2017-03-25 00:38:45 -0500452 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700453}
454
Aaron Durbinee049fa2017-03-25 00:38:45 -0500455static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700456{
457 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500458 if (ibuf_read_be32(ib, &nvr->params_size))
459 return -1;
460
461 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
462 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700463
464 if (nvr->params_size !=
465 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
466 printk(BIOS_ERR,
467 "%s:%d - parameter/buffer %d/%d size mismatch",
468 __func__, __LINE__, nvr->params_size,
469 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500470 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700471 }
472
Vadim Bendebury627afc22016-06-19 12:13:18 -0700473 /*
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100474 * Let's ignore the authorization section. It should be 5 bytes total,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700475 * just confirm that this is the case and report any discrepancy.
476 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500477 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700478 printk(BIOS_ERR,
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100479 "%s:%d - unexpected authorization section size %zd\n",
Aaron Durbinee049fa2017-03-25 00:38:45 -0500480 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700481
Aaron Durbinee049fa2017-03-25 00:38:45 -0500482 ibuf_oob_drain(ib, ibuf_remaining(ib));
483
484 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700485}
486
Aaron Durbinee049fa2017-03-25 00:38:45 -0500487static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700488 struct vendor_command_response *vcr)
489{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500490 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
491 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700492
493 switch (vcr->vc_subcommand) {
Keith Shorte0f34002019-02-05 16:15:10 -0700494 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
495 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700496 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
497 break;
498 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500499 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Keith Shorte371d422019-01-11 07:52:32 -0700500 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
501 return ibuf_read_be8(ib, &vcr->recovery_button_state);
Keith Shorte0f34002019-02-05 16:15:10 -0700502 case TPM2_CR50_SUB_CMD_TPM_MODE:
503 return ibuf_read_be8(ib, &vcr->tpm_mode);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700504 default:
505 printk(BIOS_ERR,
506 "%s:%d - unsupported vendor command %#04x!\n",
507 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500508 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700509 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500510
511 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700512}
513
Aaron Durbinee049fa2017-03-25 00:38:45 -0500514struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700515{
Duncan Laurie4a560762016-09-01 16:09:43 -0700516 static struct tpm2_response tpm2_static_resp CAR_GLOBAL;
517 struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500518 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700519
Aaron Durbinee049fa2017-03-25 00:38:45 -0500520 rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag);
521 rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size);
522 rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code);
523
524 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700525 return NULL;
526
Aaron Durbinee049fa2017-03-25 00:38:45 -0500527 if (ibuf_remaining(ib) == 0) {
528 if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700529 printk(BIOS_ERR,
530 "%s: size mismatch in response to command %#x\n",
531 __func__, command);
Duncan Laurie4a560762016-09-01 16:09:43 -0700532 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700533 }
534
535 switch (command) {
536 case TPM2_Startup:
Joel Kitching2e690ee2018-11-15 16:48:53 +0800537 case TPM2_Shutdown:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700538 break;
539
540 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500541 rc |= unmarshal_get_capability(ib, &tpm2_resp->gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700542 break;
543
544 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500545 rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700546 break;
547
Aaron Durbinf56c7782017-01-10 17:44:42 -0600548 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700549 case TPM2_Clear:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700550 case TPM2_NV_DefineSpace:
551 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700552 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700553 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700554 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500555 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700556 break;
557
Aaron Durbineeb77372017-03-08 11:23:11 -0600558 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500559 rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600560 break;
561
Vadim Bendebury627afc22016-06-19 12:13:18 -0700562 default:
563 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500564 size_t i;
565 size_t sz_left;
566 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700567
568 printk(BIOS_INFO, "%s:%d:"
569 "Request to unmarshal unexpected command %#x,"
570 " code %#x",
571 __func__, __LINE__, command,
Duncan Laurie4a560762016-09-01 16:09:43 -0700572 tpm2_resp->hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700573
Aaron Durbinee049fa2017-03-25 00:38:45 -0500574 sz_left = ibuf_remaining(ib);
575 data = ibuf_oob_drain(ib, sz_left);
576
577 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700578 if (!(i % 16))
579 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500580 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700581 }
582 }
583 printk(BIOS_INFO, "\n");
584 return NULL;
585 }
586
Aaron Durbinee049fa2017-03-25 00:38:45 -0500587 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700588 printk(BIOS_INFO,
589 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500590 " failed to parse (%zd)\n",
Duncan Laurie4a560762016-09-01 16:09:43 -0700591 __func__, __LINE__, tpm2_resp->hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500592 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700593 return NULL;
594 }
Richard Spiegel248c60a2018-08-07 09:24:14 -0700595 if (rc)
596 printk(BIOS_WARNING, "Warning: %s had one or more failures.\n",
597 __func__);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700598
599 /* The entire message have been parsed. */
Duncan Laurie4a560762016-09-01 16:09:43 -0700600 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700601}