[PATCH 2/2 v4] efi: Add basic EFI_TCG2_PROTOCOL support

Heinrich Schuchardt xypron.glpk at gmx.de
Thu Nov 12 20:21:06 CET 2020


On 11/12/20 7:49 PM, Heinrich Schuchardt wrote:
> On 11/11/20 10:18 AM, Ilias Apalodimas wrote:
>> Since U-boot EFI implementation is getting richer it makes sense to
>> add support for EFI_TCG2_PROTOCOL taking advantage of any hardware TPM
>> available on the device.
>>
>> This is the initial implementation of the protocol which only adds
>> support for GetCapability(). It's limited in the newer and safer
>> TPMv2 devices.
>>
>> Signed-off-by: Ilias Apalodimas <ilias.apalodimas at linaro.org>
>> ---
>> * changes since v3:
>> - added check for maximum number of PCRs allowed
>> - replaced multiple return Xl with goto out tags
>> * changes since v2:
>> - added description about include/efi_tcg2.h
>> - switch bool to u8 for tpm_present_flag
>> - removed superfluous 'default n' from Kconfig
>> - use 'goto 'tag' when possible
>>
>> * changes since v1:
>> - change return variable of platform_get_tpm2_device() when used
>> - since more headers were included in patch #2 use them in offset
>>   calculations for all tpm commands
>> - change the size of the response buffer regardless of what
>>   tpm2_get_capability() is doing
>>  include/efi_loader.h       |   2 +
>>  include/efi_tcg2.h         |  94 +++++++
>>  lib/efi_loader/Kconfig     |   7 +
>>  lib/efi_loader/Makefile    |   1 +
>>  lib/efi_loader/efi_setup.c |   7 +
>>  lib/efi_loader/efi_tcg2.c  | 539 +++++++++++++++++++++++++++++++++++++
>>  6 files changed, 650 insertions(+)
>>  create mode 100644 include/efi_tcg2.h
>>  create mode 100644 lib/efi_loader/efi_tcg2.c
>>
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index f550ced56876..e5015d865ec9 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -405,6 +405,8 @@ efi_status_t efi_console_register(void);
>>  efi_status_t efi_disk_register(void);
>>  /* Called by efi_init_obj_list() to install EFI_RNG_PROTOCOL */
>>  efi_status_t efi_rng_register(void);
>> +/* Called by efi_init_obj_list() to install EFI_TCG2_PROTOCOL */
>> +efi_status_t efi_tcg2_register(void);
>>  /* Create handles and protocols for the partitions of a block device */
>>  int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
>>  			       const char *if_typename, int diskid,
>> diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
>> new file mode 100644
>> index 000000000000..4214f767eaba
>> --- /dev/null
>> +++ b/include/efi_tcg2.h
>> @@ -0,0 +1,94 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Defines data structures and APIs that allow an OS to interact with UEFI
>> + * firmware to query information about the device
>> + *
>> + * Copyright (c) 2020, Linaro Limited
>> + */
>> +
>> +#if !defined _EFI_TCG2_PROTOCOL_H_
>> +#define _EFI_TCG2_PROTOCOL_H_
>> +
>> +#include <tpm-v2.h>
>> +
>> +#define EFI_TCG2_PROTOCOL_GUID \
>> +	EFI_GUID(0x607f766c, 0x7455, 0x42be, 0x93, \
>> +		 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
>> +
>> +/* TPMV2 only */
>> +#define TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002
>> +
>> +/* SHA1, SHA256, SHA384, SHA512, TPM_ALG_SM3_256 */
>> +#define MAX_HASH_COUNT 5
>> +/* Algorithm Registry */
>> +#define EFI_TCG2_BOOT_HASH_ALG_SHA1    0x00000001
>> +#define EFI_TCG2_BOOT_HASH_ALG_SHA256  0x00000002
>> +#define EFI_TCG2_BOOT_HASH_ALG_SHA384  0x00000004
>> +#define EFI_TCG2_BOOT_HASH_ALG_SHA512  0x00000008
>> +#define EFI_TCG2_BOOT_HASH_ALG_SM3_256 0x00000010
>> +
>> +typedef u32 efi_tcg_event_log_bitmap;
>> +typedef u32 efi_tcg_event_log_format;
>> +typedef u32 efi_tcg_event_algorithm_bitmap;
>> +
>> +struct efi_tcg2_version {
>> +	u8 major;
>> +	u8 minor;
>> +};
>> +
>> +struct efi_tcg2_event_header {
>> +	u32 header_size;
>> +	u16 header_version;
>> +	u32 pcr_index;
>> +	u32 event_type;
>> +} __packed;
>> +
>> +struct efi_tcg2_event {
>> +	u32 size;
>> +	struct efi_tcg2_event_header header;
>> +	u8 event[];
>> +} __packed;
>> +
>> +struct efi_tcg2_boot_service_capability {
>> +	u8 size;
>> +	struct efi_tcg2_version structure_version;
>> +	struct efi_tcg2_version protocol_version;
>> +	efi_tcg_event_algorithm_bitmap hash_algorithm_bitmap;
>> +	efi_tcg_event_log_bitmap supported_event_logs;
>> +	u8 tpm_present_flag;
>> +	u16 max_command_size;
>> +	u16 max_response_size;
>> +	u32 manufacturer_id;
>> +	u32 number_of_pcr_banks;
>> +	efi_tcg_event_algorithm_bitmap active_pcr_banks;
>> +};
>> +
>> +#define boot_service_capability_min \
>> +	sizeof(struct efi_tcg2_boot_service_capability) - \
>> +	offsetof(struct efi_tcg2_boot_service_capability, number_of_pcr_banks)
>> +
>> +struct efi_tcg2_protocol {
>> +	efi_status_t (EFIAPI * get_capability)(struct efi_tcg2_protocol *this,
>> +					       struct efi_tcg2_boot_service_capability *capability);
>> +	efi_status_t (EFIAPI * get_eventlog)(struct efi_tcg2_protocol *this,
>> +					     efi_tcg_event_log_format log_format,
>> +					     u64 *event_log_location, u64 *event_log_last_entry,
>> +					     bool *event_log_truncated);
>> +	efi_status_t (EFIAPI * hash_log_extend_event)(struct efi_tcg2_protocol *this,
>> +						      u64 flags, u64 data_to_hash,
>> +						      u64 data_to_hash_len,
>> +						      struct efi_tcg2_event *efi_tcg_event);
>> +	efi_status_t (EFIAPI * submit_command)(struct efi_tcg2_protocol *this,
>> +					       u32 input_parameter_block_size,
>> +					       u8 *input_parameter_block,
>> +					       u32 output_parameter_block_size,
>> +					       u8 *output_parameter_block);
>> +	efi_status_t (EFIAPI * get_active_pcr_banks)(struct efi_tcg2_protocol *this,
>> +						     u32 *active_pcr_banks);
>> +	efi_status_t (EFIAPI * set_active_pcr_banks)(struct efi_tcg2_protocol *this,
>> +						     u32 active_pcr_banks);
>> +	efi_status_t (EFIAPI * get_result_of_set_active_pcr_banks)(struct efi_tcg2_protocol *this,
>> +								   u32 *operation_present,
>> +								   u32 *response);
>> +};
>> +#endif
>> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
>> index 075481428cdf..29ea14b2ee2a 100644
>> --- a/lib/efi_loader/Kconfig
>> +++ b/lib/efi_loader/Kconfig
>> @@ -184,6 +184,13 @@ config EFI_RNG_PROTOCOL
>>  	  Provide a EFI_RNG_PROTOCOL implementation using the hardware random
>>  	  number generator of the platform.
>>
>> +config EFI_TCG2_PROTOCOL
>> +	bool "EFI_TCG2_PROTOCOL support"
>> +	depends on TPM_V2
>> +	help
>> +	  Provide a EFI_TCG2_PROTOCOL implementation using the TPM hardware
>> +	  of the platform.
>> +
>>  config EFI_LOAD_FILE2_INITRD
>>  	bool "EFI_FILE_LOAD2_PROTOCOL for Linux initial ramdisk"
>>  	default n
>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>> index 8892fb01e125..cd4b252a417c 100644
>> --- a/lib/efi_loader/Makefile
>> +++ b/lib/efi_loader/Makefile
>> @@ -53,6 +53,7 @@ obj-$(CONFIG_NET) += efi_net.o
>>  obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o
>>  obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
>>  obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
>> +obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o
>>  obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o
>>  obj-y += efi_signature.o
>>
>> diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
>> index 45226c5c1a53..e206b60bb82c 100644
>> --- a/lib/efi_loader/efi_setup.c
>> +++ b/lib/efi_loader/efi_setup.c
>> @@ -156,6 +156,13 @@ efi_status_t efi_init_obj_list(void)
>>  		if (ret != EFI_SUCCESS)
>>  			goto out;
>>  	}
>> +
>> +	if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
>> +		ret = efi_tcg2_register();
>> +		if (ret != EFI_SUCCESS)
>> +			goto out;
>> +	}
>> +
>>  	/* Initialize variable services */
>>  	ret = efi_init_variables();
>>  	if (ret != EFI_SUCCESS)
>> diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
>> new file mode 100644
>> index 000000000000..d600cff66af1
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_tcg2.c
>> @@ -0,0 +1,539 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Defines APIs that allow an OS to interact with UEFI firmware to query
>> + * information about the device.
>> + * https://trustedcomputinggroup.org/resource/tcg-efi-protocol-specification/
>> + *
>> + * Copyright (c) 2020, Linaro Limited
>> + */
>> +
>> +#define LOG_CATEGORY LOGC_EFI
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <efi_loader.h>
>> +#include <efi_tcg2.h>
>> +#include <log.h>
>> +#include <tpm-v2.h>
>> +#include <linux/unaligned/access_ok.h>
>> +#include <linux/unaligned/generic.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +/*
>> + * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.
>> + * Since the current tpm2_get_capability() response buffers starts at
>> + * 'union tpmu_capabilities data' of 'struct tpms_capability_data', calculate
>> + * the response size and offset once for all consumers
>> + */
>> +#define TPM2_RESPONSE_BUFFER_SIZE (sizeof(struct tpms_capability_data) - \
>> +				   offsetof(struct tpms_capability_data, data))
>> +#define properties_offset (offsetof(struct tpml_tagged_tpm_property, tpm_property) + \
>> +			   offsetof(struct tpms_tagged_property, value))
>> +
>> +const efi_guid_t efi_guid_tcg2_protocol = EFI_TCG2_PROTOCOL_GUID;
>> +
>> +/**
>> + * platform_get_tpm_device() - retrieve TPM device
>> + *
>> + * This function retrieves the udevice implementing a TPM
>> + *
>> + * This function may be overridden if special initialization is needed.
>> + *
>> + * @dev:	udevice
>> + * Return:	status code
>> + */
>> +__weak efi_status_t platform_get_tpm2_device(struct udevice **dev)
>> +{
>> +	int ret;
>> +	struct udevice *devp;
>> +
>> +	ret = uclass_get_device(UCLASS_TPM, 0, &devp);
>
> 'dm tree' on the sandbox shows:
>
> tpm           0  [   ]   google_sandbox_tpm    |-- tpm
> tpm           1  [   ]   sandbox_tpm2          |-- tpm2
>
> You have to loop over all TPM devices and look for one supporting TPMv2
> using tpm_get_version(dev).

You must also ensure that the device is probed. for_each_tpm_device()
does the probing for you:

__weak efi_status_t platform_get_tpm2_device(struct udevice **dev)
{
        for_each_tpm_device((*dev)) {
                if (tpm_get_version(*dev) == TPM_V2)
                        return EFI_SUCCESS;
        }
        return EFI_NOT_FOUND;
}

Best regards

Heinrich


More information about the U-Boot mailing list