summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Pronin <apronin@chromium.org>2018-03-22 17:45:20 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-03-27 14:58:10 -0700
commit3ee5c7d8adf5d78d6864c73bf4f33b95f04a7979 (patch)
tree0b6506791bb56bcae5f99a4c90ce0b50209cca9f
parentd3ec8f8116b167f58d76f0c798ae1b4d14aec389 (diff)
downloadvboot-3ee5c7d8adf5d78d6864c73bf4f33b95f04a7979.tar.gz
firmware: tpm2_lite: propagate actual errors
Propagate the actual error - a non-successful response code from the tpm or communication/serializing failure - to the caller of the Tlcl functions in TPM 2.0 case. Currently, the callers only have special processing for the error codes from TCG TPM 1.2 range, which are never returned in case of communication or serialization failures or from the actual TPM 2.0. (The only case of mapping TPM 2.0 error codes to TPM_E_BADINDEX is preserved in this CL.) Thus, changing the actual values returned from the functions won't change any current behavior in the calling layers. This CL is a preparatory work for adding special processing for communication errors in mount-encrypted. BUG=chromium:702724 BRANCH=none TEST=build; test that tpmc getvf, tpmc read still work. Change-Id: I96b20e7285e83f0038abc01e4b7175c938867e7d Signed-off-by: Andrey Pronin <apronin@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/977225 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--firmware/include/tpm2_marshaling.h14
-rw-r--r--firmware/lib/tpm2_lite/marshaling.c37
-rw-r--r--firmware/lib/tpm2_lite/tlcl.c239
3 files changed, 132 insertions, 158 deletions
diff --git a/firmware/include/tpm2_marshaling.h b/firmware/include/tpm2_marshaling.h
index cbfded11..3ebea388 100644
--- a/firmware/include/tpm2_marshaling.h
+++ b/firmware/include/tpm2_marshaling.h
@@ -33,18 +33,18 @@ int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
* Given a buffer received from the TPM in response to a certain command,
* deserialize the buffer into the expeced response structure.
*
- * struct tpm2_response is a union of all possible responses.
- *
* @command: code of the TPM2 command for which a response is unmarshaled
* @response_body: buffer containing the serialized response.
* @response_size: number of bytes in the buffer containing response
+ * @response: structure to be filled with deserialized response,
+ * struct tpm2_response is a union of all possible responses.
*
- * Returns a pointer to the deserialized response or NULL in case of
- * unmarshaling problems.
+ * Returns 0 on success, or -1 on error.
*/
-struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
- void *response_body,
- int response_size);
+int tpm_unmarshal_response(TPM_CC command,
+ void *response_body,
+ int response_size,
+ struct tpm2_response *response);
/**
* tpm_get_packet_size
diff --git a/firmware/lib/tpm2_lite/marshaling.c b/firmware/lib/tpm2_lite/marshaling.c
index 93beaf70..b5d45bfc 100644
--- a/firmware/lib/tpm2_lite/marshaling.c
+++ b/firmware/lib/tpm2_lite/marshaling.c
@@ -717,40 +717,39 @@ int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
return body_size;
}
-struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
- void *response_body,
- int cr_size)
+int tpm_unmarshal_response(TPM_CC command,
+ void *response_body,
+ int cr_size,
+ struct tpm2_response *response)
{
- static struct tpm2_response tpm2_resp;
-
if (cr_size < sizeof(struct tpm_header))
- return NULL;
+ return -1;
- tpm2_resp.hdr.tpm_tag = unmarshal_u16(&response_body, &cr_size);
- tpm2_resp.hdr.tpm_size = unmarshal_u32(&response_body, &cr_size);
- tpm2_resp.hdr.tpm_code = unmarshal_TPM_CC(&response_body, &cr_size);
+ response->hdr.tpm_tag = unmarshal_u16(&response_body, &cr_size);
+ response->hdr.tpm_size = unmarshal_u32(&response_body, &cr_size);
+ response->hdr.tpm_code = unmarshal_TPM_CC(&response_body, &cr_size);
if (!cr_size) {
- if (tpm2_resp.hdr.tpm_size != sizeof(tpm2_resp.hdr))
+ if (response->hdr.tpm_size != sizeof(response->hdr))
VB2_DEBUG("size mismatch in response to command %#x\n",
command);
- return &tpm2_resp;
+ return 0;
}
switch (command) {
case TPM2_NV_Read:
unmarshal_nv_read(&response_body, &cr_size,
- &tpm2_resp.nvr);
+ &response->nvr);
break;
case TPM2_NV_ReadPublic:
unmarshal_nv_read_public(&response_body, &cr_size,
- &tpm2_resp.nv_read_public);
+ &response->nv_read_public);
break;
case TPM2_GetCapability:
unmarshal_get_capability(&response_body, &cr_size,
- &tpm2_resp.cap);
+ &response->cap);
break;
case TPM2_Hierarchy_Control:
@@ -773,7 +772,7 @@ struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
VB2_DEBUG("Request to unmarshal unexpected command %#x,"
" code %#x",
command,
- tpm2_resp.hdr.tpm_code);
+ response->hdr.tpm_code);
for (i = 0; i < cr_size; i++) {
if (!(i % 16))
@@ -783,19 +782,19 @@ struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
}
}
VB2_DEBUG("\n");
- return NULL;
+ return -1;
}
if (cr_size) {
VB2_DEBUG("got %d bytes back in response to %#x,"
" failed to parse (%d)\n",
- tpm2_resp.hdr.tpm_size,
+ response->hdr.tpm_size,
command, cr_size);
- return NULL;
+ return -1;
}
/* The entire message have been parsed. */
- return &tpm2_resp;
+ return 0;
}
uint32_t tpm_get_packet_size(const uint8_t *packet)
diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c
index 89bf25a7..aec3e2b3 100644
--- a/firmware/lib/tpm2_lite/tlcl.c
+++ b/firmware/lib/tpm2_lite/tlcl.c
@@ -15,34 +15,83 @@
#include "utility.h"
#include "tlcl.h"
-static struct tpm2_response *tpm_process_command(TPM_CC command,
- void *command_body)
+/* Global buffer for deserialized responses. */
+struct tpm2_response tpm2_resp;
+
+/*
+ * Serializes and sends the command, gets back the response and
+ * parses it into the provided buffer.
+ *
+ * @command: command code.
+ * @command_body: command-specific payload.
+ * @response: pointer to the buffer to place the parsed response to.
+ *
+ * Returns the result of processing the command:
+ * - if an error happened at marshaling, sending, receiving or unmarshaling
+ * stages, returns the error code;
+ * - if the received response was successfully unmarshaled, returns success
+ * regardless of the received response code.
+ */
+static uint32_t tpm_get_response(TPM_CC command,
+ void *command_body,
+ struct tpm2_response *response)
{
/* Command/response buffer. */
static uint8_t cr_buffer[TPM_BUFFER_SIZE];
- uint32_t out_size, in_size;
- struct tpm2_response *response;
+ uint32_t out_size, in_size, res;
out_size = tpm_marshal_command(command, command_body,
cr_buffer, sizeof(cr_buffer));
if (out_size < 0) {
- VB2_DEBUG("command %#x, cr size %d\n", command, out_size);
- return NULL;
+ VB2_DEBUG("command %#x, failed to serialize\n", command);
+ return TPM_E_WRITE_FAILURE;
}
in_size = sizeof(cr_buffer);
- if (VbExTpmSendReceive(cr_buffer, out_size,
- cr_buffer, &in_size) != TPM_SUCCESS) {
- VB2_DEBUG("tpm transaction failed for %#x\n", command);
- return NULL;
+ res = VbExTpmSendReceive(cr_buffer, out_size, cr_buffer, &in_size);
+ if (res != TPM_SUCCESS) {
+ VB2_DEBUG("tpm transaction failed for %#x with error %#x\n",
+ command, res);
+ return res;
}
- response = tpm_unmarshal_response(command, cr_buffer, in_size);
+ if (tpm_unmarshal_response(command, cr_buffer, in_size, response) < 0) {
+ VB2_DEBUG("command %#x, failed to parse response\n", command);
+ return TPM_E_READ_FAILURE;
+ }
VB2_DEBUG("command %#x, return code %#x\n", command,
- response ? response->hdr.tpm_code : -1);
+ response->hdr.tpm_code);
- return response;
+ return TPM_SUCCESS;
+}
+
+/*
+ * Same as tpm_get_response() but, if the response was successfully received,
+ * returns the received response code. The set of errors returned by the
+ * communication stack doesn't overlap with the set of errors returned by the
+ * TPM, so it's always possible to distinguish the two. In case of communication
+ * errors, the caller should not check other fields of response, as the response
+ * is likely not filled. In any case, it is recommended that callers, who need
+ * to work with response fields even if a non-zero response code was received
+ * from the TPM, use tpm_get_response() and explicitly check the response code
+ * themselves.
+ */
+static uint32_t tpm_send_receive(TPM_CC command,
+ void *command_body,
+ struct tpm2_response *response)
+{
+ uint32_t rv = tpm_get_response(command, command_body, response);
+
+ return rv ? rv : response->hdr.tpm_code;
+}
+
+/*
+ * Same as tpm_send_receive() for callers that care only about the return code.
+ */
+static uint32_t tpm_get_response_code(TPM_CC command, void *command_body)
+{
+ return tpm_send_receive(command, command_body, &tpm2_resp);
}
static uint32_t tlcl_read_ph_disabled(void)
@@ -51,12 +100,10 @@ static uint32_t tlcl_read_ph_disabled(void)
TPM_STCLEAR_FLAGS flags;
rv = TlclGetSTClearFlags(&flags);
- if (rv != TPM_SUCCESS)
- return rv;
-
- tpm_set_ph_disabled(!flags.phEnable);
+ if (rv == TPM_SUCCESS)
+ tpm_set_ph_disabled(!flags.phEnable);
- return TPM_SUCCESS;
+ return rv;
}
uint32_t TlclLibInit(void)
@@ -68,12 +115,10 @@ uint32_t TlclLibInit(void)
return rv;
rv = tlcl_read_ph_disabled();
- if (rv != TPM_SUCCESS) {
+ if (rv != TPM_SUCCESS)
TlclLibClose();
- return rv;
- }
- return TPM_SUCCESS;
+ return rv;
}
uint32_t TlclLibClose(void)
@@ -100,77 +145,51 @@ int TlclPacketSize(const uint8_t *packet)
uint32_t TlclStartup(void)
{
- struct tpm2_response *response;
struct tpm2_startup_cmd startup;
startup.startup_type = TPM_SU_CLEAR;
- response = tpm_process_command(TPM2_Startup, &startup);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_Startup, &startup);
}
uint32_t TlclSaveState(void)
{
- struct tpm2_response *response;
struct tpm2_shutdown_cmd shutdown;
shutdown.shutdown_type = TPM_SU_STATE;
- response = tpm_process_command(TPM2_Shutdown, &shutdown);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_Shutdown, &shutdown);
}
uint32_t TlclResume(void)
{
- struct tpm2_response *response;
struct tpm2_startup_cmd startup;
startup.startup_type = TPM_SU_STATE;
- response = tpm_process_command(TPM2_Startup, &startup);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_Startup, &startup);
}
uint32_t TlclSelfTestFull(void)
{
- struct tpm2_response *response;
struct tpm2_self_test_cmd self_test;
self_test.full_test = 1;
- response = tpm_process_command(TPM2_SelfTest, &self_test);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_SelfTest, &self_test);
}
uint32_t TlclContinueSelfTest(void)
{
- struct tpm2_response *response;
struct tpm2_self_test_cmd self_test;
self_test.full_test = 0;
- response = tpm_process_command(TPM2_SelfTest, &self_test);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_SelfTest, &self_test);
}
uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
{
- struct tpm2_response *response;
struct tpm2_nv_define_space_cmd define_space;
/* For backwards-compatibility, if no READ or WRITE permissions are set,
@@ -187,11 +206,7 @@ uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
define_space.publicInfo.attributes = perm;
define_space.publicInfo.nameAlg = TPM_ALG_SHA256;
- response = tpm_process_command(TPM2_NV_DefineSpace, &define_space);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_NV_DefineSpace, &define_space);
}
/**
@@ -199,13 +214,7 @@ uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
*/
uint32_t TlclForceClear(void)
{
- struct tpm2_response *response;
-
- response = tpm_process_command(TPM2_Clear, NULL);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_Clear, NULL);
}
uint32_t TlclSetDeactivated(uint8_t flag)
@@ -250,18 +259,18 @@ uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest)
static uint32_t tlcl_nv_read_public(uint32_t index,
struct nv_read_public_response **presp)
{
- struct tpm2_response *response;
+ struct tpm2_response *response = &tpm2_resp;
struct tpm2_nv_read_public_cmd read_pub;
+ uint32_t rv;
memset(&read_pub, 0, sizeof(read_pub));
read_pub.nvIndex = HR_NV_INDEX + index;
- response = tpm_process_command(TPM2_NV_ReadPublic, &read_pub);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
- *presp = &response->nv_read_public;
+ rv = tpm_send_receive(TPM2_NV_ReadPublic, &read_pub, response);
+ if (rv == TPM_SUCCESS)
+ *presp = &response->nv_read_public;
- return TPM_SUCCESS;
+ return rv;
}
/**
@@ -273,29 +282,28 @@ uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions)
struct nv_read_public_response *resp;
rv = tlcl_nv_read_public(index, &resp);
- if (rv != TPM_SUCCESS)
- return rv;
+ if (rv == TPM_SUCCESS)
+ *permissions = resp->nvPublic.attributes;
- *permissions = resp->nvPublic.attributes;
- return TPM_SUCCESS;
+ return rv;
}
static uint32_t tlcl_get_capability(TPM_CAP cap, TPM_PT property,
struct get_capability_response **presp)
{
- struct tpm2_response *response;
+ struct tpm2_response *response = &tpm2_resp;
struct tpm2_get_capability_cmd getcap;
+ uint32_t rv;
getcap.capability = cap;
getcap.property = property;
getcap.property_count = 1;
- response = tpm_process_command(TPM2_GetCapability, &getcap);
- if (!response || response->hdr.tpm_code)
- return TPM_E_IOERROR;
- *presp = &response->cap;
+ rv = tpm_send_receive(TPM2_GetCapability, &getcap, response);
+ if (rv == TPM_SUCCESS)
+ *presp = &response->cap;
- return TPM_SUCCESS;
+ return rv;
}
static uint32_t tlcl_get_tpm_property(TPM_PT property, uint32_t *pvalue)
@@ -340,43 +348,33 @@ uint32_t TlclGetOwnership(uint8_t *owned)
*owned = 0;
rv = TlclGetPermanentFlags(&flags);
- if (rv != TPM_SUCCESS)
- return rv;
-
- *owned = flags.ownerAuthSet;
+ if (rv == TPM_SUCCESS)
+ *owned = flags.ownerAuthSet;
- return TPM_SUCCESS;
+ return rv;
}
static uint32_t tlcl_lock_nv_write(uint32_t index)
{
- struct tpm2_response *response;
struct tpm2_nv_write_lock_cmd nv_wl;
nv_wl.nvIndex = HR_NV_INDEX + index;
- response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
-
- if (!response || response->hdr.tpm_code)
- return TPM_E_INTERNAL_INCONSISTENCY;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_NV_WriteLock, &nv_wl);
}
static uint32_t tlcl_disable_platform_hierarchy(void)
{
- struct tpm2_response *response;
struct tpm2_hierarchy_control_cmd hc;
+ uint32_t rv;
hc.enable = TPM_RH_PLATFORM;
hc.state = 0;
- response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
+ rv = tpm_get_response_code(TPM2_Hierarchy_Control, &hc);
+ if (rv == TPM_SUCCESS)
+ tpm_set_ph_disabled(1);
- if (!response || response->hdr.tpm_code)
- return TPM_E_INTERNAL_INCONSISTENCY;
-
- tpm_set_ph_disabled(1);
- return TPM_SUCCESS;
+ return rv;
}
/**
@@ -419,28 +417,26 @@ uint32_t TlclLockPhysicalPresence(void)
uint32_t TlclRead(uint32_t index, void* data, uint32_t length)
{
struct tpm2_nv_read_cmd nv_readc;
- struct tpm2_response *response;
+ struct tpm2_response *response = &tpm2_resp;
+ uint32_t rv;
memset(&nv_readc, 0, sizeof(nv_readc));
nv_readc.nvIndex = HR_NV_INDEX + index;
nv_readc.size = length;
- response = tpm_process_command(TPM2_NV_Read, &nv_readc);
+ rv = tpm_send_receive(TPM2_NV_Read, &nv_readc, response);
/* Need to map tpm error codes into internal values. */
- if (!response)
- return TPM_E_READ_FAILURE;
-
- switch (response->hdr.tpm_code) {
- case 0:
+ switch (rv) {
+ case TPM_SUCCESS:
break;
case 0x28b:
return TPM_E_BADINDEX;
default:
- return TPM_E_READ_FAILURE;
+ return rv;
}
if (length > response->nvr.buffer.t.size)
@@ -457,7 +453,6 @@ uint32_t TlclRead(uint32_t index, void* data, uint32_t length)
uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length)
{
struct tpm2_nv_write_cmd nv_writec;
- struct tpm2_response *response;
memset(&nv_writec, 0, sizeof(nv_writec));
@@ -465,13 +460,7 @@ uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length)
nv_writec.data.t.size = length;
nv_writec.data.t.buffer = data;
- response = tpm_process_command(TPM2_NV_Write, &nv_writec);
-
- /* Need to map tpm error codes into internal values. */
- if (!response || response->hdr.tpm_code)
- return TPM_E_WRITE_FAILURE;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_NV_Write, &nv_writec);
}
uint32_t TlclPCRRead(uint32_t index, void *data, uint32_t length)
@@ -483,37 +472,23 @@ uint32_t TlclPCRRead(uint32_t index, void *data, uint32_t length)
uint32_t TlclWriteLock(uint32_t index)
{
struct tpm2_nv_write_lock_cmd nv_writelockc;
- struct tpm2_response *response;
memset(&nv_writelockc, 0, sizeof(nv_writelockc));
nv_writelockc.nvIndex = HR_NV_INDEX | index;
- response = tpm_process_command(TPM2_NV_WriteLock, &nv_writelockc);
-
- /* Need to map tpm error codes into internal values. */
- if (!response || response->hdr.tpm_code)
- return TPM_E_WRITE_FAILURE;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_NV_WriteLock, &nv_writelockc);
}
uint32_t TlclReadLock(uint32_t index)
{
struct tpm2_nv_read_lock_cmd nv_readlockc;
- struct tpm2_response *response;
memset(&nv_readlockc, 0, sizeof(nv_readlockc));
nv_readlockc.nvIndex = HR_NV_INDEX | index;
- response = tpm_process_command(TPM2_NV_ReadLock, &nv_readlockc);
-
- /* Need to map tpm error codes into internal values. */
- if (!response || response->hdr.tpm_code)
- return TPM_E_READ_FAILURE;
-
- return TPM_SUCCESS;
+ return tpm_get_response_code(TPM2_NV_ReadLock, &nv_readlockc);
}
uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size)