From c1a7eb2c75c4007bddb0afc73189d9d15fb552c0 Mon Sep 17 00:00:00 2001 From: Andrey Pronin Date: Fri, 6 Oct 2017 20:01:53 -0700 Subject: tlcl, tpmc: extend GetVersion to report vendor specific data 1) Extend TlclGetVersion to return vendor specific data, if requested. 2) Extend 'tpmc getver' to include vendor specific data. BRANCH=none BUG=chromium:771561 TEST=unit tests, running 'tpmc getver' Change-Id: Ic04c242d4e6f33b45a80479be9ab9777b317ebe2 Reviewed-on: https://chromium-review.googlesource.com/706240 Commit-Ready: Andrey Pronin Tested-by: Andrey Pronin Reviewed-by: Andrey Pronin (cherry picked from commit 3b805725c15022783f0737a72b4f27962abf48cd) Reviewed-on: https://chromium-review.googlesource.com/733664 Commit-Queue: Andrey Pronin --- firmware/include/tlcl.h | 13 ++++++- firmware/include/tpm2_tss_constants.h | 2 + firmware/lib/tpm2_lite/tlcl.c | 49 ++++++++++++++++++++++++- firmware/lib/tpm_lite/mocked_tlcl.c | 7 +++- firmware/lib/tpm_lite/tlcl.c | 32 ++++++++++++++-- tests/tlcl_tests.c | 69 ++++++++++++++++++++++++++++++++--- utility/tpmc.c | 12 +++++- 7 files changed, 170 insertions(+), 14 deletions(-) diff --git a/firmware/include/tlcl.h b/firmware/include/tlcl.h index fba764c9..f8d94721 100644 --- a/firmware/include/tlcl.h +++ b/firmware/include/tlcl.h @@ -208,8 +208,17 @@ uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size); /** * Requests version information from the TPM. - */ -uint32_t TlclGetVersion(uint32_t *vendor, uint64_t *firmware_version); + * If vendor_specific_buf_size != NULL, requests also the vendor-specific + * variable-length part of the version: + * if vendor_specific_buf == NULL, determines its size and returns in + * *vendor_specific_buf_size; + * if vendor_specific_buf != NULL, fills the buffer until either the + * end of the vendor specific data or the end of the buffer, sets + * *vendor_specific_buf_size to the length of the filled data. + */ +uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version, + uint8_t* vendor_specific_buf, + size_t* vendor_specific_buf_size); /** * Issues the IFX specific FieldUpgradeInfoRequest2 TPM_FieldUpgrade subcommand diff --git a/firmware/include/tpm2_tss_constants.h b/firmware/include/tpm2_tss_constants.h index 53be3fb4..f44dc715 100644 --- a/firmware/include/tpm2_tss_constants.h +++ b/firmware/include/tpm2_tss_constants.h @@ -55,6 +55,8 @@ #define PT_GROUP ((TPM_PT)0x00000100) #define PT_FIXED PT_GROUP #define TPM_PT_MANUFACTURER (PT_FIXED + 5) +#define TPM_PT_VENDOR_STRING_1 (PT_FIXED + 6) +#define TPM_PT_VENDOR_STRING_4 (PT_FIXED + 9) #define TPM_PT_FIRMWARE_VERSION_1 (PT_FIXED + 11) #define TPM_PT_FIRMWARE_VERSION_2 (PT_FIXED + 12) #define PT_VAR (PT_GROUP * 2) diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c index bb212d24..89bf25a7 100644 --- a/firmware/lib/tpm2_lite/tlcl.c +++ b/firmware/lib/tpm2_lite/tlcl.c @@ -523,7 +523,25 @@ uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size) return TPM_E_IOERROR; } -uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version) +// Converts TPM_PT_VENDOR_STRING_x |value| to an array of bytes in |buf|. +// Returns the number of bytes in the array. +// |buf| should be at least 4 bytes long. +size_t tlcl_vendor_string_parse(uint32_t value, uint8_t* buf) +{ + size_t len = 0; + int shift = 24; + for (; len < 4; shift -= 8) { + uint8_t byte = (value >> shift) & 0xffu; + if (!byte) + break; + buf[len++] = byte; + } + return len; +} + +uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version, + uint8_t* vendor_specific_buf, + size_t* vendor_specific_buf_size) { uint32_t result = tlcl_get_tpm_property(TPM_PT_MANUFACTURER, vendor); if (result != TPM_SUCCESS) @@ -539,6 +557,35 @@ uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version) return result; *firmware_version = ((uint64_t) version_1 << 32) | version_2; + + if (!vendor_specific_buf_size) + return TPM_SUCCESS; + + size_t total_size = 0; + uint32_t prop_id; + uint8_t prop_string[16]; + for (prop_id = TPM_PT_VENDOR_STRING_1; + prop_id <= TPM_PT_VENDOR_STRING_4; + ++prop_id) { + uint32_t prop_value; + result = tlcl_get_tpm_property(prop_id, &prop_value); + if (result != TPM_SUCCESS) + break; + + size_t prop_len = tlcl_vendor_string_parse( + prop_value, prop_string + total_size); + VbAssert(prop_len <= 4 && + total_size + prop_len <= sizeof(prop_string)); + total_size += prop_len; + if (prop_len < 4) + break; + } + if (vendor_specific_buf) { + if (total_size > *vendor_specific_buf_size) + total_size = *vendor_specific_buf_size; + memcpy(vendor_specific_buf, prop_string, total_size); + } + *vendor_specific_buf_size = total_size; return TPM_SUCCESS; } diff --git a/firmware/lib/tpm_lite/mocked_tlcl.c b/firmware/lib/tpm_lite/mocked_tlcl.c index def4810b..0abcb7c9 100644 --- a/firmware/lib/tpm_lite/mocked_tlcl.c +++ b/firmware/lib/tpm_lite/mocked_tlcl.c @@ -186,10 +186,15 @@ uint32_t TlclGetRandom(uint8_t* data, uint32_t length, uint32_t *size) return TPM_SUCCESS; } -uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version) +uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version, + uint8_t* vendor_specific_buf, + size_t* vendor_specific_buf_size) { *vendor = 0x4e4f4e45; *firmware_version = 0x1; + if (vendor_specific_buf_size) { + *vendor_specific_buf_size = 0; + } return TPM_SUCCESS; } diff --git a/firmware/lib/tpm_lite/tlcl.c b/firmware/lib/tpm_lite/tlcl.c index 59dd1208..6f71f2bc 100644 --- a/firmware/lib/tpm_lite/tlcl.c +++ b/firmware/lib/tpm_lite/tlcl.c @@ -513,7 +513,10 @@ uint32_t TlclGetRandom(uint8_t* data, uint32_t length, uint32_t *size) return result; } -uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version) { +uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version, + uint8_t* vendor_specific_buf, + size_t* vendor_specific_buf_size) +{ uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; uint32_t result = TlclSendReceive(tpm_getversionval_cmd.buffer, response, sizeof(response)); @@ -528,7 +531,9 @@ uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version) { /* Verify size >= sizeof(TPM_CAP_VERSION_INFO). */ const uint32_t kSizeofCapVersionInfo = 15; - if (size < kSizeofCapVersionInfo) { + if (size < kSizeofCapVersionInfo || + kTpmResponseHeaderLength + sizeof(size) + size > + TPM_LARGE_ENOUGH_COMMAND_SIZE) { return TPM_E_IOERROR; } @@ -546,6 +551,26 @@ uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version) { FromTpmUint32(cursor, vendor); cursor += sizeof(*vendor); + if (vendor_specific_buf_size) { + uint16_t vendor_specific_size; + FromTpmUint16(cursor, &vendor_specific_size); + cursor += sizeof(vendor_specific_size); + + if (size < kSizeofCapVersionInfo + vendor_specific_size) { + return TPM_E_IOERROR; + } + if (vendor_specific_buf) { + if (vendor_specific_size > *vendor_specific_buf_size) { + vendor_specific_size = + *vendor_specific_buf_size; + } + memcpy(vendor_specific_buf, cursor, + vendor_specific_size); + cursor += vendor_specific_size; + } + *vendor_specific_buf_size = vendor_specific_size; + } + return TPM_SUCCESS; } @@ -563,7 +588,8 @@ static void ParseIFXFirmwarePackage(uint8_t** cursor, uint32_t TlclIFXFieldUpgradeInfo(TPM_IFX_FIELDUPGRADEINFO* info) { uint32_t vendor; uint64_t firmware_version; - uint32_t result = TlclGetVersion(&vendor, &firmware_version); + uint32_t result = + TlclGetVersion(&vendor, &firmware_version, NULL, NULL); if (result != TPM_SUCCESS) { return result; } diff --git a/tests/tlcl_tests.c b/tests/tlcl_tests.c index b8d64a86..c2f3681c 100644 --- a/tests/tlcl_tests.c +++ b/tests/tlcl_tests.c @@ -351,19 +351,54 @@ static void GetVersionTest(void) uint32_t vendor; uint64_t firmware_version; + uint8_t vendor_specific[32]; + size_t vendor_specific_size; ResetMocks(); calls[0].rsp = response; calls[0].rsp_size = sizeof(response); - TEST_EQ(TlclGetVersion(&vendor, &firmware_version), 0, "GetVersion"); + TEST_EQ(TlclGetVersion(&vendor, &firmware_version, NULL, NULL), 0, + "GetVersion"); TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); TEST_EQ(vendor, 0x49465800, " vendor"); TEST_EQ(firmware_version, 0x420, " firmware_version"); + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + vendor_specific_size = 100; + TEST_EQ(TlclGetVersion(&vendor, &firmware_version, + NULL, &vendor_specific_size), 0, + "GetVersion - vendor specific size"); + TEST_EQ(vendor_specific_size, 0xd, " vendor specific size"); + + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + vendor_specific_size = sizeof(vendor_specific); + TEST_EQ(TlclGetVersion(&vendor, &firmware_version, + vendor_specific, &vendor_specific_size), 0, + "GetVersion - vendor specific data"); + TEST_EQ(vendor_specific_size, 0xd, " vendor specific size"); + TEST_EQ(memcmp(vendor_specific, response + 29, 0xd), 0, + " vendor specific data check"); + + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + vendor_specific_size = 4; + TEST_EQ(TlclGetVersion(&vendor, &firmware_version, + vendor_specific, &vendor_specific_size), 0, + "GetVersion - vendor specific data, short buf"); + TEST_EQ(vendor_specific_size, 4, + " min(vendor specific size, buf size)"); + TEST_EQ(memcmp(vendor_specific, response + 29, 4), 0, + " vendor specific data check"); + ResetMocks(); SetResponse(0, TPM_E_IOERROR, 0); - TEST_EQ(TlclGetVersion(&vendor, &firmware_version), TPM_E_IOERROR, - "GetVersion - error"); + TEST_EQ(TlclGetVersion(&vendor, &firmware_version, NULL, NULL), + TPM_E_IOERROR, "GetVersion - error"); TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); /* Adjust response to indicate a 1 byte too short payload size. */ @@ -371,8 +406,32 @@ static void GetVersionTest(void) ResetMocks(); calls[0].rsp = response; calls[0].rsp_size = sizeof(response); - TEST_EQ(TlclGetVersion(&vendor, &firmware_version), TPM_E_IOERROR, - "GetVersion -- short"); + TEST_EQ(TlclGetVersion(&vendor, &firmware_version, NULL, NULL), + TPM_E_IOERROR, "GetVersion -- short"); + TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); + + /* Adjust response to indicate a payload size too long for the + * response buffer. */ + ToTpmUint32(response + kTpmResponseHeaderLength, + TPM_LARGE_ENOUGH_COMMAND_SIZE - sizeof(uint32_t) - + kTpmResponseHeaderLength + 1); + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + TEST_EQ(TlclGetVersion(&vendor, &firmware_version, NULL, NULL), + TPM_E_IOERROR, "GetVersion -- long"); + TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); + + /* Restore the original payload length and adjust response to contain + * less vendor specific data than indicated in its size. */ + ToTpmUint32(response + kTpmResponseHeaderLength, 0x1c); + ToTpmUint16(response + 27, 0xd + 1); + ResetMocks(); + calls[0].rsp = response; + calls[0].rsp_size = sizeof(response); + TEST_EQ(TlclGetVersion(&vendor, &firmware_version, + NULL, &vendor_specific_size), TPM_E_IOERROR, + "GetVersion -- short with vendor specific"); TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd"); } diff --git a/utility/tpmc.c b/utility/tpmc.c index a36f7e94..0584e32e 100644 --- a/utility/tpmc.c +++ b/utility/tpmc.c @@ -460,10 +460,18 @@ static uint32_t HandlerSendRaw(void) { static uint32_t HandlerGetVersion(void) { uint32_t vendor; uint64_t firmware_version; - uint32_t result = TlclGetVersion(&vendor, &firmware_version); + uint8_t vendor_specific[32]; + size_t vendor_specific_size = sizeof(vendor_specific); + uint32_t result = TlclGetVersion(&vendor, &firmware_version, vendor_specific, + &vendor_specific_size); if (result == 0) { - printf("vendor %08x\nfirmware_version %016" PRIx64 "\n", + printf("vendor %08x\nfirmware_version %016" PRIx64 "\nvendor_specific ", vendor, firmware_version); + size_t n; + for (n = 0; n < vendor_specific_size; ++n) { + printf("%02x", vendor_specific[n]); + } + printf("\n"); } return result; } -- cgit v1.2.1