xref: /aosp_15_r20/external/coreboot/src/security/tpm/tss/tcg-2.0/tss_marshaling.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 
3 #include <commonlib/iobuf.h>
4 #include <console/console.h>
5 #include <string.h>
6 
7 #include "tss_marshaling.h"
8 #include <security/tpm/tss/vendor/cr50/cr50.h>
9 #include <security/tpm/tss.h>
10 
11 static uint16_t tpm_tag;  /* Depends on the command type. */
12 
13 #define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b)
14 #define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b)
15 #define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b)
16 #define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b)
17 
18 #define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b)
19 #define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b)
20 
marshal_startup(struct obuf * ob,const struct tpm2_startup * cmd_body)21 static int marshal_startup(struct obuf *ob, const struct tpm2_startup *cmd_body)
22 {
23 	return obuf_write_be16(ob, cmd_body->startup_type);
24 }
25 
marshal_shutdown(struct obuf * ob,const struct tpm2_shutdown * cmd_body)26 static int marshal_shutdown(struct obuf *ob, const struct tpm2_shutdown *cmd_body)
27 {
28 	return obuf_write_be16(ob, cmd_body->shutdown_type);
29 }
30 
marshal_get_capability(struct obuf * ob,const struct tpm2_get_capability * cmd_body)31 static int marshal_get_capability(struct obuf *ob,
32 				  const struct tpm2_get_capability *cmd_body)
33 {
34 	int rc = 0;
35 
36 	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);
39 
40 	return rc;
41 }
42 
marshal_TPM2B(struct obuf * ob,const TPM2B * data)43 static int marshal_TPM2B(struct obuf *ob, const TPM2B *data)
44 {
45 	int rc = 0;
46 
47 	rc |= obuf_write_be16(ob, data->size);
48 	rc |= obuf_write(ob, data->buffer, data->size);
49 
50 	return rc;
51 }
52 
marshal_TPMA_NV(struct obuf * ob,const TPMA_NV * nv)53 static int marshal_TPMA_NV(struct obuf *ob, const TPMA_NV *nv)
54 {
55 	uint32_t v;
56 
57 	memcpy(&v, nv, sizeof(v));
58 	return obuf_write_be32(ob, v);
59 }
60 
marshal_TPMS_NV_PUBLIC(struct obuf * ob,const TPMS_NV_PUBLIC * nvpub)61 static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, const TPMS_NV_PUBLIC *nvpub)
62 {
63 	int rc = 0;
64 
65 	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);
70 
71 	return rc;
72 }
73 
marshal_TPMT_HA(struct obuf * ob,const TPMT_HA * tpmtha)74 static int marshal_TPMT_HA(struct obuf *ob, const TPMT_HA *tpmtha)
75 {
76 	int rc = 0;
77 
78 	rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg);
79 	switch (tpmtha->hashAlg) {
80 	case TPM_ALG_SHA1:
81 		rc |= obuf_write(ob, tpmtha->digest.sha1,
82 			 tlcl2_get_hash_size_from_algo(tpmtha->hashAlg));
83 		break;
84 	case TPM_ALG_SHA256:
85 		rc |= obuf_write(ob, tpmtha->digest.sha256,
86 			 tlcl2_get_hash_size_from_algo(tpmtha->hashAlg));
87 		break;
88 	case TPM_ALG_SM3_256:
89 		rc |= obuf_write(ob, tpmtha->digest.sm3_256,
90 			 tlcl2_get_hash_size_from_algo(tpmtha->hashAlg));
91 		break;
92 	case TPM_ALG_SHA384:
93 		rc |= obuf_write(ob, tpmtha->digest.sha384,
94 			 tlcl2_get_hash_size_from_algo(tpmtha->hashAlg));
95 		break;
96 	case TPM_ALG_SHA512:
97 		rc |= obuf_write(ob, tpmtha->digest.sha512,
98 			 tlcl2_get_hash_size_from_algo(tpmtha->hashAlg));
99 		break;
100 	default:
101 		rc = -1;
102 	}
103 	return rc;
104 }
105 
marshal_TPML_DIGEST_VALUES(struct obuf * ob,const TPML_DIGEST_VALUES * dvalues)106 static int marshal_TPML_DIGEST_VALUES(struct obuf *ob,
107 				      const TPML_DIGEST_VALUES *dvalues)
108 {
109 	int i;
110 	int rc = 0;
111 
112 	rc |= obuf_write_be32(ob, dvalues->count);
113 	for (i = 0; i < dvalues->count; i++)
114 		rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]);
115 
116 	return rc;
117 }
118 
marshal_session_header(struct obuf * ob,const struct tpm2_session_header * session_header)119 static int marshal_session_header(struct obuf *ob,
120 			const struct tpm2_session_header *session_header)
121 {
122 	int rc = 0;
123 	struct obuf ob_sz;
124 	size_t prev_written;
125 
126 	/* Snapshot current location to place size of header. */
127 	if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0)
128 		return -1;
129 
130 	/* Write a size placeholder. */
131 	rc |= obuf_write_be32(ob, 0);
132 
133 	/* Keep track of session header data size by tracking num written. */
134 	prev_written = obuf_nr_written(ob);
135 
136 	rc |= obuf_write_be32(ob, session_header->session_handle);
137 	rc |= obuf_write_be16(ob, session_header->nonce_size);
138 	rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size);
139 	rc |= obuf_write_be8(ob, session_header->session_attrs);
140 	rc |= obuf_write_be16(ob, session_header->auth_size);
141 	rc |= obuf_write(ob, session_header->auth, session_header->auth_size);
142 
143 	/* Fill back in proper size of session header. */
144 	rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written);
145 
146 	return rc;
147 }
148 
149 /*
150  * Common session header can include one or two handles and an empty
151  * session_header structure.
152  */
marshal_common_session_header(struct obuf * ob,const uint32_t * handles,size_t handle_count)153 static int marshal_common_session_header(struct obuf *ob,
154 					 const uint32_t *handles,
155 					 size_t handle_count)
156 {
157 	size_t i;
158 	struct tpm2_session_header session_header;
159 	int rc = 0;
160 
161 	tpm_tag = TPM_ST_SESSIONS;
162 
163 	for (i = 0; i < handle_count; i++)
164 		rc |= marshal_TPM_HANDLE(ob, handles[i]);
165 
166 	memset(&session_header, 0, sizeof(session_header));
167 	session_header.session_handle = TPM_RS_PW;
168 	rc |= marshal_session_header(ob, &session_header);
169 
170 	return rc;
171 }
172 
marshal_nv_define_space(struct obuf * ob,const struct tpm2_nv_define_space_cmd * nvd_in)173 static int marshal_nv_define_space(struct obuf *ob,
174 				   const struct tpm2_nv_define_space_cmd *nvd_in)
175 {
176 	const uint32_t handle[] = { TPM_RH_PLATFORM };
177 	struct obuf ob_sz;
178 	size_t prev_written;
179 	int rc = 0;
180 
181 	rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
182 	rc |= marshal_TPM2B(ob, &nvd_in->auth.b);
183 
184 	/* Snapshot current location to place size field. */
185 	if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0)
186 		return -1;
187 
188 	/* Put placeholder for size */
189 	rc |= obuf_write_be16(ob, 0);
190 
191 	/* Keep track of nv define space data size by tracking num written. */
192 	prev_written = obuf_nr_written(ob);
193 
194 	rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo);
195 	rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written);
196 
197 	return rc;
198 }
199 
marshal_nv_setbits(struct obuf * ob,const struct tpm2_nv_setbits_cmd * command_body)200 static int marshal_nv_setbits(struct obuf *ob,
201 			      const struct tpm2_nv_setbits_cmd *command_body)
202 {
203 	int rc = 0;
204 	const uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
205 
206 	rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
207 	rc |= obuf_write_be64(ob, command_body->bits);
208 
209 	return rc;
210 }
211 
marshal_nv_write(struct obuf * ob,const struct tpm2_nv_write_cmd * command_body)212 static int marshal_nv_write(struct obuf *ob,
213 			    const struct tpm2_nv_write_cmd *command_body)
214 {
215 	int rc = 0;
216 	const uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
217 
218 	rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
219 	rc |= marshal_TPM2B(ob, &command_body->data.b);
220 	rc |= obuf_write_be16(ob, command_body->offset);
221 
222 	return rc;
223 }
224 
marshal_nv_write_lock(struct obuf * ob,const struct tpm2_nv_write_lock_cmd * command_body)225 static int marshal_nv_write_lock(struct obuf *ob,
226 			const struct tpm2_nv_write_lock_cmd *command_body)
227 {
228 	const uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
229 
230 	return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
231 }
232 
marshal_pcr_extend(struct obuf * ob,const struct tpm2_pcr_extend_cmd * command_body)233 static int marshal_pcr_extend(struct obuf *ob,
234 			      const struct tpm2_pcr_extend_cmd *command_body)
235 {
236 	int rc = 0;
237 	const uint32_t handles[] = { command_body->pcrHandle };
238 
239 	rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
240 	rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests);
241 
242 	return rc;
243 }
244 
marshal_nv_read(struct obuf * ob,const struct tpm2_nv_read_cmd * command_body)245 static int marshal_nv_read(struct obuf *ob,
246 			   const struct tpm2_nv_read_cmd *command_body)
247 {
248 	int rc = 0;
249 	const uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex };
250 
251 	rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles));
252 	rc |= obuf_write_be16(ob, command_body->size);
253 	rc |= obuf_write_be16(ob, command_body->offset);
254 
255 	return rc;
256 }
257 
258 /* TPM2_Clear command does not require parameters. */
marshal_clear(struct obuf * ob)259 static int marshal_clear(struct obuf *ob)
260 {
261 	const uint32_t handle[] = { TPM_RH_PLATFORM };
262 
263 	return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle));
264 }
265 
marshal_selftest(struct obuf * ob,const struct tpm2_self_test * command_body)266 static int marshal_selftest(struct obuf *ob,
267 			    const struct tpm2_self_test *command_body)
268 {
269 	return obuf_write_be8(ob, command_body->yes_no);
270 }
271 
marshal_hierarchy_control(struct obuf * ob,const struct tpm2_hierarchy_control_cmd * command_body)272 static int marshal_hierarchy_control(struct obuf *ob,
273 			const struct tpm2_hierarchy_control_cmd *command_body)
274 {
275 	int rc = 0;
276 	struct tpm2_session_header session_header;
277 
278 	tpm_tag = TPM_ST_SESSIONS;
279 
280 	rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
281 	memset(&session_header, 0, sizeof(session_header));
282 	session_header.session_handle = TPM_RS_PW;
283 	rc |= marshal_session_header(ob, &session_header);
284 
285 	rc |= marshal_TPM_HANDLE(ob, command_body->enable);
286 	rc |= obuf_write_be8(ob, command_body->state);
287 
288 	return rc;
289 }
290 
marshal_clear_control(struct obuf * ob,const struct tpm2_clear_control_cmd * command_body)291 static int marshal_clear_control(struct obuf *ob,
292 			const struct tpm2_clear_control_cmd *command_body)
293 {
294 	int rc = 0;
295 	struct tpm2_session_header session_header;
296 
297 	tpm_tag = TPM_ST_SESSIONS;
298 
299 	rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM);
300 	memset(&session_header, 0, sizeof(session_header));
301 	session_header.session_handle = TPM_RS_PW;
302 	rc |= marshal_session_header(ob, &session_header);
303 
304 	rc |= obuf_write_be8(ob, command_body->disable);
305 
306 	return rc;
307 }
308 
marshal_cr50_vendor_command(struct obuf * ob,const void * command_body)309 static int marshal_cr50_vendor_command(struct obuf *ob, const void *command_body)
310 {
311 	int rc = 0;
312 	const uint16_t *sub_command = command_body;
313 
314 	switch (*sub_command) {
315 	case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
316 		/* The 16-bit timeout parameter is optional for the
317 		 * IMMEDIATE_RESET command.  However in coreboot, the timeout
318 		 * parameter must be specified.
319 		 */
320 		rc |= obuf_write_be16(ob, sub_command[0]);
321 		rc |= obuf_write_be16(ob, sub_command[1]);
322 		break;
323 	case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
324 		rc |= obuf_write_be16(ob, *sub_command);
325 		break;
326 	case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
327 		rc |= obuf_write_be16(ob, sub_command[0]);
328 		rc |= obuf_write_be16(ob, sub_command[1]);
329 		break;
330 	case TPM2_CR50_SUB_CMD_GET_REC_BTN:
331 		rc |= obuf_write_be16(ob, *sub_command);
332 		break;
333 	case TPM2_CR50_SUB_CMD_TPM_MODE:
334 		/* The Cr50 TPM_MODE command supports an optional parameter.
335 		 * When the parameter is present the Cr50 will attempt to change
336 		 * the TPM state (enable or disable) and returns the new state
337 		 * in the response.  When the parameter is absent, the Cr50
338 		 * returns the current TPM state.
339 		 *
340 		 * coreboot currently only uses the TPM get capability and does
341 		 * not set a new TPM state with the Cr50.
342 		 */
343 		rc |= obuf_write_be16(ob, *sub_command);
344 		break;
345 	case TPM2_CR50_SUB_CMD_GET_BOOT_MODE:
346 		rc |= obuf_write_be16(ob, *sub_command);
347 		break;
348 	case TPM2_CR50_SUB_CMD_RESET_EC:
349 		rc |= obuf_write_be16(ob, *sub_command);
350 		break;
351 	case TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG:
352 		rc |= obuf_write_be16(ob, *sub_command);
353 		break;
354 	default:
355 		/* Unsupported subcommand. */
356 		printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n",
357 			*sub_command);
358 		rc = -1;
359 		break;
360 	}
361 	return rc;
362 }
363 
tpm_marshal_command(TPM_CC command,const void * tpm_command_body,struct obuf * ob)364 int tpm_marshal_command(TPM_CC command, const void *tpm_command_body, struct obuf *ob)
365 {
366 	struct obuf ob_hdr;
367 	const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t);
368 	int rc = 0;
369 
370 	tpm_tag = TPM_ST_NO_SESSIONS;
371 
372 	if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0)
373 		return -1;
374 
375 	/* Write TPM command header with placeholder field values. */
376 	rc |= obuf_write_be16(ob, 0);
377 	rc |= obuf_write_be32(ob, 0);
378 	rc |= obuf_write_be32(ob, command);
379 
380 	if (rc != 0)
381 		return rc;
382 
383 	switch (command) {
384 	case TPM2_Startup:
385 		rc |= marshal_startup(ob, tpm_command_body);
386 		break;
387 
388 	case TPM2_Shutdown:
389 		rc |= marshal_shutdown(ob, tpm_command_body);
390 		break;
391 
392 	case TPM2_GetCapability:
393 		rc |= marshal_get_capability(ob, tpm_command_body);
394 		break;
395 
396 	case TPM2_NV_Read:
397 		rc |= marshal_nv_read(ob, tpm_command_body);
398 		break;
399 
400 	case TPM2_NV_DefineSpace:
401 		rc |= marshal_nv_define_space(ob, tpm_command_body);
402 		break;
403 
404 	case TPM2_NV_SetBits:
405 		rc |= marshal_nv_setbits(ob, tpm_command_body);
406 		break;
407 
408 	case TPM2_NV_Write:
409 		rc |= marshal_nv_write(ob, tpm_command_body);
410 		break;
411 
412 	case TPM2_NV_WriteLock:
413 		rc |= marshal_nv_write_lock(ob, tpm_command_body);
414 		break;
415 
416 	case TPM2_SelfTest:
417 		rc |= marshal_selftest(ob, tpm_command_body);
418 		break;
419 
420 	case TPM2_Hierarchy_Control:
421 		rc |= marshal_hierarchy_control(ob, tpm_command_body);
422 		break;
423 
424 	case TPM2_ClearControl:
425 		rc |= marshal_clear_control(ob, tpm_command_body);
426 		break;
427 
428 	case TPM2_Clear:
429 		rc |= marshal_clear(ob);
430 		break;
431 
432 	case TPM2_PCR_Extend:
433 		rc |= marshal_pcr_extend(ob, tpm_command_body);
434 		break;
435 
436 	case TPM2_CR50_VENDOR_COMMAND:
437 		rc |= marshal_cr50_vendor_command(ob, tpm_command_body);
438 		break;
439 
440 	default:
441 		printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n",
442 		       __FILE__, __LINE__, command);
443 		rc = -1;
444 	}
445 
446 	if (rc != 0)
447 		return rc;
448 
449 	/* Fix up the command header with known values. */
450 	rc |= obuf_write_be16(&ob_hdr, tpm_tag);
451 	rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob));
452 
453 	return rc;
454 }
455 
unmarshal_get_capability(struct ibuf * ib,struct get_cap_response * gcr)456 static int unmarshal_get_capability(struct ibuf *ib,
457 				    struct get_cap_response *gcr)
458 {
459 	int i;
460 	int rc = 0;
461 
462 	rc |= ibuf_read_be8(ib, &gcr->more_data);
463 	rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability);
464 
465 	if (rc != 0)
466 		return rc;
467 
468 	switch (gcr->cd.capability) {
469 	case TPM_CAP_TPM_PROPERTIES:
470 		if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count))
471 			return -1;
472 		if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE
473 		    (gcr->cd.data.tpmProperties.tpmProperty)) {
474 			printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
475 			       __FILE__, __func__, __LINE__,
476 			       gcr->cd.data.tpmProperties.count);
477 			return -1;
478 		}
479 		for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) {
480 			TPMS_TAGGED_PROPERTY *pp;
481 
482 			pp = gcr->cd.data.tpmProperties.tpmProperty + i;
483 			rc |= unmarshal_TPM_PT(ib, &pp->property);
484 			rc |= ibuf_read_be32(ib, &pp->value);
485 		}
486 		break;
487 	case TPM_CAP_PCRS:
488 		if (ibuf_read_be32(ib, &gcr->cd.data.assignedPCR.count))
489 			return -1;
490 		if (gcr->cd.data.assignedPCR.count >
491 		    ARRAY_SIZE(gcr->cd.data.assignedPCR.pcrSelections)) {
492 			printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n",
493 			       __FILE__, __func__, __LINE__,
494 			      gcr->cd.data.assignedPCR.count);
495 			return -1;
496 		}
497 		for (i = 0; i < gcr->cd.data.assignedPCR.count; i++) {
498 			TPMS_PCR_SELECTION *pp =
499 				&gcr->cd.data.assignedPCR.pcrSelections[i];
500 			rc |= ibuf_read(ib, pp, sizeof(TPMS_PCR_SELECTION));
501 		}
502 		break;
503 	default:
504 		printk(BIOS_ERR,
505 		       "%s:%d - unable to unmarshal capability response",
506 		       __func__, __LINE__);
507 		printk(BIOS_ERR, " for %d\n", gcr->cd.capability);
508 		rc = -1;
509 		break;
510 	}
511 
512 	return rc;
513 }
514 
unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf * ib,TPM2B_MAX_NV_BUFFER * nv_buffer)515 static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib,
516 					 TPM2B_MAX_NV_BUFFER *nv_buffer)
517 {
518 	if (ibuf_read_be16(ib, &nv_buffer->t.size))
519 		return -1;
520 
521 	nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size);
522 
523 	if (!nv_buffer->t.buffer) {
524 		printk(BIOS_ERR, "%s:%d - "
525 		       "size mismatch: expected %d, remaining %zd\n",
526 		       __func__, __LINE__, nv_buffer->t.size,
527 			ibuf_remaining(ib));
528 		return -1;
529 	}
530 
531 	return 0;
532 }
533 
unmarshal_nv_read(struct ibuf * ib,struct nv_read_response * nvr)534 static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr)
535 {
536 	/* Total size of the parameter field. */
537 	if (ibuf_read_be32(ib, &nvr->params_size))
538 		return -1;
539 
540 	if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer))
541 		return -1;
542 
543 	if (nvr->params_size !=
544 	    (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) {
545 		printk(BIOS_ERR,
546 		       "%s:%d - parameter/buffer %d/%d size mismatch",
547 		       __func__, __LINE__, nvr->params_size,
548 		       nvr->buffer.t.size);
549 		return -1;
550 	}
551 
552 	/*
553 	 * Let's ignore the authorization section. It should be 5 bytes total,
554 	 * just confirm that this is the case and report any discrepancy.
555 	 */
556 	if (ibuf_remaining(ib) != 5)
557 		printk(BIOS_ERR,
558 		       "%s:%d - unexpected authorization section size %zd\n",
559 		       __func__, __LINE__, ibuf_remaining(ib));
560 
561 	ibuf_oob_drain(ib, ibuf_remaining(ib));
562 
563 	return 0;
564 }
565 
unmarshal_vendor_command(struct ibuf * ib,struct vendor_command_response * vcr)566 static int unmarshal_vendor_command(struct ibuf *ib,
567 				    struct vendor_command_response *vcr)
568 {
569 	if (ibuf_read_be16(ib, &vcr->vc_subcommand))
570 		return -1;
571 
572 	switch (vcr->vc_subcommand) {
573 	case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET:
574 		break;
575 	case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS:
576 		break;
577 	case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON:
578 		return ibuf_read_be8(ib, &vcr->num_restored_headers);
579 	case TPM2_CR50_SUB_CMD_GET_REC_BTN:
580 		return ibuf_read_be8(ib, &vcr->recovery_button_state);
581 	case TPM2_CR50_SUB_CMD_TPM_MODE:
582 		return ibuf_read_be8(ib, &vcr->tpm_mode);
583 	case TPM2_CR50_SUB_CMD_GET_BOOT_MODE:
584 		return ibuf_read_be8(ib, &vcr->boot_mode);
585 	case TPM2_CR50_SUB_CMD_RESET_EC:
586 		break;
587 	case TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG:
588 		return ibuf_read_be64(ib, &vcr->factory_config);
589 	default:
590 		printk(BIOS_ERR,
591 		       "%s:%d - unsupported vendor command %#04x!\n",
592 		       __func__, __LINE__, vcr->vc_subcommand);
593 		return -1;
594 	}
595 
596 	return 0;
597 }
598 
tpm_unmarshal_response(TPM_CC command,struct ibuf * ib)599 struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib)
600 {
601 	static struct tpm2_response tpm2_static_resp;
602 	int rc = 0;
603 
604 	rc |= ibuf_read_be16(ib, &tpm2_static_resp.hdr.tpm_tag);
605 	rc |= ibuf_read_be32(ib, &tpm2_static_resp.hdr.tpm_size);
606 	rc |= unmarshal_TPM_CC(ib, &tpm2_static_resp.hdr.tpm_code);
607 
608 	if (rc != 0)
609 		return NULL;
610 
611 	if (ibuf_capacity(ib) != tpm2_static_resp.hdr.tpm_size) {
612 		printk(BIOS_ERR,
613 		       "%s: size mismatch in response to command %#x\n",
614 		       __func__, command);
615 		return NULL;
616 	}
617 
618 	/* On errors, we're not sure what the TPM is returning. None of the
619 	   commands we use actually expect useful data payloads for errors, so
620 	   just ignore any data after the header. */
621 	if (tpm2_static_resp.hdr.tpm_code != TPM2_RC_SUCCESS)
622 		return &tpm2_static_resp;
623 
624 	switch (command) {
625 	case TPM2_Startup:
626 	case TPM2_Shutdown:
627 	case TPM2_SelfTest:
628 		break;
629 
630 	case TPM2_GetCapability:
631 		rc |= unmarshal_get_capability(ib, &tpm2_static_resp.gc);
632 		break;
633 
634 	case TPM2_NV_Read:
635 		rc |= unmarshal_nv_read(ib, &tpm2_static_resp.nvr);
636 		break;
637 
638 	case TPM2_Hierarchy_Control:
639 	case TPM2_Clear:
640 	case TPM2_ClearControl:
641 	case TPM2_NV_DefineSpace:
642 	case TPM2_NV_SetBits:
643 	case TPM2_NV_Write:
644 	case TPM2_NV_WriteLock:
645 	case TPM2_PCR_Extend:
646 		/* Session data included in response can be safely ignored. */
647 		ibuf_oob_drain(ib, ibuf_remaining(ib));
648 		break;
649 
650 	case TPM2_CR50_VENDOR_COMMAND:
651 		rc |= unmarshal_vendor_command(ib, &tpm2_static_resp.vcr);
652 		break;
653 
654 	default:
655 		{
656 			size_t i;
657 			size_t sz_left;
658 			const uint8_t *data;
659 
660 			printk(BIOS_INFO, "%s:%d:"
661 			       "Request to unmarshal unexpected command %#x,"
662 			       " code %#x",
663 			       __func__, __LINE__, command,
664 			       tpm2_static_resp.hdr.tpm_code);
665 
666 			sz_left = ibuf_remaining(ib);
667 			data = ibuf_oob_drain(ib, sz_left);
668 
669 			for (i = 0; i < sz_left; i++) {
670 				if (!(i % 16))
671 					printk(BIOS_INFO, "\n");
672 				printk(BIOS_INFO, "%2.2x ", data[i]);
673 			}
674 		}
675 		printk(BIOS_INFO, "\n");
676 		return NULL;
677 	}
678 
679 	if (ibuf_remaining(ib)) {
680 		printk(BIOS_INFO,
681 		       "%s:%d got %d bytes back in response to %#x,"
682 		       " failed to parse (%zd)\n",
683 		       __func__, __LINE__, tpm2_static_resp.hdr.tpm_size,
684 		       command, ibuf_remaining(ib));
685 		return NULL;
686 	}
687 	if (rc)
688 		printk(BIOS_WARNING, "%s had one or more failures.\n",
689 					__func__);
690 
691 	/* The entire message have been parsed. */
692 	return &tpm2_static_resp;
693 }
694