diff --git a/firmware/include/tpm2_tss_constants.h b/firmware/include/tpm2_tss_constants.h index cec91e6136..fa341c0fe8 100644 --- a/firmware/include/tpm2_tss_constants.h +++ b/firmware/include/tpm2_tss_constants.h @@ -17,8 +17,10 @@ #define TPM_ST_SESSIONS 0x8002 /* TPM2 command codes. */ -#define TPM2_NV_Write ((TPM_CC)0x00000137) -#define TPM2_NV_Read ((TPM_CC)0x0000014E) +#define TPM2_Hierarchy_Control ((TPM_CC)0x00000121) +#define TPM2_NV_Write ((TPM_CC)0x00000137) +#define TPM2_NV_WriteLock ((TPM_CC)0x00000138) +#define TPM2_NV_Read ((TPM_CC)0x0000014E) /* TCG Spec defined, verify for TPM2. */ #define TPM_E_BADINDEX ((uint32_t) 0x00000002) @@ -32,9 +34,11 @@ #define TPM_RS_PW 0x40000009 +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 struct { uint16_t size; @@ -61,6 +65,15 @@ struct tpm2_nv_write_cmd { uint16_t offset; }; +struct tpm2_nv_write_lock_cmd { + TPMI_RH_NV_INDEX nvIndex; +}; + +struct tpm2_hierarchy_control_cmd { + TPMI_RH_ENABLES enable; + TPMI_YES_NO state; +}; + /* Common command/response header. */ struct tpm_header { uint16_t tpm_tag; diff --git a/firmware/lib/tpm2_lite/marshaling.c b/firmware/lib/tpm2_lite/marshaling.c index 672ffad08b..29746cd7d5 100644 --- a/firmware/lib/tpm2_lite/marshaling.c +++ b/firmware/lib/tpm2_lite/marshaling.c @@ -273,6 +273,36 @@ static void marshal_nv_read(void **buffer, marshal_u16(buffer, command_body->offset, buffer_space); } +static void marshal_nv_write_lock(void **buffer, + struct tpm2_nv_write_lock_cmd *command_body, + int *buffer_space) +{ + struct tpm2_session_header session_header; + + tpm_tag = TPM_ST_SESSIONS; + marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space); + marshal_TPM_HANDLE(buffer, command_body->nvIndex, buffer_space); + Memset(&session_header, 0, sizeof(session_header)); + session_header.session_handle = TPM_RS_PW; + marshal_session_header(buffer, &session_header, buffer_space); +} + +static void marshal_hierarchy_control(void **buffer, + struct tpm2_hierarchy_control_cmd + *command_body, + int *buffer_space) +{ + struct tpm2_session_header session_header; + + tpm_tag = TPM_ST_SESSIONS; + marshal_TPM_HANDLE(buffer, TPM_RH_PLATFORM, buffer_space); + Memset(&session_header, 0, sizeof(session_header)); + session_header.session_handle = TPM_RS_PW; + marshal_session_header(buffer, &session_header, buffer_space); + + marshal_TPM_HANDLE(buffer, command_body->enable, buffer_space); + marshal_u8(buffer, command_body->state, buffer_space); +} int tpm_marshal_command(TPM_CC command, void *tpm_command_body, void *buffer, int buffer_size) @@ -294,6 +324,15 @@ int tpm_marshal_command(TPM_CC command, void *tpm_command_body, marshal_nv_write(&cmd_body, tpm_command_body, &body_size); break; + case TPM2_NV_WriteLock: + marshal_nv_write_lock(&cmd_body, tpm_command_body, &body_size); + break; + + case TPM2_Hierarchy_Control: + marshal_hierarchy_control(&cmd_body, + tpm_command_body, &body_size); + break; + default: body_size = -1; VBDEBUG(("%s:%d:Request to marshal unsupported command %#x\n", @@ -341,7 +380,9 @@ struct tpm2_response *tpm_unmarshal_response(TPM_CC command, &tpm2_resp.nvr); break; + case TPM2_Hierarchy_Control: case TPM2_NV_Write: + case TPM2_NV_WriteLock: /* Session data included in response can be safely ignored. */ cr_size = 0; break; diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c index 5202c600f0..efd73928d5 100644 --- a/firmware/lib/tpm2_lite/tlcl.c +++ b/firmware/lib/tpm2_lite/tlcl.c @@ -7,6 +7,7 @@ * in the firmware */ +#include "rollback_index.h" #include "tpm2_marshaling.h" #include "utility.h" @@ -73,14 +74,57 @@ uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions) return TPM_SUCCESS; } +static uint32_t tlcl_lock_nv_write(uint32_t index) +{ + struct tpm2_response *response; + struct tpm2_nv_write_lock_cmd nv_wl; + + nv_wl.nvIndex = HR_NV_INDEX + index; + response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl); + + if (!response || response->hdr.tpm_code) + return TPM_E_INTERNAL_INCONSISTENCY; + + return TPM_SUCCESS; +} + +static uint32_t tlcl_disable_platform_hierarchy(void) +{ + struct tpm2_response *response; + struct tpm2_hierarchy_control_cmd hc; + + hc.enable = TPM_RH_PLATFORM; + hc.state = 0; + + response = tpm_process_command(TPM2_Hierarchy_Control, &hc); + + if (!response || response->hdr.tpm_code) + return TPM_E_INTERNAL_INCONSISTENCY; + + return TPM_SUCCESS; +} + /** * Turn off physical presence and locks it off until next reboot. The TPM * error code is returned. + * + * The name of the function was kept to maintain the existing TPM API, but + * TPM2.0 does not have to use the Physical Presence concept. Instead it just + * removes platform authorization - this makes sure that firmware and kernel + * rollback counter spaces can not be modified. + * + * It also explicitly locks the kernel rollback counter space (the FW rollback + * counter space was locked before RW firmware started.) */ uint32_t TlclLockPhysicalPresence(void) { - VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__)); - return TPM_SUCCESS; + uint32_t rv; + + rv = tlcl_lock_nv_write(KERNEL_NV_INDEX); + if (rv == TPM_SUCCESS) + rv = tlcl_disable_platform_hierarchy(); + + return rv; } uint32_t TlclRead(uint32_t index, void* data, uint32_t length)