blob: 49ac5e8979f31ff87f141e8168d64525481c1c6a [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) {
269 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500270 rc |= obuf_write_be16(ob, *sub_command);
Aaron Durbineeb77372017-03-08 11:23:11 -0600271 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700272 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500273 rc |= obuf_write_be16(ob, sub_command[0]);
274 rc |= obuf_write_be16(ob, sub_command[1]);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700275 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600276 default:
277 /* Unsupported subcommand. */
278 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
279 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500280 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600281 break;
282 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500283 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600284}
285
Aaron Durbinee049fa2017-03-25 00:38:45 -0500286int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700287{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500288 struct obuf ob_hdr;
289 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
290 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700291
Victor Prupisf7060202016-08-19 10:45:04 -0700292 car_set_var(tpm_tag, TPM_ST_NO_SESSIONS);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700293
Aaron Durbinee049fa2017-03-25 00:38:45 -0500294 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
295 return -1;
296
297 /* Write TPM command header with placeholder field values. */
298 rc |= obuf_write_be16(ob, 0);
299 rc |= obuf_write_be32(ob, 0);
300 rc |= obuf_write_be32(ob, command);
301
302 if (rc != 0)
303 return rc;
304
Vadim Bendebury627afc22016-06-19 12:13:18 -0700305 switch (command) {
306 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500307 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700308 break;
309
Joel Kitching2e690ee2018-11-15 16:48:53 +0800310 case TPM2_Shutdown:
311 rc |= marshal_shutdown(ob, tpm_command_body);
312 break;
313
Vadim Bendebury627afc22016-06-19 12:13:18 -0700314 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500315 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700316 break;
317
318 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500319 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700320 break;
321
322 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500323 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700324 break;
325
326 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500327 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700328 break;
329
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700330 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500331 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700332 break;
333
Vadim Bendebury627afc22016-06-19 12:13:18 -0700334 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500335 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700336 break;
337
Aaron Durbinf56c7782017-01-10 17:44:42 -0600338 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500339 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600340 break;
341
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700342 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500343 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700344 break;
345
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700346 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500347 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700348 break;
349
Aaron Durbineeb77372017-03-08 11:23:11 -0600350 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500351 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600352 break;
353
Vadim Bendebury627afc22016-06-19 12:13:18 -0700354 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700355 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
356 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500357 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700358 }
359
Aaron Durbinee049fa2017-03-25 00:38:45 -0500360 if (rc != 0)
361 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700362
Aaron Durbinee049fa2017-03-25 00:38:45 -0500363 /* Fix up the command header with known values. */
364 rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag));
365 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700366
Aaron Durbinee049fa2017-03-25 00:38:45 -0500367 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700368}
369
Aaron Durbinee049fa2017-03-25 00:38:45 -0500370static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700371 struct get_cap_response *gcr)
372{
373 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500374 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700375
Aaron Durbinee049fa2017-03-25 00:38:45 -0500376 rc |= ibuf_read_be8(ib, &gcr->more_data);
377 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700378
Aaron Durbinee049fa2017-03-25 00:38:45 -0500379 if (rc != 0)
380 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700381
382 switch (gcr->cd.capability) {
383 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500384 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
385 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700386 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
387 (gcr->cd.data.tpmProperties.tpmProperty)) {
388 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
389 __FILE__, __func__, __LINE__,
390 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500391 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700392 }
393 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
394 TPMS_TAGGED_PROPERTY *pp;
395
396 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500397 rc |= unmarshal_TPM_PT(ib, &pp->property);
398 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700399 }
400 break;
401 default:
402 printk(BIOS_ERR,
403 "%s:%d - unable to unmarshal capability response",
404 __func__, __LINE__);
405 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500406 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700407 break;
408 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500409
410 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700411}
412
Aaron Durbinee049fa2017-03-25 00:38:45 -0500413static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700414 TPM2B_MAX_NV_BUFFER *nv_buffer)
415{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500416 if (ibuf_read_be16(ib, &nv_buffer->t.size))
417 return -1;
418
419 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
420
421 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700422 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500423 "size mismatch: expected %d, remaining %zd\n",
424 __func__, __LINE__, nv_buffer->t.size,
425 ibuf_remaining(ib));
426 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700427 }
428
Aaron Durbinee049fa2017-03-25 00:38:45 -0500429 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700430}
431
Aaron Durbinee049fa2017-03-25 00:38:45 -0500432static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700433{
434 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500435 if (ibuf_read_be32(ib, &nvr->params_size))
436 return -1;
437
438 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
439 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700440
441 if (nvr->params_size !=
442 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
443 printk(BIOS_ERR,
444 "%s:%d - parameter/buffer %d/%d size mismatch",
445 __func__, __LINE__, nvr->params_size,
446 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500447 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700448 }
449
Vadim Bendebury627afc22016-06-19 12:13:18 -0700450 /*
451 * Let's ignore the authorisation section. It should be 5 bytes total,
452 * just confirm that this is the case and report any discrepancy.
453 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500454 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700455 printk(BIOS_ERR,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500456 "%s:%d - unexpected authorisation seciton size %zd\n",
457 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700458
Aaron Durbinee049fa2017-03-25 00:38:45 -0500459 ibuf_oob_drain(ib, ibuf_remaining(ib));
460
461 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700462}
463
Aaron Durbinee049fa2017-03-25 00:38:45 -0500464static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700465 struct vendor_command_response *vcr)
466{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500467 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
468 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700469
470 switch (vcr->vc_subcommand) {
471 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
472 break;
473 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500474 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700475 break;
476 default:
477 printk(BIOS_ERR,
478 "%s:%d - unsupported vendor command %#04x!\n",
479 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500480 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700481 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500482
483 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700484}
485
Aaron Durbinee049fa2017-03-25 00:38:45 -0500486struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700487{
Duncan Laurie4a560762016-09-01 16:09:43 -0700488 static struct tpm2_response tpm2_static_resp CAR_GLOBAL;
489 struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500490 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700491
Aaron Durbinee049fa2017-03-25 00:38:45 -0500492 rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag);
493 rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size);
494 rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code);
495
496 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700497 return NULL;
498
Aaron Durbinee049fa2017-03-25 00:38:45 -0500499 if (ibuf_remaining(ib) == 0) {
500 if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700501 printk(BIOS_ERR,
502 "%s: size mismatch in response to command %#x\n",
503 __func__, command);
Duncan Laurie4a560762016-09-01 16:09:43 -0700504 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700505 }
506
507 switch (command) {
508 case TPM2_Startup:
Joel Kitching2e690ee2018-11-15 16:48:53 +0800509 case TPM2_Shutdown:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700510 break;
511
512 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500513 rc |= unmarshal_get_capability(ib, &tpm2_resp->gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700514 break;
515
516 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500517 rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700518 break;
519
Aaron Durbinf56c7782017-01-10 17:44:42 -0600520 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700521 case TPM2_Clear:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700522 case TPM2_NV_DefineSpace:
523 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700524 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700525 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700526 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500527 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700528 break;
529
Aaron Durbineeb77372017-03-08 11:23:11 -0600530 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500531 rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600532 break;
533
Vadim Bendebury627afc22016-06-19 12:13:18 -0700534 default:
535 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500536 size_t i;
537 size_t sz_left;
538 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700539
540 printk(BIOS_INFO, "%s:%d:"
541 "Request to unmarshal unexpected command %#x,"
542 " code %#x",
543 __func__, __LINE__, command,
Duncan Laurie4a560762016-09-01 16:09:43 -0700544 tpm2_resp->hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700545
Aaron Durbinee049fa2017-03-25 00:38:45 -0500546 sz_left = ibuf_remaining(ib);
547 data = ibuf_oob_drain(ib, sz_left);
548
549 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700550 if (!(i % 16))
551 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500552 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700553 }
554 }
555 printk(BIOS_INFO, "\n");
556 return NULL;
557 }
558
Aaron Durbinee049fa2017-03-25 00:38:45 -0500559 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700560 printk(BIOS_INFO,
561 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500562 " failed to parse (%zd)\n",
Duncan Laurie4a560762016-09-01 16:09:43 -0700563 __func__, __LINE__, tpm2_resp->hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500564 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700565 return NULL;
566 }
Richard Spiegel248c60a2018-08-07 09:24:14 -0700567 if (rc)
568 printk(BIOS_WARNING, "Warning: %s had one or more failures.\n",
569 __func__);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700570
571 /* The entire message have been parsed. */
Duncan Laurie4a560762016-09-01 16:09:43 -0700572 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700573}