From 4787be0c2f1c13552b080c35bc8d294f19c300a0 Mon Sep 17 00:00:00 2001 From: jinlun Date: Tue, 28 Feb 2023 19:50:44 +0800 Subject: [PATCH] add tpcm support with ipmi channel --- Makefile | 4 +- shim.c | 9 +- tpcm.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tpcm.h | 195 ++++++++++++++++++++++++++++++++++++ 4 files changed, 503 insertions(+), 4 deletions(-) create mode 100644 tpcm.c create mode 100644 tpcm.h diff --git a/Makefile b/Makefile index 115e7f0..795be0f 100644 --- a/Makefile +++ b/Makefile @@ -33,9 +33,9 @@ CFLAGS += -DENABLE_SHIM_CERT else TARGETS += $(MMNAME) $(FBNAME) endif -OBJS = shim.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o +OBJS = shim.o mok.o netboot.o cert.o replacements.o tpm.o version.o errlog.o tpcm.o KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer -ORIG_SOURCES = shim.c mok.c netboot.c replacements.c tpm.c errlog.c shim.h version.h $(wildcard include/*.h) +ORIG_SOURCES = shim.c mok.c netboot.c replacements.c tpm.c errlog.c shim.h version.h $(wildcard include/*.h) tpcm.h MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o ORIG_MOK_SOURCES = MokManager.c PasswordCrypt.c crypt_blowfish.c shim.h $(wildcard include/*.h) FALLBACK_OBJS = fallback.o tpm.o errlog.o diff --git a/shim.c b/shim.c index c81d7ea..0119a69 100644 --- a/shim.c +++ b/shim.c @@ -51,7 +51,7 @@ #include #include - +#include "tpcm.h" #define OID_EKU_MODSIGN "1.3.6.1.4.1.2312.16.1.2" static EFI_SYSTEM_TABLE *systab; @@ -1899,7 +1899,12 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath) efi_status = EFI_INVALID_PARAMETER; goto done; } - + efi_status = tpcm_ipmi_write(ImagePath, data, datasize,image_handle); + if (EFI_ERROR(efi_status)) { + PrintErrors(); + ClearErrors(); + goto done; + } /* * We need to modify the loaded image protocol entry before running * the new binary, so back it up diff --git a/tpcm.c b/tpcm.c new file mode 100644 index 0000000..358fe6d --- /dev/null +++ b/tpcm.c @@ -0,0 +1,299 @@ +#include "tpcm.h" +#include "shim.h" + +#define TRANS(value) ((((UINT32)value <<24 )&0xFF000000)|(((UINT32)value<<8)&0x00FF0000)|(((UINT32)value>>8)&0x0000FF00)|(((UINT32)value>>24)&0x000000FF)) + +static EFI_GUID hash2_service_binding_guid = SHIM_EFI_HASH2_SERVICE_BINDING_PROTOCOL_GUID; +static EFI_GUID hash2_guid = SHIM_EFI_HASH2_PROTOCOL_GUID; +static EFI_GUID sm3_guid = SHIM_HASH_ALGORITHM_SM3_GUID; +static EFI_GUID gIpmiInterfaceProtocolGuid = EFI_TPCM_GUID; + +static shim_efi_ipmi_interface_protocol_t *tpcm_ipmi; +static UINT32 bm_stage_base = 1500; + +static void httc_util_dump_hex (const CHAR16 *name, void *p, int bytes) +{ + + int i = 0; + char *data = p; + int add_newline = 1; + console_print(L"%s length=%d:\n", name, bytes); + if (bytes != 0) { + console_print(L"%02x ", (unsigned char)data[i]); + i++; + } + while (i < bytes) { + console_print(L"%02x ", (unsigned char)data[i]); + i++; + if (i % 16 == 0) { + console_print(L"\n"); + add_newline = 0; + } else { + add_newline = 1; + } + } + if (add_newline) { + console_print(L"\n"); + } +} + +static EFI_HANDLE +shim_efi_service_binding (EFI_GUID *service_binding_guid, EFI_HANDLE image_handle) +{ + EFI_SERVICE_BINDING *service; + EFI_STATUS efi_status; + EFI_HANDLE child_dev = NULL; + + efi_status = LibLocateProtocol(service_binding_guid, (VOID **) &service); + if (EFI_ERROR(efi_status)) { + console_print(L"LibLocateProtocol failed\n"); + return NULL; + } + if (!service) { + console_print(L"couldn't open efi service binding protocol\n"); + return NULL; + } + efi_status = service->CreateChild(service, &child_dev); + if (EFI_ERROR(efi_status)) { + console_print(L"Failed to create child device of http service %x\n", efi_status); + return NULL; + } + return child_dev; +} + +static EFI_STATUS +shim_efi_hash (unsigned char *buf, size_t size, EFI_HANDLE image_handle, unsigned char *content) +{ + EFI_STATUS efi_status = EFI_SUCCESS; + shim_efi_hash2_protocol_t *hash2; + EFI_HANDLE hash_handle = NULL; + unsigned char output[DEFAULT_HASH_SIZE] = {0}; + console_print(L"shim_efi_hash binding service.\n"); + hash_handle = shim_efi_service_binding (&hash2_service_binding_guid, image_handle); + if (!hash_handle) { + console_print(L"hash2 service binding failed.\n"); + return EFI_INVALID_PARAMETER; + } + console_print(L"shim_efi_hash binding service success.\n"); + + efi_status = gBS->OpenProtocol(hash_handle, &hash2_guid, + (VOID **) &hash2, image_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(efi_status)) { + console_print(L"shim_efi_hash: gBS->OpenProtocol fail\n"); + return efi_status; + } + if (!hash2) { + console_print(L"hash2 protocol open failed.\n"); + return EFI_INVALID_PARAMETER; + } + console_print(L"shim_efi_hash get protocol success.\n"); + efi_status = hash2->hash_init(hash2, &sm3_guid); + if (efi_status != EFI_SUCCESS) { + console_print(L"hash_init failed.\n"); + return efi_status; + } + efi_status = hash2->hash_update(hash2, buf, size); + if (efi_status != EFI_SUCCESS) { + console_print(L"hash_update failed.\n"); + return efi_status; + } + efi_status = hash2->hash_final(hash2, (shim_efi_hash2_output *)output); + if (efi_status != EFI_SUCCESS) { + console_print(L"hash_final failed.\n"); + return efi_status; + } + httc_util_dump_hex (L"tpcm BIOS hash output: ", output, DEFAULT_HASH_SIZE); + memcpy (content, output, DEFAULT_HASH_SIZE); + return EFI_SUCCESS; +} + +static BOOLEAN +shim_tpcm_measure_switch () +{ + EFI_STATUS efi_status = EFI_SUCCESS; + shim_ipmi_cmd_header request = {IPMI_BMC_LUN, + IPMI_NETFN_OEM, + IPMI_CMD_GET_MEASURE_PARM}; + OEM_BMC_GET_RESULT_REQUSET get_tpcm_request_value; + OEM_BMC_GET_RESULT_RESPONSE get_tpcm_response_value; + UINT8 response_length; + + memset(&get_tpcm_request_value, 0, sizeof(get_tpcm_request_value)); + memset(&get_tpcm_response_value, 0, sizeof(get_tpcm_response_value)); + get_tpcm_request_value.OemSignature[0] = 0xDB; + get_tpcm_request_value.OemSignature[1] = 0x07; + get_tpcm_request_value.OemSignature[2] = 0x00; + get_tpcm_request_value.SubCmd = IPMI_SUB_CMD_SWITCH_REQ; + get_tpcm_request_value.FirmwareType = IPMI_FW_OS; + get_tpcm_request_value.FirmwareDetailType = IPMI_FW_DETAIL_GRUB; + response_length = sizeof(OEM_BMC_GET_RESULT_RESPONSE); + + efi_status = tpcm_ipmi->excute_ipmi_cmd(tpcm_ipmi, request, &get_tpcm_request_value, + sizeof(get_tpcm_request_value), &get_tpcm_response_value, + &response_length, NULL); + + if (efi_status != EFI_SUCCESS) { + console_print(L"ipmi get tpcm switch failed.\n"); + return FALSE; + } + + if (get_tpcm_response_value.ControlResult != IPMI_SWITCH_OPEN) { + console_print(L"tpcm switch close, skip measure.\n"); + return FALSE; + } + + return TRUE; +} + +static void +shim_tpcm_fillup_content (OEM_BMC_MEASURE_REQUSET *request_data, unsigned char *output, CHAR16 *description) +{ + UINT32 filename_len = StrLen (description) * 2 + 1; + request_data->FirmwareHashContent.uiCmdTag = TRANS (TPCM_TAG_REQ_COMMAND); + request_data->FirmwareHashContent.uiCmdLength = TRANS (sizeof (extern_simple_bmeasure_req_st)); + request_data->FirmwareHashContent.uiCmdCode = TRANS (TPCM_ORD_ExternSimpleBootMeasure); + request_data->FirmwareHashContent.uiPcr = TRANS (0); + + UINT32 stage_base = bm_stage_base++; + request_data->FirmwareHashContent.uiStage = TRANS (stage_base); + + memcpy ((UINT8 *)(request_data->FirmwareHashContent.uaDigest), + output, DEFAULT_HASH_SIZE); + request_data->FirmwareHashContent.uiObjLen = TRANS (filename_len); + + memcpy ((UINT8 *)(request_data->FirmwareHashContent.uaObj), + description, filename_len); + request_data->FirmwareHashContent.uaObj[filename_len - 1] = '\0'; +} + +static EFI_STATUS +shim_tpcm_log_event (unsigned char *buf, size_t size, CHAR16 *description, EFI_HANDLE image_handle) +{ + EFI_STATUS efi_status = EFI_SUCCESS; + shim_ipmi_cmd_header request = {IPMI_BMC_LUN, + IPMI_NETFN_OEM, + IPMI_CMD_GET_MEASURE_PARM}; + OEM_BMC_MEASURE_REQUSET *request_data = NULL; + OEM_BMC_MEASURE_RESPONSE response_data; + OEM_BMC_GET_RESULT_REQUSET get_result_request_data; + OEM_BMC_GET_RESULT_RESPONSE get_result_response_data; + + unsigned char output[DEFAULT_HASH_SIZE] = {0}; + UINT8 response_length; + UINT16 timeout_ms = SHIM_IPMI_TIMEOUT_MS; + UINT32 cmd_len = sizeof(extern_simple_bmeasure_req_st); + + request_data = (OEM_BMC_MEASURE_REQUSET *)malloc(sizeof(OEM_BMC_MEASURE_REQUSET)); + memset(request_data, 0, sizeof(OEM_BMC_MEASURE_REQUSET)); + memset(&response_data, 0, sizeof(response_data)); + memset(&get_result_request_data, 0, sizeof(get_result_request_data)); + memset(&get_result_response_data, 0, sizeof(get_result_response_data)); +console_print(L"shim start\n"); + request_data->OemSignature[0] = 0xDB; + request_data->OemSignature[1] = 0x07; + request_data->OemSignature[2] = 0x00; + request_data->SubCmd = IPMI_SUB_CMD_MEASURE_REQ; + request_data->FirmwareType = IPMI_FW_SHIM_GRUB; + request_data->FirmwareDetailType = IPMI_FW_DETAIL_GRUB; + request_data->FirmwareHashAlgorithmType = SM3_HASH; + get_result_request_data.FirmwareDetailType = IPMI_FW_DETAIL_GRUB; + response_length = sizeof(OEM_BMC_MEASURE_RESPONSE); +//计算grub度量 +// 是否需要判断 + //efi_status = get_firmware_hash_content(buf, size, output, image_handle); + efi_status = shim_efi_hash (buf, size, image_handle, output); + if (efi_status != EFI_SUCCESS) { + console_print(L"get firmware hash content failed\n"); + goto out; + } + request_data->FirmwareHashLen = cmd_len; + shim_tpcm_fillup_content (request_data, output, description); + + console_print(L"get_firmware_hash_content\n"); + console_print(L"sizeof(request_data)=%d\n", sizeof(request_data)); + console_print(L"sizeof(OEM_BMC_MEASURE_REQUSET)=%d\n", sizeof(OEM_BMC_MEASURE_REQUSET)); + +//发送度量请求 + efi_status = tpcm_ipmi->excute_ipmi_cmd(tpcm_ipmi, request, request_data, + (UINT8) sizeof(OEM_BMC_MEASURE_REQUSET), &response_data, + &response_length, NULL); + if (efi_status != EFI_SUCCESS) { + console_print(L"ipmi protocol open failed\n"); + goto out; + } + console_print(L"ipmi protocol: send tpcm measure request success\n"); + +//获取度量结果 + get_result_request_data.OemSignature[0] = 0xDB; + get_result_request_data.OemSignature[1] = 0x07; + get_result_request_data.OemSignature[2] = 0x00; + get_result_request_data.SubCmd = IPMI_SUB_CMD_CONTROL_REQ; + get_result_request_data.FirmwareType = IPMI_FW_SHIM_GRUB; + + response_length = sizeof(OEM_BMC_GET_RESULT_RESPONSE); + + while (timeout_ms > 0) { + msleep(200); + timeout_ms -= 200; + console_print(L"get result request: request_size[%d], response_length[%d]\n", sizeof(get_result_request_data), response_length); + efi_status = tpcm_ipmi->excute_ipmi_cmd(tpcm_ipmi, request, &get_result_request_data, + sizeof(get_result_request_data), &get_result_response_data, + &response_length, NULL); + console_print(L"huawe iana = [ 0x%X %X %X ], ControlResult = %d\n", get_result_response_data.OemSignature[0], get_result_response_data.OemSignature[1], get_result_response_data.OemSignature[2], get_result_response_data.ControlResult); + if (efi_status != EFI_SUCCESS) { + console_print(L"EFI : attempt to get measurement result failed, ret=%d\n", efi_status); + continue; + } + if (response_length == sizeof(OEM_BMC_GET_RESULT_RESPONSE) && get_result_response_data.ControlResult != IPMI_MEASURE_UNKNOW) { + console_print(L"ipmi protocol: get tpcm measurement result success\n"); + break; + } + } + +// 决定是否启动grub + if (get_result_response_data.ControlResult == IPMI_MEASURE_SUCCESS) { + efi_status = EFI_SUCCESS; + } else { + efi_status = EFI_INVALID_PARAMETER; + console_print(L"Error: the tpcm measurement result does not pass, and the startup is rejected"); + } + +out: + if(request_data){ + free(request_data); + request_data = NULL; + } + return efi_status; +} + +static EFI_STATUS +tpcm_ipmi_measure (unsigned char *buf, size_t size, void *description, EFI_HANDLE image_handle) +{ + EFI_STATUS efi_status; + BOOLEAN switch_flag = TRUE; + efi_status = LibLocateProtocol(&gIpmiInterfaceProtocolGuid, + (VOID **) &tpcm_ipmi); + if (EFI_ERROR(efi_status)) + return EFI_SUCCESS; // support no tpcm scenes + if (!tpcm_ipmi) { + console_print(L"Error: tpcm_ipmi is NULL"); + return EFI_INVALID_PARAMETER; + } + + switch_flag = shim_tpcm_measure_switch(); + if (switch_flag == TRUE) { + return shim_tpcm_log_event(buf, size, description, image_handle); + } + return EFI_SUCCESS; +} + +EFI_STATUS +tpcm_ipmi_write (void *context __attribute__ ((unused)), unsigned char *buf, size_t size, EFI_HANDLE image_handle) +{ + EFI_STATUS efi_status; + efi_status = tpcm_ipmi_measure (buf, size, context, image_handle); + return efi_status; +} + + diff --git a/tpcm.h b/tpcm.h new file mode 100644 index 0000000..8e23a84 --- /dev/null +++ b/tpcm.h @@ -0,0 +1,195 @@ +#ifndef SHIM_EFI_TPCM_HEADER +#define SHIM_EFI_TPCM_HEADER 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define EFI_TPCM_GUID {0xa37e200e, 0xda90, 0x473b, {0x8b, 0xb5, 0x1d, 0x7b, 0x11, 0xba, 0x32, 0x33}} +#define SHIM_EFI_HASH2_SERVICE_BINDING_PROTOCOL_GUID {0xda836f8d, 0x217f, 0x4ca0, { 0x99, 0xc2, 0x1c, 0xa4, 0xe1, 0x60, 0x77, 0xea}} +#define SHIM_EFI_HASH2_PROTOCOL_GUID {0x55b1d734, 0xc5e1, 0x49db, { 0x96, 0x47, 0xb1, 0x6a, 0xfb, 0xe, 0x30, 0x5b}} +#define SHIM_HASH_ALGORITHM_SM3_GUID {0x9DCD754B, 0x3479, 0x27AD, { 0x56, 0x4C, 0x68, 0x7C, 0x68, 0xEC, 0xF9, 0xB9}} + +#define OEM_SIG_SIZE 3 +#define FIRMWARE_VERSION_SIZE 32 +#define FIRMWARE_HASH_CONYENT_SIZE 32 +#define FIRMWARE_NAME_SIZE 32 +#define SHIM_IPMI_TIMEOUT_MS 7000 +// +// LUN +// +#define IPMI_BMC_LUN 0x00 +// Net Function Definition +#define IPMI_NETFN_OEM 0x30 + +#define IPMI_CMD_GET_MEASURE_PARM 0x92 //change a name + +#define IPMI_SUB_CMD_MEASURE_REQ 0x57 //change a name +#define IPMI_SUB_CMD_CONTROL_REQ 0x58 +#define IPMI_SUB_CMD_SWITCH_REQ 0x59 + +//bmeasure +#define DEFAULT_HASH_SIZE 32 +#define MEASURE_DATA_MEM_SIZE 0x100000 + +#define TPCM_TAG_REQ_COMMAND 0x000000C1 +#define TPCM_ORD_ExternSimpleBootMeasure 0x00001053 + +typedef struct{ + UINT32 uiCmdTag; + UINT32 uiCmdLength; + UINT32 uiCmdCode; + UINT32 uiPcr; + UINT32 uiStage; + UINT8 uaDigest[DEFAULT_HASH_SIZE]; + UINT32 uiObjLen; + UINT8 uaObj[FIRMWARE_NAME_SIZE]; +}extern_simple_bmeasure_req_st; + +typedef struct { + UINT8 OemSignature[OEM_SIG_SIZE]; + UINT8 SubCmd; + UINT8 FirmwareType; + UINT8 FirmwareDetailType; + UINT8 FirmwareHashAlgorithmType; + UINT8 FirmwareHashLen; + extern_simple_bmeasure_req_st FirmwareHashContent; + UINT8 FirmwareVerionLen; + UINT8 FirmwareVerion[FIRMWARE_VERSION_SIZE]; +} OEM_BMC_MEASURE_REQUSET; + +typedef struct { + UINT8 CompletionCode; + UINT8 OemSignature[OEM_SIG_SIZE]; +} OEM_BMC_MEASURE_RESPONSE; + +typedef struct { + UINT8 OemSignature[OEM_SIG_SIZE]; + UINT8 SubCmd; + UINT8 FirmwareType; + UINT8 FirmwareDetailType; +} OEM_BMC_GET_RESULT_REQUSET; + +typedef struct { +// UINT8 CompletionCode; + UINT8 OemSignature[OEM_SIG_SIZE]; + UINT8 ControlResult; +} OEM_BMC_GET_RESULT_RESPONSE; + +typedef enum { + IPMI_SYSTEM_INTERFACE_UNKNOWN, // IPMI_SYSTEM_INTERFACE_TYPE->UNKNOWN + IPMI_SYSTEM_INTERFACE_KCS, + IPMI_SYSTEM_INTERFACE_SMIC, + IPMI_SYSTEM_INTERFACE_BT, // IPMI_SYSTEM_INTERFACE_TYPE->BT + IPMI_SYSTEM_INTERFACE_SSIF, + IPMI_SYSTEM_INTERFACE_MAX_TYPE // IPMI_SYSTEM_INTERFACE_TYPE->MAX_TYPE +} shim_ipmi_system_interface_type; + + +typedef struct { + UINT8 lun : 2; + UINT8 net_fn : 6; + UINT8 cmd; +} shim_ipmi_cmd_header; + +typedef enum { + IPMI_MEMORY, + IPMI_IO, // IPMI_IO + IPMI_MAX_INTERFACE_ADDRESS_TYPE +} shim_ipmi_interface_address_type; + +typedef enum { + IPMI_FW_SHIM, + IPMI_FW_SHIM_GRUB, + IPMI_FW_OS +} shim_ipmi_firmware_type; + +typedef enum { + IPMI_FW_DETAIL_GRUB, + RESERVED1, + RESERVED2 +} shim_ipmi_firmware_detail_type; + +typedef enum { + SM3_HASH, + HASH_RESERVED1, + HASH_RESERVED2 +} shim_ipmi_firmware_hash_type; + +typedef enum { + IPMI_MEASURE_UNKNOW, + IPMI_MEASURE_SUCCESS, + IPMI_MEASURE_FAIL +} shim_ipmi_measure_result_type; + +typedef enum { + IPMI_SWITCH_UNKNOW, + IPMI_SWITCH_OPEN, + IPMI_SWITCH_CLOSE +} shim_ipmi_get_switch_result_type; + +typedef union { + UINT8 Md5Hash[16]; + UINT8 Sha1Hash[20]; + UINT8 Sha224Hash[28]; + UINT8 Sha256Hash[32]; + UINT8 Sha384Hash[48]; + UINT8 Sha512Hash[64]; + UINT8 Sm3Hash[32]; +} shim_efi_hash2_output; + +struct shim_efi_hash2_protocol { + EFI_STATUS (*get_hash_size) (struct shim_efi_hash2_protocol *this, + EFI_GUID *hash_algorithm, + UINT64 hash_size); + + EFI_STATUS (*hash) (struct shim_efi_hash2_protocol *this, + EFI_GUID *hash_algorithm, + UINT8 *message, + UINT64 message_size, + shim_efi_hash2_output *hash); + + EFI_STATUS (*hash_init) (struct shim_efi_hash2_protocol *this, + EFI_GUID *hash_algorithm); + + EFI_STATUS (*hash_update) (struct shim_efi_hash2_protocol *this, + UINT8 *message, + UINT64 message_size); + + EFI_STATUS (*hash_final) (struct shim_efi_hash2_protocol *this, + shim_efi_hash2_output *hash); +}; + +typedef struct shim_efi_hash2_protocol shim_efi_hash2_protocol_t; + +struct shim_efi_ipmi_interface_protocol +{ + EFI_STATUS (*excute_ipmi_cmd) (struct shim_efi_ipmi_interface_protocol *this, + shim_ipmi_cmd_header request, + void *send_data, + UINT8 send_length, + void *recv_data, + UINT8 *recv_length, + UINT16 *status_codes); + shim_ipmi_system_interface_type (*get_ipmi_interface_type) (struct shim_efi_ipmi_interface_protocol *this); + UINT16 (*get_ipmi_base_address) (struct shim_efi_ipmi_interface_protocol *this); + shim_ipmi_interface_address_type (*get_ipmi_base_address_type) (struct shim_efi_ipmi_interface_protocol *this); + UINT8 (*get_ipmi_version) (struct shim_efi_ipmi_interface_protocol *this); +}; + +typedef struct shim_efi_ipmi_interface_protocol shim_efi_ipmi_interface_protocol_t; + +EFI_STATUS tpcm_ipmi_write (void *context __attribute__ ((unused)), unsigned char *buf, size_t size, EFI_HANDLE image_handle); + +#endif -- 2.27.0