diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/include/tpm2_tss_constants.h | 66 | ||||
-rw-r--r-- | firmware/lib/tpm2_lite/marshaling.c | 109 | ||||
-rw-r--r-- | firmware/lib/tpm2_lite/tlcl.c | 49 |
3 files changed, 208 insertions, 16 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; |