Implement GetCapabilities and reading flags for tpm2
authorAndrey Pronin <apronin@google.com>
Sat, 23 Jul 2016 01:45:07 +0000 (18:45 -0700)
committerchrome-bot <chrome-bot@chromium.org>
Wed, 27 Jul 2016 00:31:56 +0000 (17:31 -0700)
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>
firmware/include/tpm2_tss_constants.h
firmware/lib/tpm2_lite/marshaling.c
firmware/lib/tpm2_lite/tlcl.c
utility/tpmc.c

index 5a4b49f..98df06e 100644 (file)
@@ -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.
 #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:
index 3a22b68..61f726c 100644 (file)
@@ -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:
index ae1fa5d..9d7e1df 100644 (file)
@@ -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;
index 8d2ed24..f621661 100644 (file)
@@ -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];