blob: 1bf211a8985bba681a22cd1f9864908842064f06 [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);
Frans Hendriksaa771cb2019-09-04 11:10:27 +020086 switch (tpmtha->hashAlg) {
87 case TPM_ALG_SHA1:
88 rc |= obuf_write(ob, tpmtha->digest.sha1,
Frans Hendriks7e220ca2019-06-28 10:18:22 +020089 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
Frans Hendriksaa771cb2019-09-04 11:10:27 +020090 break;
91 case TPM_ALG_SHA256:
92 rc |= obuf_write(ob, tpmtha->digest.sha256,
93 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
94 break;
95 case TPM_ALG_SM3_256:
96 rc |= obuf_write(ob, tpmtha->digest.sm3_256,
97 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
98 break;
99 case TPM_ALG_SHA384:
100 rc |= obuf_write(ob, tpmtha->digest.sha384,
101 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
102 break;
103 case TPM_ALG_SHA512:
104 rc |= obuf_write(ob, tpmtha->digest.sha512,
105 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
106 break;
107 default:
108 rc = -1;
109 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500110 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700111}
112
Aaron Durbinee049fa2017-03-25 00:38:45 -0500113static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
114 TPML_DIGEST_VALUES *dvalues)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700115{
116 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500117 int rc = 0;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700118
Aaron Durbinee049fa2017-03-25 00:38:45 -0500119 rc |= obuf_write_be32(ob, dvalues->count);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700120 for (i = 0; i < dvalues->count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500121 rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
122
123 return rc;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700124}
125
Aaron Durbinee049fa2017-03-25 00:38:45 -0500126static int marshal_session_header(struct obuf *ob,
127 struct tpm2_session_header *session_header)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700128{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500129 int rc = 0;
130 struct obuf ob_sz;
131 size_t prev_written;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700132
Aaron Durbinee049fa2017-03-25 00:38:45 -0500133 /* Snapshot current location to place size of header. */
134 if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
135 return -1;
Vadim Bendeburybc927102016-07-07 10:52:46 -0700136
Aaron Durbinee049fa2017-03-25 00:38:45 -0500137 /* Write a size placeholder. */
138 rc |= obuf_write_be32(ob, 0);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700139
Aaron Durbinee049fa2017-03-25 00:38:45 -0500140 /* Keep track of session header data size by tracking num written. */
141 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700142
Aaron Durbinee049fa2017-03-25 00:38:45 -0500143 rc |= obuf_write_be32(ob, session_header->session_handle);
144 rc |= obuf_write_be16(ob, session_header->nonce_size);
145 rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
146 rc |= obuf_write_be8(ob, session_header->session_attrs);
147 rc |= obuf_write_be16(ob, session_header->auth_size);
148 rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700149
Aaron Durbinee049fa2017-03-25 00:38:45 -0500150 /* Fill back in proper size of session header. */
151 rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700152
Aaron Durbinee049fa2017-03-25 00:38:45 -0500153 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700154}
155
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700156/*
157 * Common session header can include one or two handles and an empty
158 * session_header structure.
159 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500160static int marshal_common_session_header(struct obuf *ob,
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700161 const uint32_t *handles,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500162 size_t handle_count)
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700163{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500164 size_t i;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700165 struct tpm2_session_header session_header;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500166 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700167
Victor Prupisf7060202016-08-19 10:45:04 -0700168 car_set_var(tpm_tag, TPM_ST_SESSIONS);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700169
170 for (i = 0; i < handle_count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500171 rc |= marshal_TPM_HANDLE(ob, handles[i]);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700172
173 memset(&session_header, 0, sizeof(session_header));
174 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500175 rc |= marshal_session_header(ob, &session_header);
176
177 return rc;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700178}
179
Aaron Durbinee049fa2017-03-25 00:38:45 -0500180static int marshal_nv_define_space(struct obuf *ob,
181 struct tpm2_nv_define_space_cmd *nvd_in)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700182{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700183 const uint32_t handle[] = { TPM_RH_PLATFORM };
Aaron Durbinee049fa2017-03-25 00:38:45 -0500184 struct obuf ob_sz;
185 size_t prev_written;
186 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700187
Aaron Durbinee049fa2017-03-25 00:38:45 -0500188 rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
189 rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700190
Aaron Durbinee049fa2017-03-25 00:38:45 -0500191 /* Snapshot current location to place size field. */
192 if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
193 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700194
Aaron Durbinee049fa2017-03-25 00:38:45 -0500195 /* Put placeholder for size */
196 rc |= obuf_write_be16(ob, 0);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700197
Aaron Durbinee049fa2017-03-25 00:38:45 -0500198 /* Keep track of nv define space data size by tracking num written. */
199 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700200
Aaron Durbinee049fa2017-03-25 00:38:45 -0500201 rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
202 rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700203
Aaron Durbinee049fa2017-03-25 00:38:45 -0500204 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700205}
206
Aaron Durbinee049fa2017-03-25 00:38:45 -0500207static int marshal_nv_write(struct obuf *ob,
208 struct tpm2_nv_write_cmd *command_body)
209{
210 int rc = 0;
211 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
212
213 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
214 rc |= marshal_TPM2B(ob, &command_body->data.b);
215 rc |= obuf_write_be16(ob, command_body->offset);
216
217 return rc;
218}
219
220static int marshal_nv_write_lock(struct obuf *ob,
221 struct tpm2_nv_write_lock_cmd *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700222{
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 return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700226}
227
Aaron Durbinee049fa2017-03-25 00:38:45 -0500228static int marshal_pcr_extend(struct obuf *ob,
229 struct tpm2_pcr_extend_cmd *command_body)
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700230{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500231 int rc = 0;
232 uint32_t handles[] = { command_body->pcrHandle };
233
234 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
235 rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
236
237 return rc;
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700238}
239
Aaron Durbinee049fa2017-03-25 00:38:45 -0500240static int marshal_nv_read(struct obuf *ob,
241 struct tpm2_nv_read_cmd *command_body)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700242{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500243 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700244 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700245
Aaron Durbinee049fa2017-03-25 00:38:45 -0500246 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
247 rc |= obuf_write_be16(ob, command_body->size);
248 rc |= obuf_write_be16(ob, command_body->offset);
249
250 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700251}
252
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200253/* TPM2_Clear command does not require parameters. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500254static int marshal_clear(struct obuf *ob)
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700255{
256 const uint32_t handle[] = { TPM_RH_PLATFORM };
257
Aaron Durbinee049fa2017-03-25 00:38:45 -0500258 return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700259}
260
Aaron Durbinee049fa2017-03-25 00:38:45 -0500261static int marshal_selftest(struct obuf *ob,
262 struct tpm2_self_test *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700263{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500264 return obuf_write_be8(ob, command_body->yes_no);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700265}
266
Aaron Durbinee049fa2017-03-25 00:38:45 -0500267static int marshal_hierarchy_control(struct obuf *ob,
268 struct tpm2_hierarchy_control_cmd *command_body)
Aaron Durbinf56c7782017-01-10 17:44:42 -0600269{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500270 int rc = 0;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600271 struct tpm2_session_header session_header;
272
273 car_set_var(tpm_tag, TPM_ST_SESSIONS);
274
Aaron Durbinee049fa2017-03-25 00:38:45 -0500275 rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600276 memset(&session_header, 0, sizeof(session_header));
277 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500278 rc |= marshal_session_header(ob, &session_header);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600279
Aaron Durbinee049fa2017-03-25 00:38:45 -0500280 rc |= marshal_TPM_HANDLE(ob, command_body->enable);
281 rc |= obuf_write_be8(ob, command_body->state);
282
283 return rc;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600284}
285
Aaron Durbinee049fa2017-03-25 00:38:45 -0500286static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
Aaron Durbineeb77372017-03-08 11:23:11 -0600287{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500288 int rc = 0;
289 uint16_t *sub_command = command_body;
Aaron Durbineeb77372017-03-08 11:23:11 -0600290
291 switch (*sub_command) {
Keith Shorte0f34002019-02-05 16:15:10 -0700292 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
293 /* The 16-bit timeout parameter is optional for the
294 * IMMEDIATE_RESET command. However in coreboot, the timeout
295 * parameter must be specified.
296 */
297 rc |= obuf_write_be16(ob, sub_command[0]);
298 rc |= obuf_write_be16(ob, sub_command[1]);
299 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600300 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500301 rc |= obuf_write_be16(ob, *sub_command);
Aaron Durbineeb77372017-03-08 11:23:11 -0600302 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700303 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500304 rc |= obuf_write_be16(ob, sub_command[0]);
305 rc |= obuf_write_be16(ob, sub_command[1]);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700306 break;
Keith Shorte371d422019-01-11 07:52:32 -0700307 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
308 rc |= obuf_write_be16(ob, *sub_command);
309 break;
Keith Shorte0f34002019-02-05 16:15:10 -0700310 case TPM2_CR50_SUB_CMD_TPM_MODE:
311 /* The Cr50 TPM_MODE command supports an optional parameter.
312 * When the parameter is present the Cr50 will attempt to change
313 * the TPM state (enable or disable) and returns the new state
314 * in the response. When the parameter is absent, the Cr50
315 * returns the current TPM state.
316 *
317 * coreboot currently only uses the TPM get capability and does
318 * not set a new TPM state with the Cr50.
319 */
320 rc |= obuf_write_be16(ob, *sub_command);
321 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600322 default:
323 /* Unsupported subcommand. */
324 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
325 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500326 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600327 break;
328 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500329 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600330}
331
Aaron Durbinee049fa2017-03-25 00:38:45 -0500332int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700333{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500334 struct obuf ob_hdr;
335 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
336 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700337
Victor Prupisf7060202016-08-19 10:45:04 -0700338 car_set_var(tpm_tag, TPM_ST_NO_SESSIONS);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700339
Aaron Durbinee049fa2017-03-25 00:38:45 -0500340 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
341 return -1;
342
343 /* Write TPM command header with placeholder field values. */
344 rc |= obuf_write_be16(ob, 0);
345 rc |= obuf_write_be32(ob, 0);
346 rc |= obuf_write_be32(ob, command);
347
348 if (rc != 0)
349 return rc;
350
Vadim Bendebury627afc22016-06-19 12:13:18 -0700351 switch (command) {
352 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500353 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700354 break;
355
Joel Kitching2e690ee2018-11-15 16:48:53 +0800356 case TPM2_Shutdown:
357 rc |= marshal_shutdown(ob, tpm_command_body);
358 break;
359
Vadim Bendebury627afc22016-06-19 12:13:18 -0700360 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500361 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700362 break;
363
364 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500365 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700366 break;
367
368 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500369 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700370 break;
371
372 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500373 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700374 break;
375
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700376 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500377 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700378 break;
379
Vadim Bendebury627afc22016-06-19 12:13:18 -0700380 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500381 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700382 break;
383
Aaron Durbinf56c7782017-01-10 17:44:42 -0600384 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500385 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600386 break;
387
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700388 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500389 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700390 break;
391
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700392 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500393 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700394 break;
395
Aaron Durbineeb77372017-03-08 11:23:11 -0600396 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500397 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600398 break;
399
Vadim Bendebury627afc22016-06-19 12:13:18 -0700400 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700401 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
402 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500403 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700404 }
405
Aaron Durbinee049fa2017-03-25 00:38:45 -0500406 if (rc != 0)
407 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700408
Aaron Durbinee049fa2017-03-25 00:38:45 -0500409 /* Fix up the command header with known values. */
410 rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag));
411 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700412
Aaron Durbinee049fa2017-03-25 00:38:45 -0500413 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700414}
415
Aaron Durbinee049fa2017-03-25 00:38:45 -0500416static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700417 struct get_cap_response *gcr)
418{
419 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500420 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700421
Aaron Durbinee049fa2017-03-25 00:38:45 -0500422 rc |= ibuf_read_be8(ib, &gcr->more_data);
423 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700424
Aaron Durbinee049fa2017-03-25 00:38:45 -0500425 if (rc != 0)
426 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700427
428 switch (gcr->cd.capability) {
429 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500430 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
431 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700432 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
433 (gcr->cd.data.tpmProperties.tpmProperty)) {
434 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
435 __FILE__, __func__, __LINE__,
436 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500437 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700438 }
439 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
440 TPMS_TAGGED_PROPERTY *pp;
441
442 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500443 rc |= unmarshal_TPM_PT(ib, &pp->property);
444 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700445 }
446 break;
Frans Hendriks589eff72019-06-26 10:43:40 +0200447 case TPM_CAP_PCRS:
448 if (ibuf_read_be32(ib, &gcr->cd.data.assignedPCR.count))
449 return -1;
450 if (gcr->cd.data.assignedPCR.count >
451 ARRAY_SIZE(gcr->cd.data.assignedPCR.pcrSelections)) {
452 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
453 __FILE__, __func__, __LINE__,
454 gcr->cd.data.assignedPCR.count);
455 return -1;
456 }
457 for (i = 0; i < gcr->cd.data.assignedPCR.count; i++) {
458 TPMS_PCR_SELECTION *pp =
459 &gcr->cd.data.assignedPCR.pcrSelections[i];
460 rc |= ibuf_read(ib, pp, sizeof(TPMS_PCR_SELECTION));
461 }
462 break;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700463 default:
464 printk(BIOS_ERR,
465 "%s:%d - unable to unmarshal capability response",
466 __func__, __LINE__);
467 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500468 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700469 break;
470 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500471
472 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700473}
474
Aaron Durbinee049fa2017-03-25 00:38:45 -0500475static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700476 TPM2B_MAX_NV_BUFFER *nv_buffer)
477{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500478 if (ibuf_read_be16(ib, &nv_buffer->t.size))
479 return -1;
480
481 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
482
483 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700484 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500485 "size mismatch: expected %d, remaining %zd\n",
486 __func__, __LINE__, nv_buffer->t.size,
487 ibuf_remaining(ib));
488 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700489 }
490
Aaron Durbinee049fa2017-03-25 00:38:45 -0500491 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700492}
493
Aaron Durbinee049fa2017-03-25 00:38:45 -0500494static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700495{
496 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500497 if (ibuf_read_be32(ib, &nvr->params_size))
498 return -1;
499
500 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
501 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700502
503 if (nvr->params_size !=
504 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
505 printk(BIOS_ERR,
506 "%s:%d - parameter/buffer %d/%d size mismatch",
507 __func__, __LINE__, nvr->params_size,
508 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500509 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700510 }
511
Vadim Bendebury627afc22016-06-19 12:13:18 -0700512 /*
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100513 * Let's ignore the authorization section. It should be 5 bytes total,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700514 * just confirm that this is the case and report any discrepancy.
515 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500516 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700517 printk(BIOS_ERR,
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100518 "%s:%d - unexpected authorization section size %zd\n",
Aaron Durbinee049fa2017-03-25 00:38:45 -0500519 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700520
Aaron Durbinee049fa2017-03-25 00:38:45 -0500521 ibuf_oob_drain(ib, ibuf_remaining(ib));
522
523 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700524}
525
Aaron Durbinee049fa2017-03-25 00:38:45 -0500526static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700527 struct vendor_command_response *vcr)
528{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500529 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
530 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700531
532 switch (vcr->vc_subcommand) {
Keith Shorte0f34002019-02-05 16:15:10 -0700533 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
534 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700535 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
536 break;
537 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500538 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Keith Shorte371d422019-01-11 07:52:32 -0700539 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
540 return ibuf_read_be8(ib, &vcr->recovery_button_state);
Keith Shorte0f34002019-02-05 16:15:10 -0700541 case TPM2_CR50_SUB_CMD_TPM_MODE:
542 return ibuf_read_be8(ib, &vcr->tpm_mode);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700543 default:
544 printk(BIOS_ERR,
545 "%s:%d - unsupported vendor command %#04x!\n",
546 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500547 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700548 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500549
550 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700551}
552
Aaron Durbinee049fa2017-03-25 00:38:45 -0500553struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700554{
Duncan Laurie4a560762016-09-01 16:09:43 -0700555 static struct tpm2_response tpm2_static_resp CAR_GLOBAL;
556 struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500557 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700558
Aaron Durbinee049fa2017-03-25 00:38:45 -0500559 rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag);
560 rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size);
561 rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code);
562
563 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700564 return NULL;
565
Aaron Durbinee049fa2017-03-25 00:38:45 -0500566 if (ibuf_remaining(ib) == 0) {
567 if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700568 printk(BIOS_ERR,
569 "%s: size mismatch in response to command %#x\n",
570 __func__, command);
Duncan Laurie4a560762016-09-01 16:09:43 -0700571 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700572 }
573
574 switch (command) {
575 case TPM2_Startup:
Joel Kitching2e690ee2018-11-15 16:48:53 +0800576 case TPM2_Shutdown:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700577 break;
578
579 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500580 rc |= unmarshal_get_capability(ib, &tpm2_resp->gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700581 break;
582
583 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500584 rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700585 break;
586
Aaron Durbinf56c7782017-01-10 17:44:42 -0600587 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700588 case TPM2_Clear:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700589 case TPM2_NV_DefineSpace:
590 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700591 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700592 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700593 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500594 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700595 break;
596
Aaron Durbineeb77372017-03-08 11:23:11 -0600597 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500598 rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600599 break;
600
Vadim Bendebury627afc22016-06-19 12:13:18 -0700601 default:
602 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500603 size_t i;
604 size_t sz_left;
605 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700606
607 printk(BIOS_INFO, "%s:%d:"
608 "Request to unmarshal unexpected command %#x,"
609 " code %#x",
610 __func__, __LINE__, command,
Duncan Laurie4a560762016-09-01 16:09:43 -0700611 tpm2_resp->hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700612
Aaron Durbinee049fa2017-03-25 00:38:45 -0500613 sz_left = ibuf_remaining(ib);
614 data = ibuf_oob_drain(ib, sz_left);
615
616 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700617 if (!(i % 16))
618 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500619 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700620 }
621 }
622 printk(BIOS_INFO, "\n");
623 return NULL;
624 }
625
Aaron Durbinee049fa2017-03-25 00:38:45 -0500626 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700627 printk(BIOS_INFO,
628 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500629 " failed to parse (%zd)\n",
Duncan Laurie4a560762016-09-01 16:09:43 -0700630 __func__, __LINE__, tpm2_resp->hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500631 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700632 return NULL;
633 }
Richard Spiegel248c60a2018-08-07 09:24:14 -0700634 if (rc)
635 printk(BIOS_WARNING, "Warning: %s had one or more failures.\n",
636 __func__);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700637
638 /* The entire message have been parsed. */
Duncan Laurie4a560762016-09-01 16:09:43 -0700639 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700640}