blob: a229dd17efdfe7265c3b58fe9ad6bae67b5c4649 [file] [log] [blame]
Vadim Bendebury627afc22016-06-19 12:13:18 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
Frans Hendriks589eff72019-06-26 10:43:40 +02003 * Copyright (c) 2018 Eltan B.V.
Vadim Bendebury627afc22016-06-19 12:13:18 -07004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Aaron Durbinee049fa2017-03-25 00:38:45 -05008#include <commonlib/iobuf.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -07009#include <console/console.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -070010#include <string.h>
11
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020012#include "tss_marshaling.h"
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010013#include <security/tpm/tss/vendor/cr50/cr50.h>
Frans Hendriks589eff72019-06-26 10:43:40 +020014#include <security/tpm/tss.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -070015
Arthur Heymans0ca944b2019-11-20 19:51:06 +010016static uint16_t tpm_tag; /* 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);
Frans Hendriksaa771cb2019-09-04 11:10:27 +020084 switch (tpmtha->hashAlg) {
85 case TPM_ALG_SHA1:
86 rc |= obuf_write(ob, tpmtha->digest.sha1,
Frans Hendriks7e220ca2019-06-28 10:18:22 +020087 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
Frans Hendriksaa771cb2019-09-04 11:10:27 +020088 break;
89 case TPM_ALG_SHA256:
90 rc |= obuf_write(ob, tpmtha->digest.sha256,
91 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
92 break;
93 case TPM_ALG_SM3_256:
94 rc |= obuf_write(ob, tpmtha->digest.sm3_256,
95 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
96 break;
97 case TPM_ALG_SHA384:
98 rc |= obuf_write(ob, tpmtha->digest.sha384,
99 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
100 break;
101 case TPM_ALG_SHA512:
102 rc |= obuf_write(ob, tpmtha->digest.sha512,
103 tlcl_get_hash_size_from_algo(tpmtha->hashAlg));
104 break;
105 default:
106 rc = -1;
107 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500108 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700109}
110
Aaron Durbinee049fa2017-03-25 00:38:45 -0500111static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
112 TPML_DIGEST_VALUES *dvalues)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700113{
114 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500115 int rc = 0;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700116
Aaron Durbinee049fa2017-03-25 00:38:45 -0500117 rc |= obuf_write_be32(ob, dvalues->count);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700118 for (i = 0; i < dvalues->count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500119 rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
120
121 return rc;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700122}
123
Aaron Durbinee049fa2017-03-25 00:38:45 -0500124static int marshal_session_header(struct obuf *ob,
125 struct tpm2_session_header *session_header)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700126{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500127 int rc = 0;
128 struct obuf ob_sz;
129 size_t prev_written;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700130
Aaron Durbinee049fa2017-03-25 00:38:45 -0500131 /* Snapshot current location to place size of header. */
132 if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
133 return -1;
Vadim Bendeburybc927102016-07-07 10:52:46 -0700134
Aaron Durbinee049fa2017-03-25 00:38:45 -0500135 /* Write a size placeholder. */
136 rc |= obuf_write_be32(ob, 0);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700137
Aaron Durbinee049fa2017-03-25 00:38:45 -0500138 /* Keep track of session header data size by tracking num written. */
139 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700140
Aaron Durbinee049fa2017-03-25 00:38:45 -0500141 rc |= obuf_write_be32(ob, session_header->session_handle);
142 rc |= obuf_write_be16(ob, session_header->nonce_size);
143 rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
144 rc |= obuf_write_be8(ob, session_header->session_attrs);
145 rc |= obuf_write_be16(ob, session_header->auth_size);
146 rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700147
Aaron Durbinee049fa2017-03-25 00:38:45 -0500148 /* Fill back in proper size of session header. */
149 rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700150
Aaron Durbinee049fa2017-03-25 00:38:45 -0500151 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700152}
153
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700154/*
155 * Common session header can include one or two handles and an empty
156 * session_header structure.
157 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500158static int marshal_common_session_header(struct obuf *ob,
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700159 const uint32_t *handles,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500160 size_t handle_count)
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700161{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500162 size_t i;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700163 struct tpm2_session_header session_header;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500164 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700165
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100166 tpm_tag = TPM_ST_SESSIONS;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700167
168 for (i = 0; i < handle_count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500169 rc |= marshal_TPM_HANDLE(ob, handles[i]);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700170
171 memset(&session_header, 0, sizeof(session_header));
172 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500173 rc |= marshal_session_header(ob, &session_header);
174
175 return rc;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700176}
177
Aaron Durbinee049fa2017-03-25 00:38:45 -0500178static int marshal_nv_define_space(struct obuf *ob,
179 struct tpm2_nv_define_space_cmd *nvd_in)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700180{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700181 const uint32_t handle[] = { TPM_RH_PLATFORM };
Aaron Durbinee049fa2017-03-25 00:38:45 -0500182 struct obuf ob_sz;
183 size_t prev_written;
184 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700185
Aaron Durbinee049fa2017-03-25 00:38:45 -0500186 rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
187 rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700188
Aaron Durbinee049fa2017-03-25 00:38:45 -0500189 /* Snapshot current location to place size field. */
190 if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
191 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700192
Aaron Durbinee049fa2017-03-25 00:38:45 -0500193 /* Put placeholder for size */
194 rc |= obuf_write_be16(ob, 0);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700195
Aaron Durbinee049fa2017-03-25 00:38:45 -0500196 /* Keep track of nv define space data size by tracking num written. */
197 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700198
Aaron Durbinee049fa2017-03-25 00:38:45 -0500199 rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
200 rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700201
Aaron Durbinee049fa2017-03-25 00:38:45 -0500202 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700203}
204
Aaron Durbinee049fa2017-03-25 00:38:45 -0500205static int marshal_nv_write(struct obuf *ob,
206 struct tpm2_nv_write_cmd *command_body)
207{
208 int rc = 0;
209 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
210
211 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
212 rc |= marshal_TPM2B(ob, &command_body->data.b);
213 rc |= obuf_write_be16(ob, command_body->offset);
214
215 return rc;
216}
217
218static int marshal_nv_write_lock(struct obuf *ob,
219 struct tpm2_nv_write_lock_cmd *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700220{
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 return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700224}
225
Aaron Durbinee049fa2017-03-25 00:38:45 -0500226static int marshal_pcr_extend(struct obuf *ob,
227 struct tpm2_pcr_extend_cmd *command_body)
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700228{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500229 int rc = 0;
230 uint32_t handles[] = { command_body->pcrHandle };
231
232 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
233 rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
234
235 return rc;
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700236}
237
Aaron Durbinee049fa2017-03-25 00:38:45 -0500238static int marshal_nv_read(struct obuf *ob,
239 struct tpm2_nv_read_cmd *command_body)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700240{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500241 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700242 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700243
Aaron Durbinee049fa2017-03-25 00:38:45 -0500244 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
245 rc |= obuf_write_be16(ob, command_body->size);
246 rc |= obuf_write_be16(ob, command_body->offset);
247
248 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700249}
250
Elyes HAOUAS3d450002018-08-09 18:55:58 +0200251/* TPM2_Clear command does not require parameters. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500252static int marshal_clear(struct obuf *ob)
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700253{
254 const uint32_t handle[] = { TPM_RH_PLATFORM };
255
Aaron Durbinee049fa2017-03-25 00:38:45 -0500256 return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700257}
258
Aaron Durbinee049fa2017-03-25 00:38:45 -0500259static int marshal_selftest(struct obuf *ob,
260 struct tpm2_self_test *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700261{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500262 return obuf_write_be8(ob, command_body->yes_no);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700263}
264
Aaron Durbinee049fa2017-03-25 00:38:45 -0500265static int marshal_hierarchy_control(struct obuf *ob,
266 struct tpm2_hierarchy_control_cmd *command_body)
Aaron Durbinf56c7782017-01-10 17:44:42 -0600267{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500268 int rc = 0;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600269 struct tpm2_session_header session_header;
270
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100271 tpm_tag = TPM_ST_SESSIONS;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600272
Aaron Durbinee049fa2017-03-25 00:38:45 -0500273 rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600274 memset(&session_header, 0, sizeof(session_header));
275 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500276 rc |= marshal_session_header(ob, &session_header);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600277
Aaron Durbinee049fa2017-03-25 00:38:45 -0500278 rc |= marshal_TPM_HANDLE(ob, command_body->enable);
279 rc |= obuf_write_be8(ob, command_body->state);
280
281 return rc;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600282}
283
Christian Walterc9ac0bc2020-01-28 19:54:33 +0100284static int marshal_clear_control(struct obuf *ob,
285 struct tpm2_clear_control_cmd *command_body)
286{
287 int rc = 0;
288 struct tpm2_session_header session_header;
289
290 tpm_tag = TPM_ST_SESSIONS;
291
292 rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
293 memset(&session_header, 0, sizeof(session_header));
294 session_header.session_handle = TPM_RS_PW;
295 rc |= marshal_session_header(ob, &session_header);
296
297 rc |= obuf_write_be8(ob, command_body->disable);
298
299 return rc;
300}
301
Aaron Durbinee049fa2017-03-25 00:38:45 -0500302static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
Aaron Durbineeb77372017-03-08 11:23:11 -0600303{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500304 int rc = 0;
305 uint16_t *sub_command = command_body;
Aaron Durbineeb77372017-03-08 11:23:11 -0600306
307 switch (*sub_command) {
Keith Shorte0f34002019-02-05 16:15:10 -0700308 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
309 /* The 16-bit timeout parameter is optional for the
310 * IMMEDIATE_RESET command. However in coreboot, the timeout
311 * parameter must be specified.
312 */
313 rc |= obuf_write_be16(ob, sub_command[0]);
314 rc |= obuf_write_be16(ob, sub_command[1]);
315 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600316 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500317 rc |= obuf_write_be16(ob, *sub_command);
Aaron Durbineeb77372017-03-08 11:23:11 -0600318 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700319 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500320 rc |= obuf_write_be16(ob, sub_command[0]);
321 rc |= obuf_write_be16(ob, sub_command[1]);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700322 break;
Keith Shorte371d422019-01-11 07:52:32 -0700323 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
324 rc |= obuf_write_be16(ob, *sub_command);
325 break;
Keith Shorte0f34002019-02-05 16:15:10 -0700326 case TPM2_CR50_SUB_CMD_TPM_MODE:
327 /* The Cr50 TPM_MODE command supports an optional parameter.
328 * When the parameter is present the Cr50 will attempt to change
329 * the TPM state (enable or disable) and returns the new state
330 * in the response. When the parameter is absent, the Cr50
331 * returns the current TPM state.
332 *
333 * coreboot currently only uses the TPM get capability and does
334 * not set a new TPM state with the Cr50.
335 */
336 rc |= obuf_write_be16(ob, *sub_command);
337 break;
dnojiri622c6b82020-04-03 10:51:50 -0700338 case TPM2_CR50_SUB_CMD_GET_BOOT_MODE:
339 rc |= obuf_write_be16(ob, *sub_command);
340 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600341 default:
342 /* Unsupported subcommand. */
343 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
344 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500345 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600346 break;
347 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500348 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600349}
350
Aaron Durbinee049fa2017-03-25 00:38:45 -0500351int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700352{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500353 struct obuf ob_hdr;
354 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
355 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700356
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100357 tpm_tag = TPM_ST_NO_SESSIONS;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700358
Aaron Durbinee049fa2017-03-25 00:38:45 -0500359 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
360 return -1;
361
362 /* Write TPM command header with placeholder field values. */
363 rc |= obuf_write_be16(ob, 0);
364 rc |= obuf_write_be32(ob, 0);
365 rc |= obuf_write_be32(ob, command);
366
367 if (rc != 0)
368 return rc;
369
Vadim Bendebury627afc22016-06-19 12:13:18 -0700370 switch (command) {
371 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500372 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700373 break;
374
Joel Kitching2e690ee2018-11-15 16:48:53 +0800375 case TPM2_Shutdown:
376 rc |= marshal_shutdown(ob, tpm_command_body);
377 break;
378
Vadim Bendebury627afc22016-06-19 12:13:18 -0700379 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500380 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700381 break;
382
383 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500384 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700385 break;
386
387 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500388 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700389 break;
390
391 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500392 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700393 break;
394
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700395 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500396 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700397 break;
398
Vadim Bendebury627afc22016-06-19 12:13:18 -0700399 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500400 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700401 break;
402
Aaron Durbinf56c7782017-01-10 17:44:42 -0600403 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500404 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600405 break;
406
Christian Walterc9ac0bc2020-01-28 19:54:33 +0100407 case TPM2_ClearControl:
408 rc |= marshal_clear_control(ob, tpm_command_body);
409 break;
410
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700411 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500412 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700413 break;
414
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700415 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500416 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700417 break;
418
Aaron Durbineeb77372017-03-08 11:23:11 -0600419 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500420 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600421 break;
422
Vadim Bendebury627afc22016-06-19 12:13:18 -0700423 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700424 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
425 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500426 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700427 }
428
Aaron Durbinee049fa2017-03-25 00:38:45 -0500429 if (rc != 0)
430 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700431
Aaron Durbinee049fa2017-03-25 00:38:45 -0500432 /* Fix up the command header with known values. */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100433 rc |= obuf_write_be16(&ob_hdr, tpm_tag);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500434 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700435
Aaron Durbinee049fa2017-03-25 00:38:45 -0500436 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700437}
438
Aaron Durbinee049fa2017-03-25 00:38:45 -0500439static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700440 struct get_cap_response *gcr)
441{
442 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500443 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700444
Aaron Durbinee049fa2017-03-25 00:38:45 -0500445 rc |= ibuf_read_be8(ib, &gcr->more_data);
446 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700447
Aaron Durbinee049fa2017-03-25 00:38:45 -0500448 if (rc != 0)
449 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700450
451 switch (gcr->cd.capability) {
452 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500453 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
454 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700455 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
456 (gcr->cd.data.tpmProperties.tpmProperty)) {
457 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
458 __FILE__, __func__, __LINE__,
459 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500460 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700461 }
462 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
463 TPMS_TAGGED_PROPERTY *pp;
464
465 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500466 rc |= unmarshal_TPM_PT(ib, &pp->property);
467 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700468 }
469 break;
Frans Hendriks589eff72019-06-26 10:43:40 +0200470 case TPM_CAP_PCRS:
471 if (ibuf_read_be32(ib, &gcr->cd.data.assignedPCR.count))
472 return -1;
473 if (gcr->cd.data.assignedPCR.count >
474 ARRAY_SIZE(gcr->cd.data.assignedPCR.pcrSelections)) {
475 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
476 __FILE__, __func__, __LINE__,
477 gcr->cd.data.assignedPCR.count);
478 return -1;
479 }
480 for (i = 0; i < gcr->cd.data.assignedPCR.count; i++) {
481 TPMS_PCR_SELECTION *pp =
482 &gcr->cd.data.assignedPCR.pcrSelections[i];
483 rc |= ibuf_read(ib, pp, sizeof(TPMS_PCR_SELECTION));
484 }
485 break;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700486 default:
487 printk(BIOS_ERR,
488 "%s:%d - unable to unmarshal capability response",
489 __func__, __LINE__);
490 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500491 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700492 break;
493 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500494
495 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700496}
497
Aaron Durbinee049fa2017-03-25 00:38:45 -0500498static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700499 TPM2B_MAX_NV_BUFFER *nv_buffer)
500{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500501 if (ibuf_read_be16(ib, &nv_buffer->t.size))
502 return -1;
503
504 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
505
506 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700507 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500508 "size mismatch: expected %d, remaining %zd\n",
509 __func__, __LINE__, nv_buffer->t.size,
510 ibuf_remaining(ib));
511 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700512 }
513
Aaron Durbinee049fa2017-03-25 00:38:45 -0500514 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700515}
516
Aaron Durbinee049fa2017-03-25 00:38:45 -0500517static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700518{
519 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500520 if (ibuf_read_be32(ib, &nvr->params_size))
521 return -1;
522
523 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
524 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700525
526 if (nvr->params_size !=
527 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
528 printk(BIOS_ERR,
529 "%s:%d - parameter/buffer %d/%d size mismatch",
530 __func__, __LINE__, nvr->params_size,
531 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500532 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700533 }
534
Vadim Bendebury627afc22016-06-19 12:13:18 -0700535 /*
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100536 * Let's ignore the authorization section. It should be 5 bytes total,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700537 * just confirm that this is the case and report any discrepancy.
538 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500539 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700540 printk(BIOS_ERR,
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100541 "%s:%d - unexpected authorization section size %zd\n",
Aaron Durbinee049fa2017-03-25 00:38:45 -0500542 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700543
Aaron Durbinee049fa2017-03-25 00:38:45 -0500544 ibuf_oob_drain(ib, ibuf_remaining(ib));
545
546 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700547}
548
Aaron Durbinee049fa2017-03-25 00:38:45 -0500549static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700550 struct vendor_command_response *vcr)
551{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500552 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
553 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700554
555 switch (vcr->vc_subcommand) {
Keith Shorte0f34002019-02-05 16:15:10 -0700556 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
557 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700558 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
559 break;
560 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500561 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Keith Shorte371d422019-01-11 07:52:32 -0700562 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
563 return ibuf_read_be8(ib, &vcr->recovery_button_state);
Keith Shorte0f34002019-02-05 16:15:10 -0700564 case TPM2_CR50_SUB_CMD_TPM_MODE:
565 return ibuf_read_be8(ib, &vcr->tpm_mode);
dnojiri622c6b82020-04-03 10:51:50 -0700566 case TPM2_CR50_SUB_CMD_GET_BOOT_MODE:
567 return ibuf_read_be8(ib, &vcr->boot_mode);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700568 default:
569 printk(BIOS_ERR,
570 "%s:%d - unsupported vendor command %#04x!\n",
571 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500572 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700573 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500574
575 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700576}
577
Aaron Durbinee049fa2017-03-25 00:38:45 -0500578struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700579{
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100580 static struct tpm2_response tpm2_static_resp;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500581 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700582
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100583 rc |= ibuf_read_be16(ib, &tpm2_static_resp.hdr.tpm_tag);
584 rc |= ibuf_read_be32(ib, &tpm2_static_resp.hdr.tpm_size);
585 rc |= unmarshal_TPM_CC(ib, &tpm2_static_resp.hdr.tpm_code);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500586
587 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700588 return NULL;
589
Aaron Durbinee049fa2017-03-25 00:38:45 -0500590 if (ibuf_remaining(ib) == 0) {
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100591 if (tpm2_static_resp.hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700592 printk(BIOS_ERR,
593 "%s: size mismatch in response to command %#x\n",
594 __func__, command);
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100595 return &tpm2_static_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700596 }
597
598 switch (command) {
599 case TPM2_Startup:
Joel Kitching2e690ee2018-11-15 16:48:53 +0800600 case TPM2_Shutdown:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700601 break;
602
603 case TPM2_GetCapability:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100604 rc |= unmarshal_get_capability(ib, &tpm2_static_resp.gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700605 break;
606
607 case TPM2_NV_Read:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100608 rc |= unmarshal_nv_read(ib, &tpm2_static_resp.nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700609 break;
610
Aaron Durbinf56c7782017-01-10 17:44:42 -0600611 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700612 case TPM2_Clear:
Christian Walterc9ac0bc2020-01-28 19:54:33 +0100613 case TPM2_ClearControl:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700614 case TPM2_NV_DefineSpace:
615 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700616 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700617 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700618 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500619 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700620 break;
621
Aaron Durbineeb77372017-03-08 11:23:11 -0600622 case TPM2_CR50_VENDOR_COMMAND:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100623 rc |= unmarshal_vendor_command(ib, &tpm2_static_resp.vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600624 break;
625
Vadim Bendebury627afc22016-06-19 12:13:18 -0700626 default:
627 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500628 size_t i;
629 size_t sz_left;
630 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700631
632 printk(BIOS_INFO, "%s:%d:"
633 "Request to unmarshal unexpected command %#x,"
634 " code %#x",
635 __func__, __LINE__, command,
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100636 tpm2_static_resp.hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700637
Aaron Durbinee049fa2017-03-25 00:38:45 -0500638 sz_left = ibuf_remaining(ib);
639 data = ibuf_oob_drain(ib, sz_left);
640
641 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700642 if (!(i % 16))
643 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500644 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700645 }
646 }
647 printk(BIOS_INFO, "\n");
648 return NULL;
649 }
650
Aaron Durbinee049fa2017-03-25 00:38:45 -0500651 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700652 printk(BIOS_INFO,
653 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500654 " failed to parse (%zd)\n",
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100655 __func__, __LINE__, tpm2_static_resp.hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500656 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700657 return NULL;
658 }
Richard Spiegel248c60a2018-08-07 09:24:14 -0700659 if (rc)
660 printk(BIOS_WARNING, "Warning: %s had one or more failures.\n",
661 __func__);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700662
663 /* The entire message have been parsed. */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100664 return &tpm2_static_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700665}