| /* |
| * Copyright 2016 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| * |
| * Some TPM constants and type definitions for standalone compilation for use |
| * in the firmware |
| */ |
| |
| #include "rollback_index.h" |
| #include "tpm2_marshaling.h" |
| #include "utility.h" |
| |
| static struct tpm2_response *tpm_process_command(TPM_CC command, |
| void *command_body) |
| { |
| /* Command/response buffer. */ |
| static uint8_t cr_buffer[TPM_BUFFER_SIZE]; |
| uint32_t out_size, in_size; |
| struct tpm2_response *response; |
| |
| out_size = tpm_marshal_command(command, command_body, |
| cr_buffer, sizeof(cr_buffer)); |
| if (out_size < 0) { |
| VBDEBUG(("command %#x, cr size %d\n", |
| command, out_size)); |
| return NULL; |
| } |
| |
| in_size = sizeof(cr_buffer); |
| if (VbExTpmSendReceive(cr_buffer, out_size, |
| cr_buffer, &in_size) != TPM_SUCCESS) { |
| VBDEBUG(("tpm transaction failed for %#x\n", command)); |
| return NULL; |
| } |
| |
| response = tpm_unmarshal_response(command, cr_buffer, in_size); |
| |
| VBDEBUG(("%s: command %#x, return code %#x\n", __func__, command, |
| response ? response->hdr.tpm_code : -1)); |
| |
| return response; |
| } |
| |
| /** |
| * Issue a ForceClear. The TPM error code is returned. |
| */ |
| uint32_t TlclForceClear(void) |
| { |
| VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__)); |
| return TPM_SUCCESS; |
| } |
| |
| uint32_t TlclSetDeactivated(uint8_t flag) |
| { |
| VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__)); |
| return TPM_SUCCESS; |
| } |
| |
| uint32_t TlclSetEnable(void) |
| { |
| VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__)); |
| return TPM_SUCCESS; |
| } |
| |
| |
| /** |
| * Get the permission bits for the NVRAM space with |index|. |
| */ |
| uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions) |
| { |
| *permissions = 0; |
| VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__)); |
| 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) |
| { |
| 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) |
| { |
| struct tpm2_nv_read_cmd nv_readc; |
| struct tpm2_response *response; |
| |
| Memset(&nv_readc, 0, sizeof(nv_readc)); |
| |
| nv_readc.nvIndex = HR_NV_INDEX + index; |
| nv_readc.size = length; |
| |
| response = tpm_process_command(TPM2_NV_Read, &nv_readc); |
| |
| /* Need to map tpm error codes into internal values. */ |
| if (!response) |
| return TPM_E_READ_FAILURE; |
| |
| switch (response->hdr.tpm_code) { |
| case 0: |
| break; |
| |
| case 0x28b: |
| return TPM_E_BADINDEX; |
| |
| default: |
| return TPM_E_READ_FAILURE; |
| } |
| |
| if (length > response->nvr.buffer.t.size) |
| return TPM_E_RESPONSE_TOO_LARGE; |
| |
| if (length < response->nvr.buffer.t.size) |
| return TPM_E_READ_EMPTY; |
| |
| Memcpy(data, response->nvr.buffer.t.buffer, length); |
| |
| return TPM_SUCCESS; |
| } |
| |
| uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length) |
| { |
| struct tpm2_nv_write_cmd nv_writec; |
| struct tpm2_response *response; |
| |
| Memset(&nv_writec, 0, sizeof(nv_writec)); |
| |
| nv_writec.nvIndex = HR_NV_INDEX + index; |
| nv_writec.data.t.size = length; |
| nv_writec.data.t.buffer = data; |
| |
| response = tpm_process_command(TPM2_NV_Write, &nv_writec); |
| |
| /* Need to map tpm error codes into internal values. */ |
| if (!response) |
| return TPM_E_WRITE_FAILURE; |
| |
| return TPM_SUCCESS; |
| } |