summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)