blob: b1d666362beb0290d6ec54fd05565d6832683e0d [file] [log] [blame]
Vadim Bendebury627afc22016-06-19 12:13:18 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Victor Prupisf7060202016-08-19 10:45:04 -07007#include <arch/early_variables.h>
Aaron Durbinee049fa2017-03-25 00:38:45 -05008#include <commonlib/iobuf.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -07009#include <console/console.h>
10#include <stdlib.h>
11#include <string.h>
12
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020013#include "tss_marshaling.h"
Vadim Bendebury627afc22016-06-19 12:13:18 -070014
Victor Prupisf7060202016-08-19 10:45:04 -070015static uint16_t tpm_tag CAR_GLOBAL; /* Depends on the command type. */
Vadim Bendebury627afc22016-06-19 12:13:18 -070016
Aaron Durbinee049fa2017-03-25 00:38:45 -050017#define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b)
18#define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b)
19#define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b)
20#define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b)
21
22#define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b)
23#define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b)
24
25static int marshal_startup(struct obuf *ob, struct tpm2_startup *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070026{
Aaron Durbinee049fa2017-03-25 00:38:45 -050027 return obuf_write_be16(ob, cmd_body->startup_type);
Vadim Bendebury627afc22016-06-19 12:13:18 -070028}
29
Aaron Durbinee049fa2017-03-25 00:38:45 -050030static int marshal_get_capability(struct obuf *ob,
31 struct tpm2_get_capability *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070032{
Aaron Durbinee049fa2017-03-25 00:38:45 -050033 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070034
Aaron Durbinee049fa2017-03-25 00:38:45 -050035 rc |= obuf_write_be32(ob, cmd_body->capability);
36 rc |= obuf_write_be32(ob, cmd_body->property);
37 rc |= obuf_write_be32(ob, cmd_body->propertyCount);
Vadim Bendeburybc927102016-07-07 10:52:46 -070038
Aaron Durbinee049fa2017-03-25 00:38:45 -050039 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070040}
41
Aaron Durbinee049fa2017-03-25 00:38:45 -050042static int marshal_TPM2B(struct obuf *ob, TPM2B *data)
Vadim Bendebury627afc22016-06-19 12:13:18 -070043{
Aaron Durbinee049fa2017-03-25 00:38:45 -050044 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070045
Aaron Durbinee049fa2017-03-25 00:38:45 -050046 rc |= obuf_write_be16(ob, data->size);
47 rc |= obuf_write(ob, data->buffer, data->size);
Vadim Bendeburybc927102016-07-07 10:52:46 -070048
Aaron Durbinee049fa2017-03-25 00:38:45 -050049 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070050}
51
Aaron Durbinee049fa2017-03-25 00:38:45 -050052static int marshal_TPMA_NV(struct obuf *ob, TPMA_NV *nv)
Vadim Bendebury627afc22016-06-19 12:13:18 -070053{
Aaron Durbinee049fa2017-03-25 00:38:45 -050054 uint32_t v;
Vadim Bendebury627afc22016-06-19 12:13:18 -070055
Aaron Durbinee049fa2017-03-25 00:38:45 -050056 memcpy(&v, nv, sizeof(v));
57 return obuf_write_be32(ob, v);
Vadim Bendebury627afc22016-06-19 12:13:18 -070058}
59
Aaron Durbinee049fa2017-03-25 00:38:45 -050060static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, TPMS_NV_PUBLIC *nvpub)
Vadim Bendebury627afc22016-06-19 12:13:18 -070061{
Aaron Durbinee049fa2017-03-25 00:38:45 -050062 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070063
Aaron Durbinee049fa2017-03-25 00:38:45 -050064 rc |= marshal_TPM_HANDLE(ob, nvpub->nvIndex);
65 rc |= marshal_TPMI_ALG_HASH(ob, nvpub->nameAlg);
66 rc |= marshal_TPMA_NV(ob, &nvpub->attributes);
67 rc |= marshal_TPM2B(ob, &nvpub->authPolicy.b);
68 rc |= obuf_write_be16(ob, nvpub->dataSize);
Vadim Bendebury627afc22016-06-19 12:13:18 -070069
Aaron Durbinee049fa2017-03-25 00:38:45 -050070 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070071}
72
Aaron Durbinee049fa2017-03-25 00:38:45 -050073static int marshal_TPMT_HA(struct obuf *ob, TPMT_HA *tpmtha)
Vadim Bendebury627afc22016-06-19 12:13:18 -070074{
Aaron Durbinee049fa2017-03-25 00:38:45 -050075 int rc = 0;
76
77 rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg);
78 rc |= obuf_write(ob, tpmtha->digest.sha256,
79 sizeof(tpmtha->digest.sha256));
80
81 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070082}
83
Aaron Durbinee049fa2017-03-25 00:38:45 -050084static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
85 TPML_DIGEST_VALUES *dvalues)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070086{
87 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -050088 int rc = 0;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070089
Aaron Durbinee049fa2017-03-25 00:38:45 -050090 rc |= obuf_write_be32(ob, dvalues->count);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070091 for (i = 0; i < dvalues->count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -050092 rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
93
94 return rc;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070095}
96
Aaron Durbinee049fa2017-03-25 00:38:45 -050097static int marshal_session_header(struct obuf *ob,
98 struct tpm2_session_header *session_header)
Vadim Bendebury627afc22016-06-19 12:13:18 -070099{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500100 int rc = 0;
101 struct obuf ob_sz;
102 size_t prev_written;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700103
Aaron Durbinee049fa2017-03-25 00:38:45 -0500104 /* Snapshot current location to place size of header. */
105 if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
106 return -1;
Vadim Bendeburybc927102016-07-07 10:52:46 -0700107
Aaron Durbinee049fa2017-03-25 00:38:45 -0500108 /* Write a size placeholder. */
109 rc |= obuf_write_be32(ob, 0);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700110
Aaron Durbinee049fa2017-03-25 00:38:45 -0500111 /* Keep track of session header data size by tracking num written. */
112 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700113
Aaron Durbinee049fa2017-03-25 00:38:45 -0500114 rc |= obuf_write_be32(ob, session_header->session_handle);
115 rc |= obuf_write_be16(ob, session_header->nonce_size);
116 rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
117 rc |= obuf_write_be8(ob, session_header->session_attrs);
118 rc |= obuf_write_be16(ob, session_header->auth_size);
119 rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700120
Aaron Durbinee049fa2017-03-25 00:38:45 -0500121 /* Fill back in proper size of session header. */
122 rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700123
Aaron Durbinee049fa2017-03-25 00:38:45 -0500124 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700125}
126
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700127/*
128 * Common session header can include one or two handles and an empty
129 * session_header structure.
130 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500131static int marshal_common_session_header(struct obuf *ob,
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700132 const uint32_t *handles,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500133 size_t handle_count)
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700134{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500135 size_t i;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700136 struct tpm2_session_header session_header;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500137 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700138
Victor Prupisf7060202016-08-19 10:45:04 -0700139 car_set_var(tpm_tag, TPM_ST_SESSIONS);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700140
141 for (i = 0; i < handle_count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500142 rc |= marshal_TPM_HANDLE(ob, handles[i]);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700143
144 memset(&session_header, 0, sizeof(session_header));
145 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500146 rc |= marshal_session_header(ob, &session_header);
147
148 return rc;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700149}
150
Aaron Durbinee049fa2017-03-25 00:38:45 -0500151static int marshal_nv_define_space(struct obuf *ob,
152 struct tpm2_nv_define_space_cmd *nvd_in)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700153{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700154 const uint32_t handle[] = { TPM_RH_PLATFORM };
Aaron Durbinee049fa2017-03-25 00:38:45 -0500155 struct obuf ob_sz;
156 size_t prev_written;
157 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700158
Aaron Durbinee049fa2017-03-25 00:38:45 -0500159 rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
160 rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700161
Aaron Durbinee049fa2017-03-25 00:38:45 -0500162 /* Snapshot current location to place size field. */
163 if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
164 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700165
Aaron Durbinee049fa2017-03-25 00:38:45 -0500166 /* Put placeholder for size */
167 rc |= obuf_write_be16(ob, 0);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700168
Aaron Durbinee049fa2017-03-25 00:38:45 -0500169 /* Keep track of nv define space data size by tracking num written. */
170 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700171
Aaron Durbinee049fa2017-03-25 00:38:45 -0500172 rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
173 rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700174
Aaron Durbinee049fa2017-03-25 00:38:45 -0500175 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700176}
177
Aaron Durbinee049fa2017-03-25 00:38:45 -0500178static int marshal_nv_write(struct obuf *ob,
179 struct tpm2_nv_write_cmd *command_body)
180{
181 int rc = 0;
182 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
183
184 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
185 rc |= marshal_TPM2B(ob, &command_body->data.b);
186 rc |= obuf_write_be16(ob, command_body->offset);
187
188 return rc;
189}
190
191static int marshal_nv_write_lock(struct obuf *ob,
192 struct tpm2_nv_write_lock_cmd *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700193{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700194 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700195
Aaron Durbinee049fa2017-03-25 00:38:45 -0500196 return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700197}
198
Aaron Durbinee049fa2017-03-25 00:38:45 -0500199static int marshal_pcr_extend(struct obuf *ob,
200 struct tpm2_pcr_extend_cmd *command_body)
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700201{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500202 int rc = 0;
203 uint32_t handles[] = { command_body->pcrHandle };
204
205 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
206 rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
207
208 return rc;
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700209}
210
Aaron Durbinee049fa2017-03-25 00:38:45 -0500211static int marshal_nv_read(struct obuf *ob,
212 struct tpm2_nv_read_cmd *command_body)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700213{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500214 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700215 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700216
Aaron Durbinee049fa2017-03-25 00:38:45 -0500217 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
218 rc |= obuf_write_be16(ob, command_body->size);
219 rc |= obuf_write_be16(ob, command_body->offset);
220
221 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700222}
223
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700224/* TPM2_Clear command does not require paramaters. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500225static int marshal_clear(struct obuf *ob)
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700226{
227 const uint32_t handle[] = { TPM_RH_PLATFORM };
228
Aaron Durbinee049fa2017-03-25 00:38:45 -0500229 return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700230}
231
Aaron Durbinee049fa2017-03-25 00:38:45 -0500232static int marshal_selftest(struct obuf *ob,
233 struct tpm2_self_test *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700234{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500235 return obuf_write_be8(ob, command_body->yes_no);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700236}
237
Aaron Durbinee049fa2017-03-25 00:38:45 -0500238static int marshal_hierarchy_control(struct obuf *ob,
239 struct tpm2_hierarchy_control_cmd *command_body)
Aaron Durbinf56c7782017-01-10 17:44:42 -0600240{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500241 int rc = 0;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600242 struct tpm2_session_header session_header;
243
244 car_set_var(tpm_tag, TPM_ST_SESSIONS);
245
Aaron Durbinee049fa2017-03-25 00:38:45 -0500246 rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600247 memset(&session_header, 0, sizeof(session_header));
248 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500249 rc |= marshal_session_header(ob, &session_header);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600250
Aaron Durbinee049fa2017-03-25 00:38:45 -0500251 rc |= marshal_TPM_HANDLE(ob, command_body->enable);
252 rc |= obuf_write_be8(ob, command_body->state);
253
254 return rc;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600255}
256
Aaron Durbinee049fa2017-03-25 00:38:45 -0500257static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
Aaron Durbineeb77372017-03-08 11:23:11 -0600258{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500259 int rc = 0;
260 uint16_t *sub_command = command_body;
Aaron Durbineeb77372017-03-08 11:23:11 -0600261
262 switch (*sub_command) {
263 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500264 rc |= obuf_write_be16(ob, *sub_command);
Aaron Durbineeb77372017-03-08 11:23:11 -0600265 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700266 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500267 rc |= obuf_write_be16(ob, sub_command[0]);
268 rc |= obuf_write_be16(ob, sub_command[1]);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700269 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600270 default:
271 /* Unsupported subcommand. */
272 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
273 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500274 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600275 break;
276 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500277 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600278}
279
Aaron Durbinee049fa2017-03-25 00:38:45 -0500280int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700281{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500282 struct obuf ob_hdr;
283 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
284 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700285
Victor Prupisf7060202016-08-19 10:45:04 -0700286 car_set_var(tpm_tag, TPM_ST_NO_SESSIONS);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700287
Aaron Durbinee049fa2017-03-25 00:38:45 -0500288 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
289 return -1;
290
291 /* Write TPM command header with placeholder field values. */
292 rc |= obuf_write_be16(ob, 0);
293 rc |= obuf_write_be32(ob, 0);
294 rc |= obuf_write_be32(ob, command);
295
296 if (rc != 0)
297 return rc;
298
Vadim Bendebury627afc22016-06-19 12:13:18 -0700299 switch (command) {
300 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500301 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700302 break;
303
304 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500305 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700306 break;
307
308 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500309 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700310 break;
311
312 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500313 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700314 break;
315
316 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500317 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700318 break;
319
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700320 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500321 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700322 break;
323
Vadim Bendebury627afc22016-06-19 12:13:18 -0700324 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500325 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700326 break;
327
Aaron Durbinf56c7782017-01-10 17:44:42 -0600328 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500329 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600330 break;
331
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700332 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500333 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700334 break;
335
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700336 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500337 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700338 break;
339
Aaron Durbineeb77372017-03-08 11:23:11 -0600340 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500341 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600342 break;
343
Vadim Bendebury627afc22016-06-19 12:13:18 -0700344 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700345 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
346 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500347 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700348 }
349
Aaron Durbinee049fa2017-03-25 00:38:45 -0500350 if (rc != 0)
351 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700352
Aaron Durbinee049fa2017-03-25 00:38:45 -0500353 /* Fix up the command header with known values. */
354 rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag));
355 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700356
Aaron Durbinee049fa2017-03-25 00:38:45 -0500357 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700358}
359
Aaron Durbinee049fa2017-03-25 00:38:45 -0500360static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700361 struct get_cap_response *gcr)
362{
363 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500364 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700365
Aaron Durbinee049fa2017-03-25 00:38:45 -0500366 rc |= ibuf_read_be8(ib, &gcr->more_data);
367 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700368
Aaron Durbinee049fa2017-03-25 00:38:45 -0500369 if (rc != 0)
370 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700371
372 switch (gcr->cd.capability) {
373 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500374 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
375 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700376 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
377 (gcr->cd.data.tpmProperties.tpmProperty)) {
378 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
379 __FILE__, __func__, __LINE__,
380 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500381 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700382 }
383 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
384 TPMS_TAGGED_PROPERTY *pp;
385
386 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500387 rc |= unmarshal_TPM_PT(ib, &pp->property);
388 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700389 }
390 break;
391 default:
392 printk(BIOS_ERR,
393 "%s:%d - unable to unmarshal capability response",
394 __func__, __LINE__);
395 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500396 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700397 break;
398 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500399
400 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700401}
402
Aaron Durbinee049fa2017-03-25 00:38:45 -0500403static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700404 TPM2B_MAX_NV_BUFFER *nv_buffer)
405{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500406 if (ibuf_read_be16(ib, &nv_buffer->t.size))
407 return -1;
408
409 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
410
411 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700412 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500413 "size mismatch: expected %d, remaining %zd\n",
414 __func__, __LINE__, nv_buffer->t.size,
415 ibuf_remaining(ib));
416 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700417 }
418
Aaron Durbinee049fa2017-03-25 00:38:45 -0500419 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700420}
421
Aaron Durbinee049fa2017-03-25 00:38:45 -0500422static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700423{
424 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500425 if (ibuf_read_be32(ib, &nvr->params_size))
426 return -1;
427
428 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
429 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700430
431 if (nvr->params_size !=
432 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
433 printk(BIOS_ERR,
434 "%s:%d - parameter/buffer %d/%d size mismatch",
435 __func__, __LINE__, nvr->params_size,
436 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500437 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700438 }
439
Vadim Bendebury627afc22016-06-19 12:13:18 -0700440 /*
441 * Let's ignore the authorisation section. It should be 5 bytes total,
442 * just confirm that this is the case and report any discrepancy.
443 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500444 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700445 printk(BIOS_ERR,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500446 "%s:%d - unexpected authorisation seciton size %zd\n",
447 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700448
Aaron Durbinee049fa2017-03-25 00:38:45 -0500449 ibuf_oob_drain(ib, ibuf_remaining(ib));
450
451 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700452}
453
Aaron Durbinee049fa2017-03-25 00:38:45 -0500454static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700455 struct vendor_command_response *vcr)
456{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500457 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
458 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700459
460 switch (vcr->vc_subcommand) {
461 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
462 break;
463 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500464 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700465 break;
466 default:
467 printk(BIOS_ERR,
468 "%s:%d - unsupported vendor command %#04x!\n",
469 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500470 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700471 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500472
473 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700474}
475
Aaron Durbinee049fa2017-03-25 00:38:45 -0500476struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700477{
Duncan Laurie4a560762016-09-01 16:09:43 -0700478 static struct tpm2_response tpm2_static_resp CAR_GLOBAL;
479 struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500480 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700481
Aaron Durbinee049fa2017-03-25 00:38:45 -0500482 rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag);
483 rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size);
484 rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code);
485
486 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700487 return NULL;
488
Aaron Durbinee049fa2017-03-25 00:38:45 -0500489 if (ibuf_remaining(ib) == 0) {
490 if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700491 printk(BIOS_ERR,
492 "%s: size mismatch in response to command %#x\n",
493 __func__, command);
Duncan Laurie4a560762016-09-01 16:09:43 -0700494 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700495 }
496
497 switch (command) {
498 case TPM2_Startup:
499 break;
500
501 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500502 rc |= unmarshal_get_capability(ib, &tpm2_resp->gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700503 break;
504
505 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500506 rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700507 break;
508
Aaron Durbinf56c7782017-01-10 17:44:42 -0600509 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700510 case TPM2_Clear:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700511 case TPM2_NV_DefineSpace:
512 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700513 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700514 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700515 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500516 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700517 break;
518
Aaron Durbineeb77372017-03-08 11:23:11 -0600519 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500520 rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600521 break;
522
Vadim Bendebury627afc22016-06-19 12:13:18 -0700523 default:
524 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500525 size_t i;
526 size_t sz_left;
527 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700528
529 printk(BIOS_INFO, "%s:%d:"
530 "Request to unmarshal unexpected command %#x,"
531 " code %#x",
532 __func__, __LINE__, command,
Duncan Laurie4a560762016-09-01 16:09:43 -0700533 tpm2_resp->hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700534
Aaron Durbinee049fa2017-03-25 00:38:45 -0500535 sz_left = ibuf_remaining(ib);
536 data = ibuf_oob_drain(ib, sz_left);
537
538 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700539 if (!(i % 16))
540 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500541 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700542 }
543 }
544 printk(BIOS_INFO, "\n");
545 return NULL;
546 }
547
Aaron Durbinee049fa2017-03-25 00:38:45 -0500548 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700549 printk(BIOS_INFO,
550 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500551 " failed to parse (%zd)\n",
Duncan Laurie4a560762016-09-01 16:09:43 -0700552 __func__, __LINE__, tpm2_resp->hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500553 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700554 return NULL;
555 }
556
557 /* The entire message have been parsed. */
Duncan Laurie4a560762016-09-01 16:09:43 -0700558 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700559}