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 <apronin@chromium.org>
Tested-by: Andrey Pronin <apronin@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
This commit is contained in:
Andrey Pronin
2017-10-06 20:01:53 -07:00
committed by chrome-bot
parent 5d5b2f1610
commit 3b805725c1
7 changed files with 169 additions and 13 deletions

View File

@@ -208,8 +208,17 @@ uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size);
/**
* Requests version information from the TPM.
* 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);
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

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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");
}

View File

@@ -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;
}