diff options
Diffstat (limited to 'src/lib/tpm2_marshaling.c')
-rw-r--r-- | src/lib/tpm2_marshaling.c | 559 |
1 files changed, 0 insertions, 559 deletions
diff --git a/src/lib/tpm2_marshaling.c b/src/lib/tpm2_marshaling.c deleted file mode 100644 index 3ce09a4f8d..0000000000 --- a/src/lib/tpm2_marshaling.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include <arch/early_variables.h> -#include <commonlib/iobuf.h> -#include <console/console.h> -#include <stdlib.h> -#include <string.h> - -#include "tpm2_marshaling.h" - -static uint16_t tpm_tag CAR_GLOBAL; /* Depends on the command type. */ - -#define unmarshal_TPM_CAP(a, b) ibuf_read_be32(a, b) -#define unmarshal_TPM_CC(a, b) ibuf_read_be32(a, b) -#define unmarshal_TPM_PT(a, b) ibuf_read_be32(a, b) -#define unmarshal_TPM_HANDLE(a, b) ibuf_read_be32(a, b) - -#define marshal_TPM_HANDLE(a, b) obuf_write_be32(a, b) -#define marshal_TPMI_ALG_HASH(a, b) obuf_write_be16(a, b) - -static int marshal_startup(struct obuf *ob, struct tpm2_startup *cmd_body) -{ - return obuf_write_be16(ob, cmd_body->startup_type); -} - -static int marshal_get_capability(struct obuf *ob, - struct tpm2_get_capability *cmd_body) -{ - int rc = 0; - - rc |= obuf_write_be32(ob, cmd_body->capability); - rc |= obuf_write_be32(ob, cmd_body->property); - rc |= obuf_write_be32(ob, cmd_body->propertyCount); - - return rc; -} - -static int marshal_TPM2B(struct obuf *ob, TPM2B *data) -{ - int rc = 0; - - rc |= obuf_write_be16(ob, data->size); - rc |= obuf_write(ob, data->buffer, data->size); - - return rc; -} - -static int marshal_TPMA_NV(struct obuf *ob, TPMA_NV *nv) -{ - uint32_t v; - - memcpy(&v, nv, sizeof(v)); - return obuf_write_be32(ob, v); -} - -static int marshal_TPMS_NV_PUBLIC(struct obuf *ob, TPMS_NV_PUBLIC *nvpub) -{ - int rc = 0; - - rc |= marshal_TPM_HANDLE(ob, nvpub->nvIndex); - rc |= marshal_TPMI_ALG_HASH(ob, nvpub->nameAlg); - rc |= marshal_TPMA_NV(ob, &nvpub->attributes); - rc |= marshal_TPM2B(ob, &nvpub->authPolicy.b); - rc |= obuf_write_be16(ob, nvpub->dataSize); - - return rc; -} - -static int marshal_TPMT_HA(struct obuf *ob, TPMT_HA *tpmtha) -{ - int rc = 0; - - rc |= marshal_TPMI_ALG_HASH(ob, tpmtha->hashAlg); - rc |= obuf_write(ob, tpmtha->digest.sha256, - sizeof(tpmtha->digest.sha256)); - - return rc; -} - -static int marshal_TPML_DIGEST_VALUES(struct obuf *ob, - TPML_DIGEST_VALUES *dvalues) -{ - int i; - int rc = 0; - - rc |= obuf_write_be32(ob, dvalues->count); - for (i = 0; i < dvalues->count; i++) - rc |= marshal_TPMT_HA(ob, &dvalues->digests[i]); - - return rc; -} - -static int marshal_session_header(struct obuf *ob, - struct tpm2_session_header *session_header) -{ - int rc = 0; - struct obuf ob_sz; - size_t prev_written; - - /* Snapshot current location to place size of header. */ - if (obuf_splice_current(ob, &ob_sz, sizeof(uint32_t)) < 0) - return -1; - - /* Write a size placeholder. */ - rc |= obuf_write_be32(ob, 0); - - /* Keep track of session header data size by tracking num written. */ - prev_written = obuf_nr_written(ob); - - rc |= obuf_write_be32(ob, session_header->session_handle); - rc |= obuf_write_be16(ob, session_header->nonce_size); - rc |= obuf_write(ob, session_header->nonce, session_header->nonce_size); - rc |= obuf_write_be8(ob, session_header->session_attrs); - rc |= obuf_write_be16(ob, session_header->auth_size); - rc |= obuf_write(ob, session_header->auth, session_header->auth_size); - - /* Fill back in proper size of session header. */ - rc |= obuf_write_be32(&ob_sz, obuf_nr_written(ob) - prev_written); - - return rc; -} - -/* - * Common session header can include one or two handles and an empty - * session_header structure. - */ -static int marshal_common_session_header(struct obuf *ob, - const uint32_t *handles, - size_t handle_count) -{ - size_t i; - struct tpm2_session_header session_header; - int rc = 0; - - car_set_var(tpm_tag, TPM_ST_SESSIONS); - - for (i = 0; i < handle_count; i++) - rc |= marshal_TPM_HANDLE(ob, handles[i]); - - memset(&session_header, 0, sizeof(session_header)); - session_header.session_handle = TPM_RS_PW; - rc |= marshal_session_header(ob, &session_header); - - return rc; -} - -static int marshal_nv_define_space(struct obuf *ob, - struct tpm2_nv_define_space_cmd *nvd_in) -{ - const uint32_t handle[] = { TPM_RH_PLATFORM }; - struct obuf ob_sz; - size_t prev_written; - int rc = 0; - - rc |= marshal_common_session_header(ob, handle, ARRAY_SIZE(handle)); - rc |= marshal_TPM2B(ob, &nvd_in->auth.b); - - /* Snapshot current location to place size field. */ - if (obuf_splice_current(ob, &ob_sz, sizeof(uint16_t)) < 0) - return -1; - - /* Put placeholder for size */ - rc |= obuf_write_be16(ob, 0); - - /* Keep track of nv define space data size by tracking num written. */ - prev_written = obuf_nr_written(ob); - - rc |= marshal_TPMS_NV_PUBLIC(ob, &nvd_in->publicInfo); - rc |= obuf_write_be16(&ob_sz, obuf_nr_written(ob) - prev_written); - - return rc; -} - -static int marshal_nv_write(struct obuf *ob, - struct tpm2_nv_write_cmd *command_body) -{ - int rc = 0; - uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex }; - - rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles)); - rc |= marshal_TPM2B(ob, &command_body->data.b); - rc |= obuf_write_be16(ob, command_body->offset); - - return rc; -} - -static int marshal_nv_write_lock(struct obuf *ob, - struct tpm2_nv_write_lock_cmd *command_body) -{ - uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex }; - - return marshal_common_session_header(ob, handles, ARRAY_SIZE(handles)); -} - -static int marshal_pcr_extend(struct obuf *ob, - struct tpm2_pcr_extend_cmd *command_body) -{ - int rc = 0; - uint32_t handles[] = { command_body->pcrHandle }; - - rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles)); - rc |= marshal_TPML_DIGEST_VALUES(ob, &command_body->digests); - - return rc; -} - -static int marshal_nv_read(struct obuf *ob, - struct tpm2_nv_read_cmd *command_body) -{ - int rc = 0; - uint32_t handles[] = { TPM_RH_PLATFORM, command_body->nvIndex }; - - rc |= marshal_common_session_header(ob, handles, ARRAY_SIZE(handles)); - rc |= obuf_write_be16(ob, command_body->size); - rc |= obuf_write_be16(ob, command_body->offset); - - return rc; -} - -/* TPM2_Clear command does not require paramaters. */ -static int marshal_clear(struct obuf *ob) -{ - const uint32_t handle[] = { TPM_RH_PLATFORM }; - - return marshal_common_session_header(ob, handle, ARRAY_SIZE(handle)); -} - -static int marshal_selftest(struct obuf *ob, - struct tpm2_self_test *command_body) -{ - return obuf_write_be8(ob, command_body->yes_no); -} - -static int marshal_hierarchy_control(struct obuf *ob, - struct tpm2_hierarchy_control_cmd *command_body) -{ - int rc = 0; - struct tpm2_session_header session_header; - - car_set_var(tpm_tag, TPM_ST_SESSIONS); - - rc |= marshal_TPM_HANDLE(ob, TPM_RH_PLATFORM); - memset(&session_header, 0, sizeof(session_header)); - session_header.session_handle = TPM_RS_PW; - rc |= marshal_session_header(ob, &session_header); - - rc |= marshal_TPM_HANDLE(ob, command_body->enable); - rc |= obuf_write_be8(ob, command_body->state); - - return rc; -} - -static int marshal_cr50_vendor_command(struct obuf *ob, void *command_body) -{ - int rc = 0; - uint16_t *sub_command = command_body; - - switch (*sub_command) { - case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS: - rc |= obuf_write_be16(ob, *sub_command); - break; - case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON: - rc |= obuf_write_be16(ob, sub_command[0]); - rc |= obuf_write_be16(ob, sub_command[1]); - break; - default: - /* Unsupported subcommand. */ - printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n", - *sub_command); - rc = -1; - break; - } - return rc; -} - -int tpm_marshal_command(TPM_CC command, void *tpm_command_body, struct obuf *ob) -{ - struct obuf ob_hdr; - const size_t hdr_sz = sizeof(uint16_t) + 2 * sizeof(uint32_t); - int rc = 0; - - car_set_var(tpm_tag, TPM_ST_NO_SESSIONS); - - if (obuf_splice_current(ob, &ob_hdr, hdr_sz) < 0) - return -1; - - /* Write TPM command header with placeholder field values. */ - rc |= obuf_write_be16(ob, 0); - rc |= obuf_write_be32(ob, 0); - rc |= obuf_write_be32(ob, command); - - if (rc != 0) - return rc; - - switch (command) { - case TPM2_Startup: - rc |= marshal_startup(ob, tpm_command_body); - break; - - case TPM2_GetCapability: - rc |= marshal_get_capability(ob, tpm_command_body); - break; - - case TPM2_NV_Read: - rc |= marshal_nv_read(ob, tpm_command_body); - break; - - case TPM2_NV_DefineSpace: - rc |= marshal_nv_define_space(ob, tpm_command_body); - break; - - case TPM2_NV_Write: - rc |= marshal_nv_write(ob, tpm_command_body); - break; - - case TPM2_NV_WriteLock: - rc |= marshal_nv_write_lock(ob, tpm_command_body); - break; - - case TPM2_SelfTest: - rc |= marshal_selftest(ob, tpm_command_body); - break; - - case TPM2_Hierarchy_Control: - rc |= marshal_hierarchy_control(ob, tpm_command_body); - break; - - case TPM2_Clear: - rc |= marshal_clear(ob); - break; - - case TPM2_PCR_Extend: - rc |= marshal_pcr_extend(ob, tpm_command_body); - break; - - case TPM2_CR50_VENDOR_COMMAND: - rc |= marshal_cr50_vendor_command(ob, tpm_command_body); - break; - - default: - printk(BIOS_INFO, "%s:%d:Request to marshal unsupported command %#x\n", - __FILE__, __LINE__, command); - rc = -1; - } - - if (rc != 0) - return rc; - - /* Fix up the command header with known values. */ - rc |= obuf_write_be16(&ob_hdr, car_get_var(tpm_tag)); - rc |= obuf_write_be32(&ob_hdr, obuf_nr_written(ob)); - - return rc; -} - -static int unmarshal_get_capability(struct ibuf *ib, - struct get_cap_response *gcr) -{ - int i; - int rc = 0; - - rc |= ibuf_read_be8(ib, &gcr->more_data); - rc |= unmarshal_TPM_CAP(ib, &gcr->cd.capability); - - if (rc != 0) - return rc; - - switch (gcr->cd.capability) { - case TPM_CAP_TPM_PROPERTIES: - if (ibuf_read_be32(ib, &gcr->cd.data.tpmProperties.count)) - return -1; - if (gcr->cd.data.tpmProperties.count > ARRAY_SIZE - (gcr->cd.data.tpmProperties.tpmProperty)) { - printk(BIOS_INFO, "%s:%s:%d - %d - too many properties\n", - __FILE__, __func__, __LINE__, - gcr->cd.data.tpmProperties.count); - return -1; - } - for (i = 0; i < gcr->cd.data.tpmProperties.count; i++) { - TPMS_TAGGED_PROPERTY *pp; - - pp = gcr->cd.data.tpmProperties.tpmProperty + i; - rc |= unmarshal_TPM_PT(ib, &pp->property); - rc |= ibuf_read_be32(ib, &pp->value); - } - break; - default: - printk(BIOS_ERR, - "%s:%d - unable to unmarshal capability response", - __func__, __LINE__); - printk(BIOS_ERR, " for %d\n", gcr->cd.capability); - rc = -1; - break; - } - - return rc; -} - -static int unmarshal_TPM2B_MAX_NV_BUFFER(struct ibuf *ib, - TPM2B_MAX_NV_BUFFER *nv_buffer) -{ - if (ibuf_read_be16(ib, &nv_buffer->t.size)) - return -1; - - nv_buffer->t.buffer = ibuf_oob_drain(ib, nv_buffer->t.size); - - if (nv_buffer->t.buffer == NULL) { - printk(BIOS_ERR, "%s:%d - " - "size mismatch: expected %d, remaining %zd\n", - __func__, __LINE__, nv_buffer->t.size, - ibuf_remaining(ib)); - return -1; - } - - return 0; -} - -static int unmarshal_nv_read(struct ibuf *ib, struct nv_read_response *nvr) -{ - /* Total size of the parameter field. */ - if (ibuf_read_be32(ib, &nvr->params_size)) - return -1; - - if (unmarshal_TPM2B_MAX_NV_BUFFER(ib, &nvr->buffer)) - return -1; - - if (nvr->params_size != - (nvr->buffer.t.size + sizeof(nvr->buffer.t.size))) { - printk(BIOS_ERR, - "%s:%d - parameter/buffer %d/%d size mismatch", - __func__, __LINE__, nvr->params_size, - nvr->buffer.t.size); - return -1; - } - - /* - * Let's ignore the authorisation section. It should be 5 bytes total, - * just confirm that this is the case and report any discrepancy. - */ - if (ibuf_remaining(ib) != 5) - printk(BIOS_ERR, - "%s:%d - unexpected authorisation seciton size %zd\n", - __func__, __LINE__, ibuf_remaining(ib)); - - ibuf_oob_drain(ib, ibuf_remaining(ib)); - - return 0; -} - -static int unmarshal_vendor_command(struct ibuf *ib, - struct vendor_command_response *vcr) -{ - if (ibuf_read_be16(ib, &vcr->vc_subcommand)) - return -1; - - switch (vcr->vc_subcommand) { - case TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS: - break; - case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON: - return ibuf_read_be8(ib, &vcr->num_restored_headers); - break; - default: - printk(BIOS_ERR, - "%s:%d - unsupported vendor command %#04x!\n", - __func__, __LINE__, vcr->vc_subcommand); - return -1; - } - - return 0; -} - -struct tpm2_response *tpm_unmarshal_response(TPM_CC command, struct ibuf *ib) -{ - static struct tpm2_response tpm2_static_resp CAR_GLOBAL; - struct tpm2_response *tpm2_resp = car_get_var_ptr(&tpm2_static_resp); - int rc = 0; - - rc |= ibuf_read_be16(ib, &tpm2_resp->hdr.tpm_tag); - rc |= ibuf_read_be32(ib, &tpm2_resp->hdr.tpm_size); - rc |= unmarshal_TPM_CC(ib, &tpm2_resp->hdr.tpm_code); - - if (rc != 0) - return NULL; - - if (ibuf_remaining(ib) == 0) { - if (tpm2_resp->hdr.tpm_size != ibuf_nr_read(ib)) - printk(BIOS_ERR, - "%s: size mismatch in response to command %#x\n", - __func__, command); - return tpm2_resp; - } - - switch (command) { - case TPM2_Startup: - break; - - case TPM2_GetCapability: - rc |= unmarshal_get_capability(ib, &tpm2_resp->gc); - break; - - case TPM2_NV_Read: - rc |= unmarshal_nv_read(ib, &tpm2_resp->nvr); - break; - - case TPM2_Hierarchy_Control: - case TPM2_Clear: - case TPM2_NV_DefineSpace: - case TPM2_NV_Write: - case TPM2_NV_WriteLock: - case TPM2_PCR_Extend: - /* Session data included in response can be safely ignored. */ - ibuf_oob_drain(ib, ibuf_remaining(ib)); - break; - - case TPM2_CR50_VENDOR_COMMAND: - rc |= unmarshal_vendor_command(ib, &tpm2_resp->vcr); - break; - - default: - { - size_t i; - size_t sz_left; - const uint8_t *data; - - printk(BIOS_INFO, "%s:%d:" - "Request to unmarshal unexpected command %#x," - " code %#x", - __func__, __LINE__, command, - tpm2_resp->hdr.tpm_code); - - sz_left = ibuf_remaining(ib); - data = ibuf_oob_drain(ib, sz_left); - - for (i = 0; i < sz_left; i++) { - if (!(i % 16)) - printk(BIOS_INFO, "\n"); - printk(BIOS_INFO, "%2.2x ", data[i]); - } - } - printk(BIOS_INFO, "\n"); - return NULL; - } - - if (ibuf_remaining(ib)) { - printk(BIOS_INFO, - "%s:%d got %d bytes back in response to %#x," - " failed to parse (%zd)\n", - __func__, __LINE__, tpm2_resp->hdr.tpm_size, - command, ibuf_remaining(ib)); - return NULL; - } - - /* The entire message have been parsed. */ - return tpm2_resp; -} |