From dc060ace1b461e09a8e0547f180377d707ff347d Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Tue, 5 Dec 2017 16:27:42 +0100 Subject: tpm_lite: Add TlclGetSpaceInfo The new TlclGetSpaceInfo function returns more detailed information about a defined NVRAM space. The existing TlclGetPermissions function is now using TlclGetSpaceInfo behind the scenes. BRANCH=None BUG=chromium:788719 TEST=New unit tests. Change-Id: I6c4f490d575788b696fd742a69e81e2767ec50f1 Reviewed-on: https://chromium-review.googlesource.com/937705 Trybot-Ready: Mattias Nissler Tested-by: Mattias Nissler Reviewed-by: Andrey Pronin --- firmware/include/tlcl.h | 11 +++ firmware/lib/tpm2_lite/tlcl.c | 23 +++++ firmware/lib/tpm_lite/include/tlcl_structures.h | 5 +- firmware/lib/tpm_lite/tlcl.c | 113 +++++++++++++++++++++--- tests/tlcl_tests.c | 83 +++++++++++++++-- utility/tlcl_generator.c | 9 +- 6 files changed, 218 insertions(+), 26 deletions(-) diff --git a/firmware/include/tlcl.h b/firmware/include/tlcl.h index 1b08ec9c..28508c3f 100644 --- a/firmware/include/tlcl.h +++ b/firmware/include/tlcl.h @@ -212,6 +212,17 @@ uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest); */ uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions); +/** + * Get the public information about the NVRAM space identified by |index|. All + * other parameters are filled in with the respective information. + * |auth_policy_size| is both an input an output parameter. It should contain + * the available buffer size in |auth_policy| and will be updated to indicate + * the size of the filled in auth policy upon return. If the buffer size is not + * sufficient, the return value will be TPM_E_BUFFER_SIZE. + */ +uint32_t TlclGetSpaceInfo(uint32_t index, uint32_t *attributes, uint32_t *size, + void* auth_policy, uint32_t* auth_policy_size); + /** * Get the entire set of permanent flags. */ diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c index 70d584f0..9c0ab887 100644 --- a/firmware/lib/tpm2_lite/tlcl.c +++ b/firmware/lib/tpm2_lite/tlcl.c @@ -313,6 +313,29 @@ uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions) return rv; } +uint32_t TlclGetSpaceInfo(uint32_t index, uint32_t *attributes, uint32_t *size, + void* auth_policy, uint32_t* auth_policy_size) +{ + uint32_t rv; + struct nv_read_public_response *resp; + + rv = tlcl_nv_read_public(index, &resp); + if (rv != TPM_SUCCESS) + return rv; + + *attributes = resp->nvPublic.attributes; + *size = resp->nvPublic.dataSize; + if (resp->nvPublic.authPolicy.size > *auth_policy_size) { + return TPM_E_BUFFER_SIZE; + } + + *auth_policy_size = resp->nvPublic.authPolicy.size; + memcpy(auth_policy, resp->nvPublic.authPolicy.buffer, + *auth_policy_size); + + return TPM_SUCCESS; +} + static uint32_t tlcl_get_capability(TPM_CAP cap, TPM_PT property, struct get_capability_response **presp) { diff --git a/firmware/lib/tpm_lite/include/tlcl_structures.h b/firmware/lib/tpm_lite/include/tlcl_structures.h index a3772328..8a17ccc8 100644 --- a/firmware/lib/tpm_lite/include/tlcl_structures.h +++ b/firmware/lib/tpm_lite/include/tlcl_structures.h @@ -59,10 +59,10 @@ const struct s_tpm_getownership_cmd{ } tpm_getownership_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x11, }, }; -const struct s_tpm_getpermissions_cmd{ +const struct s_tpm_getspaceinfo_cmd{ uint8_t buffer[22]; uint16_t index; -} tpm_getpermissions_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x4, }, +} tpm_getspaceinfo_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x4, }, 18, }; const struct s_tpm_getstclearflags_cmd{ @@ -179,4 +179,3 @@ const struct s_tpm_nv_definespace_cmd{ 12, 16, 42, 70, 77, }; const int kWriteInfoLength = 12; -const int kNvDataPublicPermissionsOffset = 60; diff --git a/firmware/lib/tpm_lite/tlcl.c b/firmware/lib/tpm_lite/tlcl.c index 37d0fe20..d7dfade9 100644 --- a/firmware/lib/tpm_lite/tlcl.c +++ b/firmware/lib/tpm_lite/tlcl.c @@ -834,21 +834,110 @@ uint32_t TlclExtend(int pcr_num, const uint8_t* in_digest, uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions) { - struct s_tpm_getpermissions_cmd cmd; - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint8_t* nvdata; - uint32_t result; - uint32_t size; + uint32_t dummy_attributes; + TPM_NV_AUTH_POLICY dummy_policy; + uint32_t dummy_policy_size = sizeof(dummy_policy); - memcpy(&cmd, &tpm_getpermissions_cmd, sizeof(cmd)); - ToTpmUint32(cmd.buffer + tpm_getpermissions_cmd.index, index); - result = TlclSendReceive(cmd.buffer, response, sizeof(response)); - if (result != TPM_SUCCESS) + return TlclGetSpaceInfo(index, permissions, &dummy_attributes, + &dummy_policy, &dummy_policy_size); +} + +static int DecodePCRInfo(const uint8_t** cursor, + const uint8_t* end, + TPM_PCR_INFO_SHORT* pcr_info) +{ + const size_t available_size = end - *cursor; + if (available_size < sizeof(uint16_t)) { + return 0; + } + + uint16_t size_of_select = 0; + FromTpmUint16(*cursor, &size_of_select); + + /* Compute the actual size of the encoded PCR selection (which is a + * variable-length field). */ + const size_t encoded_pcr_info_size = sizeof(TPM_PCR_INFO_SHORT) - + sizeof(pcr_info->pcrSelection.pcrSelect) + size_of_select; + if (available_size < encoded_pcr_info_size || + size_of_select > sizeof(pcr_info->pcrSelection.pcrSelect)) { + return 0; + } + + memset(&pcr_info->pcrSelection, 0, sizeof(pcr_info->pcrSelection)); + const size_t pcr_selection_size = + sizeof(size_of_select) + size_of_select; + memcpy(&pcr_info->pcrSelection, *cursor, pcr_selection_size); + *cursor += pcr_selection_size; + + pcr_info->localityAtRelease = **cursor; + (*cursor)++; + + memcpy(&pcr_info->digestAtRelease, *cursor, sizeof(TPM_COMPOSITE_HASH)); + *cursor += sizeof(TPM_COMPOSITE_HASH); + + return 1; +} + +uint32_t TlclGetSpaceInfo(uint32_t index, uint32_t *attributes, uint32_t *size, + void* auth_policy, uint32_t* auth_policy_size) +{ + TPM_NV_AUTH_POLICY* policy; + uint32_t buffer_size = *auth_policy_size; + *auth_policy_size = sizeof(TPM_NV_AUTH_POLICY); + if (buffer_size < sizeof(TPM_NV_AUTH_POLICY)) { + return TPM_E_BUFFER_SIZE; + } + policy = auth_policy; + + struct s_tpm_getspaceinfo_cmd cmd; + memcpy(&cmd, &tpm_getspaceinfo_cmd, sizeof(cmd)); + ToTpmUint32(cmd.buffer + tpm_getspaceinfo_cmd.index, index); + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + uint32_t result = TlclSendReceive(cmd.buffer, response, + sizeof(response)); + if (result != TPM_SUCCESS) { return result; + } - nvdata = response + kTpmResponseHeaderLength + sizeof(size); - FromTpmUint32(nvdata + kNvDataPublicPermissionsOffset, permissions); - return result; + uint32_t response_size = TpmCommandSize(response); + if (response_size > sizeof(response)) { + return TPM_E_RESPONSE_TOO_LARGE; + } + + const uint8_t* cursor = response + kTpmResponseHeaderLength; + uint32_t cap_size = ReadTpmUint32(&cursor); + if (cap_size > + response_size - sizeof(cap_size) - kTpmResponseHeaderLength) { + return TPM_E_INVALID_RESPONSE; + } + const uint8_t* end = cursor + cap_size; + + cursor += sizeof(uint16_t); /* skip tag */ + uint32_t response_index = ReadTpmUint32(&cursor); + if (index != response_index) { + return TPM_E_INVALID_RESPONSE; + } + + if (!DecodePCRInfo(&cursor, end, &policy->pcr_info_read) || + !DecodePCRInfo(&cursor, end, &policy->pcr_info_write)) { + return TPM_E_INVALID_RESPONSE; + } + + /* Make sure that the remaining data in the buffer matches the size of + * the remaining fields to decode. */ + if (end - cursor != + 2 * sizeof(uint32_t) + 3 * sizeof(uint8_t) + sizeof(uint16_t)) { + return TPM_E_INVALID_RESPONSE; + } + + cursor += sizeof(uint16_t); /* skip TPM_NV_ATTRIBUTES tag */ + *attributes = ReadTpmUint32(&cursor); + cursor += sizeof(uint8_t); /* skip bReadSTClear */ + cursor += sizeof(uint8_t); /* skip bWriteSTClear */ + cursor += sizeof(uint8_t); /* skip bWriteDefine */ + *size = ReadTpmUint32(&cursor); + + return TPM_SUCCESS; } uint32_t TlclGetOwnership(uint8_t* owned) diff --git a/tests/tlcl_tests.c b/tests/tlcl_tests.c index b7f288a3..55e897cb 100644 --- a/tests/tlcl_tests.c +++ b/tests/tlcl_tests.c @@ -465,6 +465,83 @@ static void PcrTest(void) TEST_EQ(calls[0].req_cmd, TPM_ORD_Extend, " cmd"); } +/** + * Test TlclGetSpaceInfo. + */ +static void GetSpaceInfoTest(void) +{ + uint8_t response[] = { + 0x00, 0xc4, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x18, + 0x20, 0x00, 0x00, 0x04, 0x00, 0x03, 0x01, 0x00, + 0x00, 0x01, 0xb3, 0x2b, 0x96, 0x30, 0xd3, 0x21, + 0x1e, 0x99, 0x78, 0x9e, 0xd3, 0x1f, 0x11, 0x8e, + 0x96, 0xbc, 0xf7, 0x7e, 0x7b, 0x06, 0x00, 0x03, + 0x20, 0x00, 0x00, 0x10, 0x3b, 0xb2, 0x69, 0x03, + 0x3d, 0x12, 0xe1, 0x99, 0x87, 0xe9, 0x3d, 0xf1, + 0x11, 0xe8, 0x69, 0xcb, 0x7f, 0xe7, 0xb7, 0x60, + 0x00, 0x17, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x45, + }; + + uint32_t attributes = 0; + uint32_t size = 0; + TPM_NV_AUTH_POLICY policy; + uint32_t policy_size = sizeof(policy); + + /* Test successful parsing. */ + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + TEST_EQ(TlclGetSpaceInfo(0x20000004, &attributes, &size, &policy, + &policy_size), + TPM_SUCCESS, "GetSpaceInfo"); + TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); + TEST_EQ(policy_size, sizeof(policy), " policy_size"); + TEST_EQ(attributes, TPM_NV_PER_WRITEDEFINE, " attributes"); + TEST_EQ(size, 0x45, " size"); + TEST_EQ(memcmp(&policy, response + 20, sizeof(policy)), 0, " policy"); + + /* Test that GetPermissions returns the attributes as well. */ + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + TEST_EQ(TlclGetPermissions(0x20000004, &attributes), + TPM_SUCCESS, "GetPermissions"); + TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); + TEST_EQ(attributes, TPM_NV_PER_WRITEDEFINE, " attributes"); + + /* Test whether a short response gets detected. */ + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + ToTpmUint32(response + 10, 0x46); + TEST_EQ(TlclGetSpaceInfo(0x20000004, &attributes, &size, &policy, + &policy_size), + TPM_E_INVALID_RESPONSE, "GetSpaceInfo short length"); + ToTpmUint32(response + 10, 0x47); + + /* Test whether an overlong PCR selection length causes failure. */ + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + ToTpmUint16(response + 20, 4); + TEST_EQ(TlclGetSpaceInfo(0x20000004, &attributes, &size, &policy, + &policy_size), + TPM_E_INVALID_RESPONSE, "GetSpaceInfo overlong pcr selection"); + ToTpmUint16(response + 20, 3); + + /* Test that a short policy buffer triggers an error. */ + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + policy_size = sizeof(policy) - 1; + TEST_EQ(TlclGetSpaceInfo(0x20000004, &attributes, &size, &policy, + &policy_size), + TPM_E_BUFFER_SIZE, "GetSpaceInfo short policy buffer"); + TEST_EQ(sizeof(policy), policy_size, " policy_size"); +} + /** * Test flags / capabilities * @@ -475,7 +552,6 @@ static void FlagsTest(void) TPM_PERMANENT_FLAGS pflags; TPM_STCLEAR_FLAGS vflags; uint8_t disable = 0, deactivated = 0, nvlocked = 0; - uint32_t u; uint8_t buf[32]; ResetMocks(); @@ -492,10 +568,6 @@ static void FlagsTest(void) ResetMocks(); TEST_EQ(TlclGetFlags(&disable, &deactivated, &nvlocked), 0, "GetFlags"); - ResetMocks(); - TEST_EQ(TlclGetPermissions(1, &u), 0, "GetPermissions"); - TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); - ResetMocks(); TEST_EQ(TlclGetOwnership(buf), 0, "GetOwnership"); TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); @@ -1084,6 +1156,7 @@ int main(void) DefineSpaceExTest(); InitNvAuthPolicyTest(); PcrTest(); + GetSpaceInfoTest(); FlagsTest(); RandomTest(); GetVersionTest(); diff --git a/utility/tlcl_generator.c b/utility/tlcl_generator.c index c545bed1..c021ed36 100644 --- a/utility/tlcl_generator.c +++ b/utility/tlcl_generator.c @@ -338,14 +338,14 @@ Command* BuildGetSTClearFlagsCommand(void) { return cmd; } -Command* BuildGetPermissionsCommand(void) { +Command* BuildGetSpaceInfoCommand(void) { int size = (kTpmRequestHeaderLength + sizeof(TPM_CAPABILITY_AREA) + /* capArea */ sizeof(uint32_t) + /* subCapSize */ sizeof(uint32_t)); /* subCap */ Command* cmd = newCommand(TPM_ORD_GetCapability, size); - cmd->name = "tpm_getpermissions_cmd"; + cmd->name = "tpm_getspaceinfo_cmd"; AddInitializedField(cmd, kTpmRequestHeaderLength, sizeof(TPM_CAPABILITY_AREA), TPM_CAP_NV_INDEX); AddInitializedField(cmd, kTpmRequestHeaderLength + @@ -634,7 +634,7 @@ Command* (*builders[])(void) = { BuildPhysicalSetDeactivatedCommand, BuildGetFlagsCommand, BuildGetSTClearFlagsCommand, - BuildGetPermissionsCommand, + BuildGetSpaceInfoCommand, BuildGetOwnershipCommand, BuildGetRandomCommand, BuildExtendCommand, @@ -676,9 +676,6 @@ int main(void) { printf("/* This file is automatically generated */\n\n"); OutputCommands(commands); printf("const int kWriteInfoLength = %d;\n", (int) sizeof(TPM_WRITE_INFO)); - printf("const int kNvDataPublicPermissionsOffset = %d;\n", - (int) (offsetof(TPM_NV_DATA_PUBLIC, permission) + - offsetof(TPM_NV_ATTRIBUTES, attributes))); FreeCommands(commands); return 0; -- cgit v1.2.1