summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Pronin <apronin@google.com>2016-07-22 18:45:07 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-07-26 17:31:56 -0700
commit0960682caa1fd27539b0c2100e4f8766ebe66640 (patch)
treeb1cf5c1004163ffe3bd6277ba3e9d88f3d1d236b
parentca7251286655fe8865d0089bfc23b42ffececbf3 (diff)
downloadvboot-0960682caa1fd27539b0c2100e4f8766ebe66640.tar.gz
Implement GetCapabilities and reading flags for tpm2
For TPM2.0: 1) Implement TPM2_GetCapabilities command that allows reading TPM properties, including PERMANENT and STARTUP_CLEAR flags. 2) Implement 'getpf' and 'getvf' commands in tpmc. BRANCH=none BUG=chrome-os-partner:55210 BUG=chrome-os-partner:55250 TEST=boot on kevin, verify 'tpmc getpf' and 'tpmc getvf' Change-Id: I8490b2c92ebf7c266e27b7cb5898126a1b99b1a8 Reviewed-on: https://chromium-review.googlesource.com/362770 Commit-Ready: Andrey Pronin <apronin@chromium.org> Tested-by: Andrey Pronin <apronin@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--firmware/include/tpm2_tss_constants.h66
-rw-r--r--firmware/lib/tpm2_lite/marshaling.c109
-rw-r--r--firmware/lib/tpm2_lite/tlcl.c49
-rw-r--r--utility/tpmc.c30
4 files changed, 225 insertions, 29 deletions
diff --git a/firmware/include/tpm2_tss_constants.h b/firmware/include/tpm2_tss_constants.h
index 5a4b49fe..98df06e4 100644
--- a/firmware/include/tpm2_tss_constants.h
+++ b/firmware/include/tpm2_tss_constants.h
@@ -21,6 +21,7 @@
#define TPM2_NV_Write ((TPM_CC)0x00000137)
#define TPM2_NV_WriteLock ((TPM_CC)0x00000138)
#define TPM2_NV_Read ((TPM_CC)0x0000014E)
+#define TPM2_GetCapability ((TPM_CC)0x0000017A)
/* TCG Spec defined, verify for TPM2.
* TODO(apronin): find TPM2 RC substitutes for TPM1.2 error codes.
@@ -37,12 +38,25 @@
#define TPM_RH_PLATFORM 0x4000000C
#define TPM_RS_PW 0x40000009
+/* TPM2 capabilities. */
+#define TPM_CAP_FIRST ((TPM_CAP)0x00000000)
+#define TPM_CAP_TPM_PROPERTIES ((TPM_CAP)0x00000006)
+
+/* TPM properties */
+#define TPM_PT_NONE ((TPM_PT)0x00000000)
+#define PT_GROUP ((TPM_PT)0x00000100)
+#define PT_FIXED PT_GROUP
+#define PT_VAR (PT_GROUP * 2)
+#define TPM_PT_PERMANENT (PT_VAR + 0)
+#define TPM_PT_STARTUP_CLEAR (PT_VAR + 1)
typedef uint8_t TPMI_YES_NO;
typedef uint32_t TPM_CC;
typedef uint32_t TPM_HANDLE;
typedef TPM_HANDLE TPMI_RH_NV_INDEX;
typedef TPM_HANDLE TPMI_RH_ENABLES;
+typedef uint32_t TPM_CAP;
+typedef uint32_t TPM_PT;
typedef struct {
uint16_t size;
@@ -57,6 +71,25 @@ typedef union {
TPM2B b;
} TPM2B_MAX_NV_BUFFER;
+typedef struct {
+ TPM_PT property;
+ uint32_t value;
+} TPMS_TAGGED_PROPERTY;
+
+typedef struct {
+ uint32_t count;
+ TPMS_TAGGED_PROPERTY tpm_property[1];
+} TPML_TAGGED_TPM_PROPERTY;
+
+typedef union {
+ TPML_TAGGED_TPM_PROPERTY tpm_properties;
+} TPMU_CAPABILITIES;
+
+typedef struct {
+ TPM_CAP capability;
+ TPMU_CAPABILITIES data;
+} TPMS_CAPABILITY_DATA;
+
struct tpm2_nv_read_cmd {
TPMI_RH_NV_INDEX nvIndex;
uint16_t size;
@@ -78,6 +111,12 @@ struct tpm2_hierarchy_control_cmd {
TPMI_YES_NO state;
};
+struct tpm2_get_capability_cmd {
+ TPM_CAP capability;
+ uint32_t property;
+ uint32_t property_count;
+};
+
/* Common command/response header. */
struct tpm_header {
uint16_t tpm_tag;
@@ -112,18 +151,39 @@ struct tpm2_session_header {
uint8_t *auth;
};
+struct get_capability_response {
+ TPMI_YES_NO more_data;
+ TPMS_CAPABILITY_DATA capability_data;
+} __attribute__((packed));
+
struct tpm2_response {
struct tpm_header hdr;
union {
struct nv_read_response nvr;
struct tpm2_session_header def_space;
+ struct get_capability_response cap;
};
};
+typedef struct {
+ uint32_t ownerAuthSet : 1;
+ uint32_t endorsementAuthSet : 1;
+ uint32_t lockoutAuthSet : 1;
+ uint32_t reserved3_7 : 5;
+ uint32_t disableClear : 1;
+ uint32_t inLockout : 1;
+ uint32_t tpmGeneratedEPS : 1;
+ uint32_t reserved11_31 : 21;
+} TPM_PERMANENT_FLAGS;
-/* Temp stubs to quiet down compilation errors. */
-typedef struct {} TPM_PERMANENT_FLAGS;
-typedef struct {} TPM_STCLEAR_FLAGS;
+typedef struct {
+ uint32_t phEnable : 1;
+ uint32_t shEnable : 1;
+ uint32_t ehEnable : 1;
+ uint32_t phEnableNV : 1;
+ uint32_t reserved4_30 : 27;
+ uint32_t orderly : 1;
+} TPM_STCLEAR_FLAGS;
/* TODO(apronin): For TPM2 certain properties must be received using
* TPM2_GetCapability instead of being hardcoded as they are now:
diff --git a/firmware/lib/tpm2_lite/marshaling.c b/firmware/lib/tpm2_lite/marshaling.c
index 3a22b682..61f726c4 100644
--- a/firmware/lib/tpm2_lite/marshaling.c
+++ b/firmware/lib/tpm2_lite/marshaling.c
@@ -53,6 +53,22 @@ static inline uint32_t read_be32(const void *src)
* has been extracted from the buffer.
*/
+static uint8_t unmarshal_u8(void **buffer, int *buffer_space)
+{
+ uint8_t value;
+
+ if (*buffer_space < sizeof(value)) {
+ *buffer_space = -1; /* Indicate a failure. */
+ return 0;
+ }
+
+ value = *(uint8_t *)(*buffer);
+ *buffer = (void *) ((uintptr_t) (*buffer) + sizeof(value));
+ *buffer_space -= sizeof(value);
+
+ return value;
+}
+
static uint16_t unmarshal_u16(void **buffer, int *buffer_space)
{
uint16_t value;
@@ -103,6 +119,22 @@ static void unmarshal_TPM2B_MAX_NV_BUFFER(void **buffer,
*size -= nv_buffer->t.size;
}
+static void unmarshal_authorization_section(void **buffer, int *size,
+ char *cmd_name)
+{
+ /*
+ * Let's ignore the authorisation section. It should be 5 bytes total,
+ * just confirm that this is the case and report any discrepancy.
+ */
+ if (*size != 5)
+ VBDEBUG(("%s:%d - unexpected authorisation section size %d "
+ "for %s\n",
+ __func__, __LINE__, *size, cmd_name));
+
+ *buffer = ((uint8_t *)(*buffer)) + *size;
+ *size = 0;
+}
+
static void unmarshal_nv_read(void **buffer, int *size,
struct nv_read_response *nvr)
{
@@ -120,16 +152,54 @@ static void unmarshal_nv_read(void **buffer, int *size,
if (*size < 0)
return;
- /*
- * Let's ignore the authorisation section. It should be 5 bytes total,
- * just confirm that this is the case and report any discrepancy.
- */
- if (*size != 5)
- VBDEBUG(("%s:%d - unexpected authorisation seciton size %d\n",
- __func__, __LINE__, *size));
- *buffer = ((uint8_t *)(*buffer)) + *size;
- *size = 0;
+ unmarshal_authorization_section(buffer, size, "NV_Read");
+}
+
+static void unmarshal_TPML_TAGGED_TPM_PROPERTY(void **buffer, int *size,
+ TPML_TAGGED_TPM_PROPERTY *prop)
+{
+ prop->count = unmarshal_u32(buffer, size);
+
+ if (prop->count != 1) {
+ *size = -1;
+ VBDEBUG(("%s:%d:Request to unmarshal unsupported "
+ "number of properties: %u\n",
+ __FILE__, __LINE__, prop->count));
+ return;
+ }
+
+ prop->tpm_property[0].property = unmarshal_u32(buffer, size);
+ prop->tpm_property[0].value = unmarshal_u32(buffer, size);
+}
+
+static void unmarshal_TPMS_CAPABILITY_DATA(void **buffer, int *size,
+ TPMS_CAPABILITY_DATA *cap_data)
+{
+ cap_data->capability = unmarshal_u32(buffer, size);
+
+ switch (cap_data->capability) {
+
+ case TPM_CAP_TPM_PROPERTIES:
+ unmarshal_TPML_TAGGED_TPM_PROPERTY(buffer, size,
+ &cap_data->data.
+ tpm_properties);
+ break;
+
+ default:
+ *size = -1;
+ VBDEBUG(("%s:%d:Request to unmarshal unsupported "
+ "capability %#x\n",
+ __FILE__, __LINE__, cap_data->capability));
+ }
+}
+
+static void unmarshal_get_capability(void **buffer, int *size,
+ struct get_capability_response *cap)
+{
+ /* Total size of the parameter field. */
+ cap->more_data = unmarshal_u8(buffer, size);
+ unmarshal_TPMS_CAPABILITY_DATA(buffer, size, &cap->capability_data);
}
@@ -309,6 +379,18 @@ static void marshal_hierarchy_control(void **buffer,
marshal_u8(buffer, command_body->state, buffer_space);
}
+static void marshal_get_capability(void **buffer,
+ struct tpm2_get_capability_cmd
+ *command_body,
+ int *buffer_space)
+{
+ tpm_tag = TPM_ST_NO_SESSIONS;
+
+ marshal_u32(buffer, command_body->capability, buffer_space);
+ marshal_u32(buffer, command_body->property, buffer_space);
+ marshal_u32(buffer, command_body->property_count, buffer_space);
+}
+
int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
void *buffer, int buffer_size)
{
@@ -338,6 +420,10 @@ int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
tpm_command_body, &body_size);
break;
+ case TPM2_GetCapability:
+ marshal_get_capability(&cmd_body, tpm_command_body, &body_size);
+ break;
+
default:
body_size = -1;
VBDEBUG(("%s:%d:Request to marshal unsupported command %#x\n",
@@ -385,6 +471,11 @@ struct tpm2_response *tpm_unmarshal_response(TPM_CC command,
&tpm2_resp.nvr);
break;
+ case TPM2_GetCapability:
+ unmarshal_get_capability(&response_body, &cr_size,
+ &tpm2_resp.cap);
+ break;
+
case TPM2_Hierarchy_Control:
case TPM2_NV_Write:
case TPM2_NV_WriteLock:
diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c
index ae1fa5d8..9d7e1dfb 100644
--- a/firmware/lib/tpm2_lite/tlcl.c
+++ b/firmware/lib/tpm2_lite/tlcl.c
@@ -163,18 +163,59 @@ uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions)
return TPM_SUCCESS;
}
-uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS *pflags)
+static uint32_t tlcl_get_capability(TPM_CAP cap, TPM_PT property,
+ struct get_capability_response **presp)
{
- VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
+ struct tpm2_response *response;
+ struct tpm2_get_capability_cmd getcap;
+
+ 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;
+
return TPM_SUCCESS;
}
-uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS *pflags)
+static uint32_t tlcl_get_tpm_property(TPM_PT property, uint32_t *pvalue)
{
- VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
+ uint32_t rv;
+ struct get_capability_response *resp;
+ TPML_TAGGED_TPM_PROPERTY *tpm_prop;
+
+ rv = tlcl_get_capability(TPM_CAP_TPM_PROPERTIES, property, &resp);
+ if (rv != TPM_SUCCESS)
+ return rv;
+
+ if (resp->capability_data.capability != TPM_CAP_TPM_PROPERTIES)
+ return TPM_E_IOERROR;
+
+ tpm_prop = &resp->capability_data.data.tpm_properties;
+
+ if ((tpm_prop->count != 1) ||
+ (tpm_prop->tpm_property[0].property != property))
+ return TPM_E_IOERROR;
+
+ *pvalue = tpm_prop->tpm_property[0].value;
return TPM_SUCCESS;
}
+uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS *pflags)
+{
+ return tlcl_get_tpm_property(TPM_PT_PERMANENT,
+ (uint32_t *)pflags);
+}
+
+uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS *pflags)
+{
+ return tlcl_get_tpm_property(TPM_PT_STARTUP_CLEAR,
+ (uint32_t *)pflags);
+}
+
uint32_t TlclGetOwnership(uint8_t *owned)
{
*owned = 0;
diff --git a/utility/tpmc.c b/utility/tpmc.c
index 8d2ed241..f621661e 100644
--- a/utility/tpmc.c
+++ b/utility/tpmc.c
@@ -322,23 +322,19 @@ static uint32_t HandlerGetRandom(void) {
return result;
}
-/* TODO(apronin): stubs for permanent and ST_CLEAR flags for TPM2 */
-#ifdef TPM2_MODE
-static uint32_t HandlerGetPermanentFlags(void) {
- fprintf(stderr, "getpermanentflags not implemented for TPM2\n");
- return OTHER_ERROR;
-}
-
-static uint32_t HandlerGetSTClearFlags(void) {
- fprintf(stderr, "getstclearflags not implemented for TPM2\n");
- return OTHER_ERROR;
-}
-#else
static uint32_t HandlerGetPermanentFlags(void) {
TPM_PERMANENT_FLAGS pflags;
uint32_t result = TlclGetPermanentFlags(&pflags);
if (result == 0) {
#define P(name) printf("%s %d\n", #name, pflags.name)
+#ifdef TPM2_MODE
+ P(ownerAuthSet);
+ P(endorsementAuthSet);
+ P(lockoutAuthSet);
+ P(disableClear);
+ P(inLockout);
+ P(tpmGeneratedEPS);
+#else
P(disable);
P(ownership);
P(deactivated);
@@ -359,6 +355,7 @@ static uint32_t HandlerGetPermanentFlags(void) {
P(tpmEstablished);
P(maintenanceDone);
P(disableFullDALogicInfo);
+#endif
#undef P
}
return result;
@@ -369,16 +366,23 @@ static uint32_t HandlerGetSTClearFlags(void) {
uint32_t result = TlclGetSTClearFlags(&vflags);
if (result == 0) {
#define P(name) printf("%s %d\n", #name, vflags.name)
+#ifdef TPM2_MODE
+ P(phEnable);
+ P(shEnable);
+ P(ehEnable);
+ P(phEnableNV);
+ P(orderly);
+#else
P(deactivated);
P(disableForceClear);
P(physicalPresence);
P(physicalPresenceLock);
P(bGlobalLock);
+#endif
#undef P
}
return result;
}
-#endif /* TPM2_MODE */
static uint32_t HandlerSendRaw(void) {
uint8_t request[4096];