blob: 45ade1a314165b228f45545fa707c9bcf2b4721a [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;
Aaron Durbineeb77372017-03-08 11:23:11 -0600338 default:
339 /* Unsupported subcommand. */
340 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
341 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500342 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600343 break;
344 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500345 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600346}
347
Aaron Durbinee049fa2017-03-25 00:38:45 -0500348int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700349{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500350 struct obuf ob_hdr;
351 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
352 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700353
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100354 tpm_tag = TPM_ST_NO_SESSIONS;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700355
Aaron Durbinee049fa2017-03-25 00:38:45 -0500356 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
357 return -1;
358
359 /* Write TPM command header with placeholder field values. */
360 rc |= obuf_write_be16(ob, 0);
361 rc |= obuf_write_be32(ob, 0);
362 rc |= obuf_write_be32(ob, command);
363
364 if (rc != 0)
365 return rc;
366
Vadim Bendebury627afc22016-06-19 12:13:18 -0700367 switch (command) {
368 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500369 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700370 break;
371
Joel Kitching2e690ee2018-11-15 16:48:53 +0800372 case TPM2_Shutdown:
373 rc |= marshal_shutdown(ob, tpm_command_body);
374 break;
375
Vadim Bendebury627afc22016-06-19 12:13:18 -0700376 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500377 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700378 break;
379
380 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500381 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700382 break;
383
384 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500385 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700386 break;
387
388 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500389 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700390 break;
391
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700392 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500393 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700394 break;
395
Vadim Bendebury627afc22016-06-19 12:13:18 -0700396 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500397 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700398 break;
399
Aaron Durbinf56c7782017-01-10 17:44:42 -0600400 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500401 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600402 break;
403
Christian Walterc9ac0bc2020-01-28 19:54:33 +0100404 case TPM2_ClearControl:
405 rc |= marshal_clear_control(ob, tpm_command_body);
406 break;
407
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700408 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500409 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700410 break;
411
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700412 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500413 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700414 break;
415
Aaron Durbineeb77372017-03-08 11:23:11 -0600416 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500417 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600418 break;
419
Vadim Bendebury627afc22016-06-19 12:13:18 -0700420 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700421 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
422 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500423 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700424 }
425
Aaron Durbinee049fa2017-03-25 00:38:45 -0500426 if (rc != 0)
427 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700428
Aaron Durbinee049fa2017-03-25 00:38:45 -0500429 /* Fix up the command header with known values. */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100430 rc |= obuf_write_be16(&ob_hdr, tpm_tag);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500431 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700432
Aaron Durbinee049fa2017-03-25 00:38:45 -0500433 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700434}
435
Aaron Durbinee049fa2017-03-25 00:38:45 -0500436static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700437 struct get_cap_response *gcr)
438{
439 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500440 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700441
Aaron Durbinee049fa2017-03-25 00:38:45 -0500442 rc |= ibuf_read_be8(ib, &gcr->more_data);
443 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700444
Aaron Durbinee049fa2017-03-25 00:38:45 -0500445 if (rc != 0)
446 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700447
448 switch (gcr->cd.capability) {
449 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500450 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
451 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700452 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
453 (gcr->cd.data.tpmProperties.tpmProperty)) {
454 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
455 __FILE__, __func__, __LINE__,
456 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500457 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700458 }
459 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
460 TPMS_TAGGED_PROPERTY *pp;
461
462 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500463 rc |= unmarshal_TPM_PT(ib, &pp->property);
464 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700465 }
466 break;
Frans Hendriks589eff72019-06-26 10:43:40 +0200467 case TPM_CAP_PCRS:
468 if (ibuf_read_be32(ib, &gcr->cd.data.assignedPCR.count))
469 return -1;
470 if (gcr->cd.data.assignedPCR.count >
471 ARRAY_SIZE(gcr->cd.data.assignedPCR.pcrSelections)) {
472 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
473 __FILE__, __func__, __LINE__,
474 gcr->cd.data.assignedPCR.count);
475 return -1;
476 }
477 for (i = 0; i < gcr->cd.data.assignedPCR.count; i++) {
478 TPMS_PCR_SELECTION *pp =
479 &gcr->cd.data.assignedPCR.pcrSelections[i];
480 rc |= ibuf_read(ib, pp, sizeof(TPMS_PCR_SELECTION));
481 }
482 break;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700483 default:
484 printk(BIOS_ERR,
485 "%s:%d - unable to unmarshal capability response",
486 __func__, __LINE__);
487 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500488 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700489 break;
490 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500491
492 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700493}
494
Aaron Durbinee049fa2017-03-25 00:38:45 -0500495static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700496 TPM2B_MAX_NV_BUFFER *nv_buffer)
497{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500498 if (ibuf_read_be16(ib, &nv_buffer->t.size))
499 return -1;
500
501 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
502
503 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700504 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500505 "size mismatch: expected %d, remaining %zd\n",
506 __func__, __LINE__, nv_buffer->t.size,
507 ibuf_remaining(ib));
508 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700509 }
510
Aaron Durbinee049fa2017-03-25 00:38:45 -0500511 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700512}
513
Aaron Durbinee049fa2017-03-25 00:38:45 -0500514static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700515{
516 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500517 if (ibuf_read_be32(ib, &nvr->params_size))
518 return -1;
519
520 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
521 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700522
523 if (nvr->params_size !=
524 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
525 printk(BIOS_ERR,
526 "%s:%d - parameter/buffer %d/%d size mismatch",
527 __func__, __LINE__, nvr->params_size,
528 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500529 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700530 }
531
Vadim Bendebury627afc22016-06-19 12:13:18 -0700532 /*
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100533 * Let's ignore the authorization section. It should be 5 bytes total,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700534 * just confirm that this is the case and report any discrepancy.
535 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500536 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700537 printk(BIOS_ERR,
Frans Hendriks8bd5c992018-10-29 10:47:52 +0100538 "%s:%d - unexpected authorization section size %zd\n",
Aaron Durbinee049fa2017-03-25 00:38:45 -0500539 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700540
Aaron Durbinee049fa2017-03-25 00:38:45 -0500541 ibuf_oob_drain(ib, ibuf_remaining(ib));
542
543 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700544}
545
Aaron Durbinee049fa2017-03-25 00:38:45 -0500546static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700547 struct vendor_command_response *vcr)
548{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500549 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
550 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700551
552 switch (vcr->vc_subcommand) {
Keith Shorte0f34002019-02-05 16:15:10 -0700553 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
554 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700555 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
556 break;
557 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500558 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Keith Shorte371d422019-01-11 07:52:32 -0700559 case TPM2_CR50_SUB_CMD_GET_REC_BTN:
560 return ibuf_read_be8(ib, &vcr->recovery_button_state);
Keith Shorte0f34002019-02-05 16:15:10 -0700561 case TPM2_CR50_SUB_CMD_TPM_MODE:
562 return ibuf_read_be8(ib, &vcr->tpm_mode);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700563 default:
564 printk(BIOS_ERR,
565 "%s:%d - unsupported vendor command %#04x!\n",
566 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500567 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700568 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500569
570 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700571}
572
Aaron Durbinee049fa2017-03-25 00:38:45 -0500573struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700574{
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100575 static struct tpm2_response tpm2_static_resp;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500576 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700577
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100578 rc |= ibuf_read_be16(ib, &tpm2_static_resp.hdr.tpm_tag);
579 rc |= ibuf_read_be32(ib, &tpm2_static_resp.hdr.tpm_size);
580 rc |= unmarshal_TPM_CC(ib, &tpm2_static_resp.hdr.tpm_code);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500581
582 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700583 return NULL;
584
Aaron Durbinee049fa2017-03-25 00:38:45 -0500585 if (ibuf_remaining(ib) == 0) {
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100586 if (tpm2_static_resp.hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700587 printk(BIOS_ERR,
588 "%s: size mismatch in response to command %#x\n",
589 __func__, command);
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100590 return &tpm2_static_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700591 }
592
593 switch (command) {
594 case TPM2_Startup:
Joel Kitching2e690ee2018-11-15 16:48:53 +0800595 case TPM2_Shutdown:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700596 break;
597
598 case TPM2_GetCapability:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100599 rc |= unmarshal_get_capability(ib, &tpm2_static_resp.gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700600 break;
601
602 case TPM2_NV_Read:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100603 rc |= unmarshal_nv_read(ib, &tpm2_static_resp.nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700604 break;
605
Aaron Durbinf56c7782017-01-10 17:44:42 -0600606 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700607 case TPM2_Clear:
Christian Walterc9ac0bc2020-01-28 19:54:33 +0100608 case TPM2_ClearControl:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700609 case TPM2_NV_DefineSpace:
610 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700611 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700612 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700613 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500614 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700615 break;
616
Aaron Durbineeb77372017-03-08 11:23:11 -0600617 case TPM2_CR50_VENDOR_COMMAND:
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100618 rc |= unmarshal_vendor_command(ib, &tpm2_static_resp.vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600619 break;
620
Vadim Bendebury627afc22016-06-19 12:13:18 -0700621 default:
622 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500623 size_t i;
624 size_t sz_left;
625 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700626
627 printk(BIOS_INFO, "%s:%d:"
628 "Request to unmarshal unexpected command %#x,"
629 " code %#x",
630 __func__, __LINE__, command,
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100631 tpm2_static_resp.hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700632
Aaron Durbinee049fa2017-03-25 00:38:45 -0500633 sz_left = ibuf_remaining(ib);
634 data = ibuf_oob_drain(ib, sz_left);
635
636 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700637 if (!(i % 16))
638 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500639 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700640 }
641 }
642 printk(BIOS_INFO, "\n");
643 return NULL;
644 }
645
Aaron Durbinee049fa2017-03-25 00:38:45 -0500646 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700647 printk(BIOS_INFO,
648 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500649 " failed to parse (%zd)\n",
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100650 __func__, __LINE__, tpm2_static_resp.hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500651 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700652 return NULL;
653 }
Richard Spiegel248c60a2018-08-07 09:24:14 -0700654 if (rc)
655 printk(BIOS_WARNING, "Warning: %s had one or more failures.\n",
656 __func__);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700657
658 /* The entire message have been parsed. */
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100659 return &tpm2_static_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700660}