blob: 94bfbcfb10bae0bba817a58489cdd3b8d37f88d3 [file] [log] [blame]
Vadim Bendebury627afc22016-06-19 12:13:18 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
Victor Prupisf7060202016-08-19 10:45:04 -07007#include <arch/early_variables.h>
Aaron Durbinee049fa2017-03-25 00:38:45 -05008#include <commonlib/iobuf.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -07009#include <console/console.h>
10#include <stdlib.h>
11#include <string.h>
12
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020013#include "tss_marshaling.h"
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010014#include <security/tpm/tss/vendor/cr50/cr50.h>
Vadim Bendebury627afc22016-06-19 12:13:18 -070015
Victor Prupisf7060202016-08-19 10:45:04 -070016static uint16_t tpm_tag CAR_GLOBAL; /* Depends on the command type. */
Vadim Bendebury627afc22016-06-19 12:13:18 -070017
Aaron Durbinee049fa2017-03-25 00:38:45 -050018#define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b)
19#define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b)
20#define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b)
21#define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b)
22
23#define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b)
24#define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b)
25
26static int marshal_startup(struct obuf *ob, struct tpm2_startup *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070027{
Aaron Durbinee049fa2017-03-25 00:38:45 -050028 return obuf_write_be16(ob, cmd_body->startup_type);
Vadim Bendebury627afc22016-06-19 12:13:18 -070029}
30
Aaron Durbinee049fa2017-03-25 00:38:45 -050031static int marshal_get_capability(struct obuf *ob,
32 struct tpm2_get_capability *cmd_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -070033{
Aaron Durbinee049fa2017-03-25 00:38:45 -050034 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070035
Aaron Durbinee049fa2017-03-25 00:38:45 -050036 rc |= obuf_write_be32(ob, cmd_body->capability);
37 rc |= obuf_write_be32(ob, cmd_body->property);
38 rc |= obuf_write_be32(ob, cmd_body->propertyCount);
Vadim Bendeburybc927102016-07-07 10:52:46 -070039
Aaron Durbinee049fa2017-03-25 00:38:45 -050040 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070041}
42
Aaron Durbinee049fa2017-03-25 00:38:45 -050043static int marshal_TPM2B(struct obuf *ob, TPM2B *data)
Vadim Bendebury627afc22016-06-19 12:13:18 -070044{
Aaron Durbinee049fa2017-03-25 00:38:45 -050045 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070046
Aaron Durbinee049fa2017-03-25 00:38:45 -050047 rc |= obuf_write_be16(ob, data->size);
48 rc |= obuf_write(ob, data->buffer, data->size);
Vadim Bendeburybc927102016-07-07 10:52:46 -070049
Aaron Durbinee049fa2017-03-25 00:38:45 -050050 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070051}
52
Aaron Durbinee049fa2017-03-25 00:38:45 -050053static int marshal_TPMA_NV(struct obuf *ob, TPMA_NV *nv)
Vadim Bendebury627afc22016-06-19 12:13:18 -070054{
Aaron Durbinee049fa2017-03-25 00:38:45 -050055 uint32_t v;
Vadim Bendebury627afc22016-06-19 12:13:18 -070056
Aaron Durbinee049fa2017-03-25 00:38:45 -050057 memcpy(&v, nv, sizeof(v));
58 return obuf_write_be32(ob, v);
Vadim Bendebury627afc22016-06-19 12:13:18 -070059}
60
Aaron Durbinee049fa2017-03-25 00:38:45 -050061static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, TPMS_NV_PUBLIC *nvpub)
Vadim Bendebury627afc22016-06-19 12:13:18 -070062{
Aaron Durbinee049fa2017-03-25 00:38:45 -050063 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -070064
Aaron Durbinee049fa2017-03-25 00:38:45 -050065 rc |= marshal_TPM_HANDLE(ob, nvpub->nvIndex);
66 rc |= marshal_TPMI_ALG_HASH(ob, nvpub->nameAlg);
67 rc |= marshal_TPMA_NV(ob, &nvpub->attributes);
68 rc |= marshal_TPM2B(ob, &nvpub->authPolicy.b);
69 rc |= obuf_write_be16(ob, nvpub->dataSize);
Vadim Bendebury627afc22016-06-19 12:13:18 -070070
Aaron Durbinee049fa2017-03-25 00:38:45 -050071 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070072}
73
Aaron Durbinee049fa2017-03-25 00:38:45 -050074static int marshal_TPMT_HA(struct obuf *ob, TPMT_HA *tpmtha)
Vadim Bendebury627afc22016-06-19 12:13:18 -070075{
Aaron Durbinee049fa2017-03-25 00:38:45 -050076 int rc = 0;
77
78 rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg);
79 rc |= obuf_write(ob, tpmtha->digest.sha256,
80 sizeof(tpmtha->digest.sha256));
81
82 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -070083}
84
Aaron Durbinee049fa2017-03-25 00:38:45 -050085static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
86 TPML_DIGEST_VALUES *dvalues)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070087{
88 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -050089 int rc = 0;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070090
Aaron Durbinee049fa2017-03-25 00:38:45 -050091 rc |= obuf_write_be32(ob, dvalues->count);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070092 for (i = 0; i < dvalues->count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -050093 rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
94
95 return rc;
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070096}
97
Aaron Durbinee049fa2017-03-25 00:38:45 -050098static int marshal_session_header(struct obuf *ob,
99 struct tpm2_session_header *session_header)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700100{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500101 int rc = 0;
102 struct obuf ob_sz;
103 size_t prev_written;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700104
Aaron Durbinee049fa2017-03-25 00:38:45 -0500105 /* Snapshot current location to place size of header. */
106 if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
107 return -1;
Vadim Bendeburybc927102016-07-07 10:52:46 -0700108
Aaron Durbinee049fa2017-03-25 00:38:45 -0500109 /* Write a size placeholder. */
110 rc |= obuf_write_be32(ob, 0);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700111
Aaron Durbinee049fa2017-03-25 00:38:45 -0500112 /* Keep track of session header data size by tracking num written. */
113 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700114
Aaron Durbinee049fa2017-03-25 00:38:45 -0500115 rc |= obuf_write_be32(ob, session_header->session_handle);
116 rc |= obuf_write_be16(ob, session_header->nonce_size);
117 rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
118 rc |= obuf_write_be8(ob, session_header->session_attrs);
119 rc |= obuf_write_be16(ob, session_header->auth_size);
120 rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700121
Aaron Durbinee049fa2017-03-25 00:38:45 -0500122 /* Fill back in proper size of session header. */
123 rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700124
Aaron Durbinee049fa2017-03-25 00:38:45 -0500125 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700126}
127
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700128/*
129 * Common session header can include one or two handles and an empty
130 * session_header structure.
131 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500132static int marshal_common_session_header(struct obuf *ob,
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700133 const uint32_t *handles,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500134 size_t handle_count)
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700135{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500136 size_t i;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700137 struct tpm2_session_header session_header;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500138 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700139
Victor Prupisf7060202016-08-19 10:45:04 -0700140 car_set_var(tpm_tag, TPM_ST_SESSIONS);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700141
142 for (i = 0; i < handle_count; i++)
Aaron Durbinee049fa2017-03-25 00:38:45 -0500143 rc |= marshal_TPM_HANDLE(ob, handles[i]);
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700144
145 memset(&session_header, 0, sizeof(session_header));
146 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500147 rc |= marshal_session_header(ob, &session_header);
148
149 return rc;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700150}
151
Aaron Durbinee049fa2017-03-25 00:38:45 -0500152static int marshal_nv_define_space(struct obuf *ob,
153 struct tpm2_nv_define_space_cmd *nvd_in)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700154{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700155 const uint32_t handle[] = { TPM_RH_PLATFORM };
Aaron Durbinee049fa2017-03-25 00:38:45 -0500156 struct obuf ob_sz;
157 size_t prev_written;
158 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700159
Aaron Durbinee049fa2017-03-25 00:38:45 -0500160 rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
161 rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700162
Aaron Durbinee049fa2017-03-25 00:38:45 -0500163 /* Snapshot current location to place size field. */
164 if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
165 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700166
Aaron Durbinee049fa2017-03-25 00:38:45 -0500167 /* Put placeholder for size */
168 rc |= obuf_write_be16(ob, 0);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700169
Aaron Durbinee049fa2017-03-25 00:38:45 -0500170 /* Keep track of nv define space data size by tracking num written. */
171 prev_written = obuf_nr_written(ob);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700172
Aaron Durbinee049fa2017-03-25 00:38:45 -0500173 rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
174 rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
Vadim Bendeburybc927102016-07-07 10:52:46 -0700175
Aaron Durbinee049fa2017-03-25 00:38:45 -0500176 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700177}
178
Aaron Durbinee049fa2017-03-25 00:38:45 -0500179static int marshal_nv_write(struct obuf *ob,
180 struct tpm2_nv_write_cmd *command_body)
181{
182 int rc = 0;
183 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
184
185 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
186 rc |= marshal_TPM2B(ob, &command_body->data.b);
187 rc |= obuf_write_be16(ob, command_body->offset);
188
189 return rc;
190}
191
192static int marshal_nv_write_lock(struct obuf *ob,
193 struct tpm2_nv_write_lock_cmd *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700194{
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700195 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700196
Aaron Durbinee049fa2017-03-25 00:38:45 -0500197 return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700198}
199
Aaron Durbinee049fa2017-03-25 00:38:45 -0500200static int marshal_pcr_extend(struct obuf *ob,
201 struct tpm2_pcr_extend_cmd *command_body)
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700202{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500203 int rc = 0;
204 uint32_t handles[] = { command_body->pcrHandle };
205
206 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
207 rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
208
209 return rc;
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700210}
211
Aaron Durbinee049fa2017-03-25 00:38:45 -0500212static int marshal_nv_read(struct obuf *ob,
213 struct tpm2_nv_read_cmd *command_body)
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700214{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500215 int rc = 0;
Vadim Bendeburyebba4d72016-07-07 11:04:06 -0700216 uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
Vadim Bendebury627afc22016-06-19 12:13:18 -0700217
Aaron Durbinee049fa2017-03-25 00:38:45 -0500218 rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
219 rc |= obuf_write_be16(ob, command_body->size);
220 rc |= obuf_write_be16(ob, command_body->offset);
221
222 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700223}
224
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700225/* TPM2_Clear command does not require paramaters. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500226static int marshal_clear(struct obuf *ob)
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700227{
228 const uint32_t handle[] = { TPM_RH_PLATFORM };
229
Aaron Durbinee049fa2017-03-25 00:38:45 -0500230 return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700231}
232
Aaron Durbinee049fa2017-03-25 00:38:45 -0500233static int marshal_selftest(struct obuf *ob,
234 struct tpm2_self_test *command_body)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700235{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500236 return obuf_write_be8(ob, command_body->yes_no);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700237}
238
Aaron Durbinee049fa2017-03-25 00:38:45 -0500239static int marshal_hierarchy_control(struct obuf *ob,
240 struct tpm2_hierarchy_control_cmd *command_body)
Aaron Durbinf56c7782017-01-10 17:44:42 -0600241{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500242 int rc = 0;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600243 struct tpm2_session_header session_header;
244
245 car_set_var(tpm_tag, TPM_ST_SESSIONS);
246
Aaron Durbinee049fa2017-03-25 00:38:45 -0500247 rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600248 memset(&session_header, 0, sizeof(session_header));
249 session_header.session_handle = TPM_RS_PW;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500250 rc |= marshal_session_header(ob, &session_header);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600251
Aaron Durbinee049fa2017-03-25 00:38:45 -0500252 rc |= marshal_TPM_HANDLE(ob, command_body->enable);
253 rc |= obuf_write_be8(ob, command_body->state);
254
255 return rc;
Aaron Durbinf56c7782017-01-10 17:44:42 -0600256}
257
Aaron Durbinee049fa2017-03-25 00:38:45 -0500258static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body)
Aaron Durbineeb77372017-03-08 11:23:11 -0600259{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500260 int rc = 0;
261 uint16_t *sub_command = command_body;
Aaron Durbineeb77372017-03-08 11:23:11 -0600262
263 switch (*sub_command) {
264 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500265 rc |= obuf_write_be16(ob, *sub_command);
Aaron Durbineeb77372017-03-08 11:23:11 -0600266 break;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700267 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500268 rc |= obuf_write_be16(ob, sub_command[0]);
269 rc |= obuf_write_be16(ob, sub_command[1]);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700270 break;
Aaron Durbineeb77372017-03-08 11:23:11 -0600271 default:
272 /* Unsupported subcommand. */
273 printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
274 *sub_command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500275 rc = -1;
Aaron Durbineeb77372017-03-08 11:23:11 -0600276 break;
277 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500278 return rc;
Aaron Durbineeb77372017-03-08 11:23:11 -0600279}
280
Aaron Durbinee049fa2017-03-25 00:38:45 -0500281int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700282{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500283 struct obuf ob_hdr;
284 const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
285 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700286
Victor Prupisf7060202016-08-19 10:45:04 -0700287 car_set_var(tpm_tag, TPM_ST_NO_SESSIONS);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700288
Aaron Durbinee049fa2017-03-25 00:38:45 -0500289 if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
290 return -1;
291
292 /* Write TPM command header with placeholder field values. */
293 rc |= obuf_write_be16(ob, 0);
294 rc |= obuf_write_be32(ob, 0);
295 rc |= obuf_write_be32(ob, command);
296
297 if (rc != 0)
298 return rc;
299
Vadim Bendebury627afc22016-06-19 12:13:18 -0700300 switch (command) {
301 case TPM2_Startup:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500302 rc |= marshal_startup(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700303 break;
304
305 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500306 rc |= marshal_get_capability(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700307 break;
308
309 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500310 rc |= marshal_nv_read(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700311 break;
312
313 case TPM2_NV_DefineSpace:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500314 rc |= marshal_nv_define_space(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700315 break;
316
317 case TPM2_NV_Write:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500318 rc |= marshal_nv_write(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700319 break;
320
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700321 case TPM2_NV_WriteLock:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500322 rc |= marshal_nv_write_lock(ob, tpm_command_body);
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700323 break;
324
Vadim Bendebury627afc22016-06-19 12:13:18 -0700325 case TPM2_SelfTest:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500326 rc |= marshal_selftest(ob, tpm_command_body);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700327 break;
328
Aaron Durbinf56c7782017-01-10 17:44:42 -0600329 case TPM2_Hierarchy_Control:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500330 rc |= marshal_hierarchy_control(ob, tpm_command_body);
Aaron Durbinf56c7782017-01-10 17:44:42 -0600331 break;
332
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700333 case TPM2_Clear:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500334 rc |= marshal_clear(ob);
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700335 break;
336
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700337 case TPM2_PCR_Extend:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500338 rc |= marshal_pcr_extend(ob, tpm_command_body);
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700339 break;
340
Aaron Durbineeb77372017-03-08 11:23:11 -0600341 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500342 rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
Aaron Durbineeb77372017-03-08 11:23:11 -0600343 break;
344
Vadim Bendebury627afc22016-06-19 12:13:18 -0700345 default:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700346 printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
347 __FILE__, __LINE__, command);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500348 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700349 }
350
Aaron Durbinee049fa2017-03-25 00:38:45 -0500351 if (rc != 0)
352 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700353
Aaron Durbinee049fa2017-03-25 00:38:45 -0500354 /* Fix up the command header with known values. */
355 rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag));
356 rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700357
Aaron Durbinee049fa2017-03-25 00:38:45 -0500358 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700359}
360
Aaron Durbinee049fa2017-03-25 00:38:45 -0500361static int unmarshal_get_capability(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700362 struct get_cap_response *gcr)
363{
364 int i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500365 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700366
Aaron Durbinee049fa2017-03-25 00:38:45 -0500367 rc |= ibuf_read_be8(ib, &gcr->more_data);
368 rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700369
Aaron Durbinee049fa2017-03-25 00:38:45 -0500370 if (rc != 0)
371 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700372
373 switch (gcr->cd.capability) {
374 case TPM_CAP_TPM_PROPERTIES:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500375 if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
376 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700377 if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
378 (gcr->cd.data.tpmProperties.tpmProperty)) {
379 printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
380 __FILE__, __func__, __LINE__,
381 gcr->cd.data.tpmProperties.count);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500382 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700383 }
384 for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
385 TPMS_TAGGED_PROPERTY *pp;
386
387 pp = gcr->cd.data.tpmProperties.tpmProperty + i;
Aaron Durbinee049fa2017-03-25 00:38:45 -0500388 rc |= unmarshal_TPM_PT(ib, &pp->property);
389 rc |= ibuf_read_be32(ib, &pp->value);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700390 }
391 break;
392 default:
393 printk(BIOS_ERR,
394 "%s:%d - unable to unmarshal capability response",
395 __func__, __LINE__);
396 printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500397 rc = -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700398 break;
399 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500400
401 return rc;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700402}
403
Aaron Durbinee049fa2017-03-25 00:38:45 -0500404static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
Vadim Bendebury627afc22016-06-19 12:13:18 -0700405 TPM2B_MAX_NV_BUFFER *nv_buffer)
406{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500407 if (ibuf_read_be16(ib, &nv_buffer->t.size))
408 return -1;
409
410 nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
411
412 if (nv_buffer->t.buffer == NULL) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700413 printk(BIOS_ERR, "%s:%d - "
Aaron Durbinee049fa2017-03-25 00:38:45 -0500414 "size mismatch: expected %d, remaining %zd\n",
415 __func__, __LINE__, nv_buffer->t.size,
416 ibuf_remaining(ib));
417 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700418 }
419
Aaron Durbinee049fa2017-03-25 00:38:45 -0500420 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700421}
422
Aaron Durbinee049fa2017-03-25 00:38:45 -0500423static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700424{
425 /* Total size of the parameter field. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500426 if (ibuf_read_be32(ib, &nvr->params_size))
427 return -1;
428
429 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
430 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700431
432 if (nvr->params_size !=
433 (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
434 printk(BIOS_ERR,
435 "%s:%d - parameter/buffer %d/%d size mismatch",
436 __func__, __LINE__, nvr->params_size,
437 nvr->buffer.t.size);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500438 return -1;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700439 }
440
Vadim Bendebury627afc22016-06-19 12:13:18 -0700441 /*
442 * Let's ignore the authorisation section. It should be 5 bytes total,
443 * just confirm that this is the case and report any discrepancy.
444 */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500445 if (ibuf_remaining(ib) != 5)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700446 printk(BIOS_ERR,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500447 "%s:%d - unexpected authorisation seciton size %zd\n",
448 __func__, __LINE__, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700449
Aaron Durbinee049fa2017-03-25 00:38:45 -0500450 ibuf_oob_drain(ib, ibuf_remaining(ib));
451
452 return 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700453}
454
Aaron Durbinee049fa2017-03-25 00:38:45 -0500455static int unmarshal_vendor_command(struct ibuf *ib,
Vadim Bendebury021ec282017-03-22 16:01:53 -0700456 struct vendor_command_response *vcr)
457{
Aaron Durbinee049fa2017-03-25 00:38:45 -0500458 if (ibuf_read_be16(ib, &vcr->vc_subcommand))
459 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700460
461 switch (vcr->vc_subcommand) {
462 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
463 break;
464 case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500465 return ibuf_read_be8(ib, &vcr->num_restored_headers);
Vadim Bendebury021ec282017-03-22 16:01:53 -0700466 break;
467 default:
468 printk(BIOS_ERR,
469 "%s:%d - unsupported vendor command %#04x!\n",
470 __func__, __LINE__, vcr->vc_subcommand);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500471 return -1;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700472 }
Aaron Durbinee049fa2017-03-25 00:38:45 -0500473
474 return 0;
Vadim Bendebury021ec282017-03-22 16:01:53 -0700475}
476
Aaron Durbinee049fa2017-03-25 00:38:45 -0500477struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700478{
Duncan Laurie4a560762016-09-01 16:09:43 -0700479 static struct tpm2_response tpm2_static_resp CAR_GLOBAL;
480 struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp);
Aaron Durbinee049fa2017-03-25 00:38:45 -0500481 int rc = 0;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700482
Aaron Durbinee049fa2017-03-25 00:38:45 -0500483 rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag);
484 rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size);
485 rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code);
486
487 if (rc != 0)
Vadim Bendebury627afc22016-06-19 12:13:18 -0700488 return NULL;
489
Aaron Durbinee049fa2017-03-25 00:38:45 -0500490 if (ibuf_remaining(ib) == 0) {
491 if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib))
Vadim Bendebury627afc22016-06-19 12:13:18 -0700492 printk(BIOS_ERR,
493 "%s: size mismatch in response to command %#x\n",
494 __func__, command);
Duncan Laurie4a560762016-09-01 16:09:43 -0700495 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700496 }
497
498 switch (command) {
499 case TPM2_Startup:
500 break;
501
502 case TPM2_GetCapability:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500503 rc |= unmarshal_get_capability(ib, &tpm2_resp->gc);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700504 break;
505
506 case TPM2_NV_Read:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500507 rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700508 break;
509
Aaron Durbinf56c7782017-01-10 17:44:42 -0600510 case TPM2_Hierarchy_Control:
Vadim Bendebury6acb9a62016-06-30 20:50:49 -0700511 case TPM2_Clear:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700512 case TPM2_NV_DefineSpace:
513 case TPM2_NV_Write:
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700514 case TPM2_NV_WriteLock:
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700515 case TPM2_PCR_Extend:
Vadim Bendebury627afc22016-06-19 12:13:18 -0700516 /* Session data included in response can be safely ignored. */
Aaron Durbinee049fa2017-03-25 00:38:45 -0500517 ibuf_oob_drain(ib, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700518 break;
519
Aaron Durbineeb77372017-03-08 11:23:11 -0600520 case TPM2_CR50_VENDOR_COMMAND:
Aaron Durbinee049fa2017-03-25 00:38:45 -0500521 rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr);
Aaron Durbineeb77372017-03-08 11:23:11 -0600522 break;
523
Vadim Bendebury627afc22016-06-19 12:13:18 -0700524 default:
525 {
Aaron Durbinee049fa2017-03-25 00:38:45 -0500526 size_t i;
527 size_t sz_left;
528 const uint8_t *data;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700529
530 printk(BIOS_INFO, "%s:%d:"
531 "Request to unmarshal unexpected command %#x,"
532 " code %#x",
533 __func__, __LINE__, command,
Duncan Laurie4a560762016-09-01 16:09:43 -0700534 tpm2_resp->hdr.tpm_code);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700535
Aaron Durbinee049fa2017-03-25 00:38:45 -0500536 sz_left = ibuf_remaining(ib);
537 data = ibuf_oob_drain(ib, sz_left);
538
539 for (i = 0; i < sz_left; i++) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700540 if (!(i % 16))
541 printk(BIOS_INFO, "\n");
Aaron Durbinee049fa2017-03-25 00:38:45 -0500542 printk(BIOS_INFO, "%2.2x ", data[i]);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700543 }
544 }
545 printk(BIOS_INFO, "\n");
546 return NULL;
547 }
548
Aaron Durbinee049fa2017-03-25 00:38:45 -0500549 if (ibuf_remaining(ib)) {
Vadim Bendebury627afc22016-06-19 12:13:18 -0700550 printk(BIOS_INFO,
551 "%s:%d got %d bytes back in response to %#x,"
Aaron Durbinee049fa2017-03-25 00:38:45 -0500552 " failed to parse (%zd)\n",
Duncan Laurie4a560762016-09-01 16:09:43 -0700553 __func__, __LINE__, tpm2_resp->hdr.tpm_size,
Aaron Durbinee049fa2017-03-25 00:38:45 -0500554 command, ibuf_remaining(ib));
Vadim Bendebury627afc22016-06-19 12:13:18 -0700555 return NULL;
556 }
Richard Spiegel248c60a2018-08-07 09:24:14 -0700557 if (rc)
558 printk(BIOS_WARNING, "Warning: %s had one or more failures.\n",
559 __func__);
Vadim Bendebury627afc22016-06-19 12:13:18 -0700560
561 /* The entire message have been parsed. */
Duncan Laurie4a560762016-09-01 16:09:43 -0700562 return tpm2_resp;
Vadim Bendebury627afc22016-06-19 12:13:18 -0700563}