1 /* SPDX-License-Identifier: BSD-3-Clause */
3 #include <commonlib/iobuf.h>
4 #include <console/console.h>
7 #include "tss_marshaling.h"
8 #include <security/tpm/tss/vendor/cr50/cr50.h>
9 #include <security/tpm/tss.h>
11 static uint16_t tpm_tag
; /* Depends on the command type. */
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)
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)
21 static int marshal_startup(struct obuf
*ob
, const struct tpm2_startup
*cmd_body
)
23 return obuf_write_be16(ob
, cmd_body
->startup_type
);
26 static int marshal_shutdown(struct obuf
*ob
, const struct tpm2_shutdown
*cmd_body
)
28 return obuf_write_be16(ob
, cmd_body
->shutdown_type
);
31 static int marshal_get_capability(struct obuf
*ob
,
32 const struct tpm2_get_capability
*cmd_body
)
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
);
43 static int marshal_TPM2B(struct obuf
*ob
, const TPM2B
*data
)
47 rc
|= obuf_write_be16(ob
, data
->size
);
48 rc
|= obuf_write(ob
, data
->buffer
, data
->size
);
53 static int marshal_TPMA_NV(struct obuf
*ob
, const TPMA_NV
*nv
)
57 memcpy(&v
, nv
, sizeof(v
));
58 return obuf_write_be32(ob
, v
);
61 static int marshal_TPMS_NV_PUBLIC(struct obuf
*ob
, const TPMS_NV_PUBLIC
*nvpub
)
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
);
74 static int marshal_TPMT_HA(struct obuf
*ob
, const TPMT_HA
*tpmtha
)
78 rc
|= marshal_TPMI_ALG_HASH(ob
, tpmtha
->hashAlg
);
79 switch (tpmtha
->hashAlg
) {
81 rc
|= obuf_write(ob
, tpmtha
->digest
.sha1
,
82 tlcl2_get_hash_size_from_algo(tpmtha
->hashAlg
));
85 rc
|= obuf_write(ob
, tpmtha
->digest
.sha256
,
86 tlcl2_get_hash_size_from_algo(tpmtha
->hashAlg
));
89 rc
|= obuf_write(ob
, tpmtha
->digest
.sm3_256
,
90 tlcl2_get_hash_size_from_algo(tpmtha
->hashAlg
));
93 rc
|= obuf_write(ob
, tpmtha
->digest
.sha384
,
94 tlcl2_get_hash_size_from_algo(tpmtha
->hashAlg
));
97 rc
|= obuf_write(ob
, tpmtha
->digest
.sha512
,
98 tlcl2_get_hash_size_from_algo(tpmtha
->hashAlg
));
106 static int marshal_TPML_DIGEST_VALUES(struct obuf
*ob
,
107 const TPML_DIGEST_VALUES
*dvalues
)
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
]);
119 static int marshal_session_header(struct obuf
*ob
,
120 const struct tpm2_session_header
*session_header
)
126 /* Snapshot current location to place size of header. */
127 if (obuf_splice_current(ob
, &ob_sz
, sizeof(uint32_t)) < 0)
130 /* Write a size placeholder. */
131 rc
|= obuf_write_be32(ob
, 0);
133 /* Keep track of session header data size by tracking num written. */
134 prev_written
= obuf_nr_written(ob
);
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
);
143 /* Fill back in proper size of session header. */
144 rc
|= obuf_write_be32(&ob_sz
, obuf_nr_written(ob
) - prev_written
);
150 * Common session header can include one or two handles and an empty
151 * session_header structure.
153 static int marshal_common_session_header(struct obuf
*ob
,
154 const uint32_t *handles
,
158 struct tpm2_session_header session_header
;
161 tpm_tag
= TPM_ST_SESSIONS
;
163 for (i
= 0; i
< handle_count
; i
++)
164 rc
|= marshal_TPM_HANDLE(ob
, handles
[i
]);
166 memset(&session_header
, 0, sizeof(session_header
));
167 session_header
.session_handle
= TPM_RS_PW
;
168 rc
|= marshal_session_header(ob
, &session_header
);
173 static int marshal_nv_define_space(struct obuf
*ob
,
174 const struct tpm2_nv_define_space_cmd
*nvd_in
)
176 const uint32_t handle
[] = { TPM_RH_PLATFORM
};
181 rc
|= marshal_common_session_header(ob
, handle
, ARRAY_SIZE(handle
));
182 rc
|= marshal_TPM2B(ob
, &nvd_in
->auth
.b
);
184 /* Snapshot current location to place size field. */
185 if (obuf_splice_current(ob
, &ob_sz
, sizeof(uint16_t)) < 0)
188 /* Put placeholder for size */
189 rc
|= obuf_write_be16(ob
, 0);
191 /* Keep track of nv define space data size by tracking num written. */
192 prev_written
= obuf_nr_written(ob
);
194 rc
|= marshal_TPMS_NV_PUBLIC(ob
, &nvd_in
->publicInfo
);
195 rc
|= obuf_write_be16(&ob_sz
, obuf_nr_written(ob
) - prev_written
);
200 static int marshal_nv_setbits(struct obuf
*ob
,
201 const struct tpm2_nv_setbits_cmd
*command_body
)
204 const uint32_t handles
[] = { TPM_RH_PLATFORM
, command_body
->nvIndex
};
206 rc
|= marshal_common_session_header(ob
, handles
, ARRAY_SIZE(handles
));
207 rc
|= obuf_write_be64(ob
, command_body
->bits
);
212 static int marshal_nv_write(struct obuf
*ob
,
213 const struct tpm2_nv_write_cmd
*command_body
)
216 const uint32_t handles
[] = { TPM_RH_PLATFORM
, command_body
->nvIndex
};
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
);
225 static int marshal_nv_write_lock(struct obuf
*ob
,
226 const struct tpm2_nv_write_lock_cmd
*command_body
)
228 const uint32_t handles
[] = { TPM_RH_PLATFORM
, command_body
->nvIndex
};
230 return marshal_common_session_header(ob
, handles
, ARRAY_SIZE(handles
));
233 static int marshal_pcr_extend(struct obuf
*ob
,
234 const struct tpm2_pcr_extend_cmd
*command_body
)
237 const uint32_t handles
[] = { command_body
->pcrHandle
};
239 rc
|= marshal_common_session_header(ob
, handles
, ARRAY_SIZE(handles
));
240 rc
|= marshal_TPML_DIGEST_VALUES(ob
, &command_body
->digests
);
245 static int marshal_nv_read(struct obuf
*ob
,
246 const struct tpm2_nv_read_cmd
*command_body
)
249 const uint32_t handles
[] = { TPM_RH_PLATFORM
, command_body
->nvIndex
};
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
);
258 /* TPM2_Clear command does not require parameters. */
259 static int marshal_clear(struct obuf
*ob
)
261 const uint32_t handle
[] = { TPM_RH_PLATFORM
};
263 return marshal_common_session_header(ob
, handle
, ARRAY_SIZE(handle
));
266 static int marshal_selftest(struct obuf
*ob
,
267 const struct tpm2_self_test
*command_body
)
269 return obuf_write_be8(ob
, command_body
->yes_no
);
272 static int marshal_hierarchy_control(struct obuf
*ob
,
273 const struct tpm2_hierarchy_control_cmd
*command_body
)
276 struct tpm2_session_header session_header
;
278 tpm_tag
= TPM_ST_SESSIONS
;
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
);
285 rc
|= marshal_TPM_HANDLE(ob
, command_body
->enable
);
286 rc
|= obuf_write_be8(ob
, command_body
->state
);
291 static int marshal_clear_control(struct obuf
*ob
,
292 const struct tpm2_clear_control_cmd
*command_body
)
295 struct tpm2_session_header session_header
;
297 tpm_tag
= TPM_ST_SESSIONS
;
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
);
304 rc
|= obuf_write_be8(ob
, command_body
->disable
);
309 static int marshal_cr50_vendor_command(struct obuf
*ob
, const void *command_body
)
312 const uint16_t *sub_command
= command_body
;
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.
320 rc
|= obuf_write_be16(ob
, sub_command
[0]);
321 rc
|= obuf_write_be16(ob
, sub_command
[1]);
323 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS
:
324 rc
|= obuf_write_be16(ob
, *sub_command
);
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]);
330 case TPM2_CR50_SUB_CMD_GET_REC_BTN
:
331 rc
|= obuf_write_be16(ob
, *sub_command
);
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.
340 * coreboot currently only uses the TPM get capability and does
341 * not set a new TPM state with the Cr50.
343 rc
|= obuf_write_be16(ob
, *sub_command
);
345 case TPM2_CR50_SUB_CMD_GET_BOOT_MODE
:
346 rc
|= obuf_write_be16(ob
, *sub_command
);
348 case TPM2_CR50_SUB_CMD_RESET_EC
:
349 rc
|= obuf_write_be16(ob
, *sub_command
);
351 case TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG
:
352 rc
|= obuf_write_be16(ob
, *sub_command
);
355 /* Unsupported subcommand. */
356 printk(BIOS_WARNING
, "Unsupported cr50 subcommand: 0x%04x\n",
364 int tpm_marshal_command(TPM_CC command
, const void *tpm_command_body
, struct obuf
*ob
)
367 const size_t hdr_sz
= sizeof(uint16_t) + 2 * sizeof(uint32_t);
370 tpm_tag
= TPM_ST_NO_SESSIONS
;
372 if (obuf_splice_current(ob
, &ob_hdr
, hdr_sz
) < 0)
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
);
385 rc
|= marshal_startup(ob
, tpm_command_body
);
389 rc
|= marshal_shutdown(ob
, tpm_command_body
);
392 case TPM2_GetCapability
:
393 rc
|= marshal_get_capability(ob
, tpm_command_body
);
397 rc
|= marshal_nv_read(ob
, tpm_command_body
);
400 case TPM2_NV_DefineSpace
:
401 rc
|= marshal_nv_define_space(ob
, tpm_command_body
);
404 case TPM2_NV_SetBits
:
405 rc
|= marshal_nv_setbits(ob
, tpm_command_body
);
409 rc
|= marshal_nv_write(ob
, tpm_command_body
);
412 case TPM2_NV_WriteLock
:
413 rc
|= marshal_nv_write_lock(ob
, tpm_command_body
);
417 rc
|= marshal_selftest(ob
, tpm_command_body
);
420 case TPM2_Hierarchy_Control
:
421 rc
|= marshal_hierarchy_control(ob
, tpm_command_body
);
424 case TPM2_ClearControl
:
425 rc
|= marshal_clear_control(ob
, tpm_command_body
);
429 rc
|= marshal_clear(ob
);
432 case TPM2_PCR_Extend
:
433 rc
|= marshal_pcr_extend(ob
, tpm_command_body
);
436 case TPM2_CR50_VENDOR_COMMAND
:
437 rc
|= marshal_cr50_vendor_command(ob
, tpm_command_body
);
441 printk(BIOS_INFO
, "%s:%d:Request to marshal unsupported command %#x\n",
442 __FILE__
, __LINE__
, command
);
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
));
456 static int unmarshal_get_capability(struct ibuf
*ib
,
457 struct get_cap_response
*gcr
)
462 rc
|= ibuf_read_be8(ib
, &gcr
->more_data
);
463 rc
|= unmarshal_TPM_CAP(ib
, &gcr
->cd
.capability
);
468 switch (gcr
->cd
.capability
) {
469 case TPM_CAP_TPM_PROPERTIES
:
470 if (ibuf_read_be32(ib
, &gcr
->cd
.data
.tpmProperties
.count
))
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
);
479 for (i
= 0; i
< gcr
->cd
.data
.tpmProperties
.count
; i
++) {
480 TPMS_TAGGED_PROPERTY
*pp
;
482 pp
= gcr
->cd
.data
.tpmProperties
.tpmProperty
+ i
;
483 rc
|= unmarshal_TPM_PT(ib
, &pp
->property
);
484 rc
|= ibuf_read_be32(ib
, &pp
->value
);
488 if (ibuf_read_be32(ib
, &gcr
->cd
.data
.assignedPCR
.count
))
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
);
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
));
505 "%s:%d - unable to unmarshal capability response",
507 printk(BIOS_ERR
, " for %d\n", gcr
->cd
.capability
);
515 static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf
*ib
,
516 TPM2B_MAX_NV_BUFFER
*nv_buffer
)
518 if (ibuf_read_be16(ib
, &nv_buffer
->t
.size
))
521 nv_buffer
->t
.buffer
= ibuf_oob_drain(ib
, nv_buffer
->t
.size
);
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
,
534 static int unmarshal_nv_read(struct ibuf
*ib
, struct nv_read_response
*nvr
)
536 /* Total size of the parameter field. */
537 if (ibuf_read_be32(ib
, &nvr
->params_size
))
540 if (unmarshal_TPM2B_MAX_NV_BUFFER(ib
, &nvr
->buffer
))
543 if (nvr
->params_size
!=
544 (nvr
->buffer
.t
.size
+ sizeof(nvr
->buffer
.t
.size
))) {
546 "%s:%d - parameter/buffer %d/%d size mismatch",
547 __func__
, __LINE__
, nvr
->params_size
,
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.
556 if (ibuf_remaining(ib
) != 5)
558 "%s:%d - unexpected authorization section size %zd\n",
559 __func__
, __LINE__
, ibuf_remaining(ib
));
561 ibuf_oob_drain(ib
, ibuf_remaining(ib
));
566 static int unmarshal_vendor_command(struct ibuf
*ib
,
567 struct vendor_command_response
*vcr
)
569 if (ibuf_read_be16(ib
, &vcr
->vc_subcommand
))
572 switch (vcr
->vc_subcommand
) {
573 case TPM2_CR50_SUB_CMD_IMMEDIATE_RESET
:
575 case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS
:
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
:
587 case TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG
:
588 return ibuf_read_be64(ib
, &vcr
->factory_config
);
591 "%s:%d - unsupported vendor command %#04x!\n",
592 __func__
, __LINE__
, vcr
->vc_subcommand
);
599 struct tpm2_response
*tpm_unmarshal_response(TPM_CC command
, struct ibuf
*ib
)
601 static struct tpm2_response tpm2_static_resp
;
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
);
611 if (ibuf_capacity(ib
) != tpm2_static_resp
.hdr
.tpm_size
) {
613 "%s: size mismatch in response to command %#x\n",
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
;
630 case TPM2_GetCapability
:
631 rc
|= unmarshal_get_capability(ib
, &tpm2_static_resp
.gc
);
635 rc
|= unmarshal_nv_read(ib
, &tpm2_static_resp
.nvr
);
638 case TPM2_Hierarchy_Control
:
640 case TPM2_ClearControl
:
641 case TPM2_NV_DefineSpace
:
642 case TPM2_NV_SetBits
:
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
));
650 case TPM2_CR50_VENDOR_COMMAND
:
651 rc
|= unmarshal_vendor_command(ib
, &tpm2_static_resp
.vcr
);
660 printk(BIOS_INFO
, "%s:%d:"
661 "Request to unmarshal unexpected command %#x,"
663 __func__
, __LINE__
, command
,
664 tpm2_static_resp
.hdr
.tpm_code
);
666 sz_left
= ibuf_remaining(ib
);
667 data
= ibuf_oob_drain(ib
, sz_left
);
669 for (i
= 0; i
< sz_left
; i
++) {
671 printk(BIOS_INFO
, "\n");
672 printk(BIOS_INFO
, "%2.2x ", data
[i
]);
675 printk(BIOS_INFO
, "\n");
679 if (ibuf_remaining(ib
)) {
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
));
688 printk(BIOS_WARNING
, "%s had one or more failures.\n",
691 /* The entire message have been parsed. */
692 return &tpm2_static_resp
;