From patchwork Wed Nov 4 13:47:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 320532 Delivered-To: patch@linaro.org Received: by 2002:a92:7b12:0:0:0:0:0 with SMTP id w18csp5452978ilc; Wed, 4 Nov 2020 05:48:56 -0800 (PST) X-Google-Smtp-Source: ABdhPJz46GEyHZYRub1x5Lm4Sdq5waRjJQe7qRncpxw3PpaZpDvpZLacgRSeswdXSFPqduTK7GIV X-Received: by 2002:a17:906:d1c3:: with SMTP id bs3mr23873176ejb.246.1604497735917; Wed, 04 Nov 2020 05:48:55 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1604497735; cv=none; d=google.com; s=arc-20160816; b=SEdz+As+np/y6CFOqmdqogSG1kwQMHXe0W9c90yM1k4qX+m0DS0pQzlHK0N3cBnZcE OxY6Xt/wd8buis9OnWrq9lS78yImJ7jubfQR1P2DKdV6OeRn2YrYwyTbFnm8Ael6b9ip T0IlfK6uC4OyH1J3lzLeN4rpu7sqfkBRutBJ4zuSWRg31d3dxBx/VIUtSD06JoI1jfpE vHW5FY19SeeJGkSCAJd/0d9rgT0GcpntV8wzNqK7Pt2Es7bI7EGiwmNb0ralv9v8hRSi imsIzlbDhMvUCJNKs3OU/nNwUfOp5h7nJw2cjupvr+7fA3Acjh36QPwg5bVgwSF/8Jqz xjPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=+f0eSEl8+MmpNk7V7y7kB7md2kGmDuR/iOlNkUzoIgA=; b=uOxnWQ+oAu5H5W020kfTsJbN3Mpp/m5LE568y+LWoPTJ8nUbqsQ+3KqjuNw/o4ECFb /WNyi/79rWaIU801bA0O76ydMnDOyMeZeTsZc0KQLlvvhJwEkyEEMMxFKFWvyS2oFFc9 aRwu8Ru2l79QWnpBOW1nOmL8wAE+CFqQlQMSPRfFYRG+d7V7KacKpXRZNQqoFBuf7wGM OeL164+F9fRLy+OV6KOkMDVPZkpjqhBwqU0dyd1JfEikFfnz+GrHuYCaXlMpIdA/apb2 YoxEUxzVhgq74gKD69fwcXwteTySPp0TCssj6oWIM4Q77/RpwibiVq2mCCrrmFn29yoG vIzQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=KiZBZXwQ; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id bt21si1484283ejb.368.2020.11.04.05.48.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 05:48:55 -0800 (PST) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=KiZBZXwQ; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 4B6A6824C4; Wed, 4 Nov 2020 14:48:28 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="KiZBZXwQ"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id A5833824A8; Wed, 4 Nov 2020 14:48:21 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-ej1-x633.google.com (mail-ej1-x633.google.com [IPv6:2a00:1450:4864:20::633]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 38FF38246A for ; Wed, 4 Nov 2020 14:48:10 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ilias.apalodimas@linaro.org Received: by mail-ej1-x633.google.com with SMTP id k3so29775156ejj.10 for ; Wed, 04 Nov 2020 05:48:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+f0eSEl8+MmpNk7V7y7kB7md2kGmDuR/iOlNkUzoIgA=; b=KiZBZXwQIk/NNj3XqXQ8X9uMGluFuZN/nOtsqeIVQeOnC/NKTh6CwicsfCR8DhGkN0 h3sLkbYVpsU9eKI0ORfwIafrUfYD6/XeXBX7vZcPP1902NWjsBMv9xbaVBPuZPWOeAdH iUdGM97gWqfVeOyN+rCRIwaOMxrzYz6qu17twQoN+EasctO29IpGVArqTZubAeQUw9Bh p0/QW56Nvf3cHQs37W1BiWGB3KI17qSHytzXNYZyLoJwVpWVZ9QQcDYwYCHK6mXe+bFX G+oOhkcTMMXMsL+gw3fLDJuBOpFBmpJgrzig/lmd+QH3TQ+GdViNM6tnYzgxVSss4XU/ VmnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+f0eSEl8+MmpNk7V7y7kB7md2kGmDuR/iOlNkUzoIgA=; b=lbAOvr3dPAX3SUgLhfLTBGN4CjqBMP3yA2vInEsUz+Uv3MpjM8kdZnMWRyEyzxljhA K0xwXwFyyDP+MXYjzPj3DJt7x0kW7quqzGJ/Om3YwfBWGiF1ksQTky+UaY0Vypqa4sY+ D+huRCejLXq03+qDYOFbXhaWXWyOqJgsV9sq2gy83Hy+af6vG2aoFK5fhBYFUro7D9l4 EBdf7mjpTvEveEaPHruaIgQ8QvxNb31q+C98/Sc7lQ5CiLtbRCwH1OtoQLEjEtuSENj5 qjBzhFEnajSeX86qxG/WNfznA5jTuY1sGD0L+4FY0II5LML+VLYCzYXvcU42it//pKiC 2I5Q== X-Gm-Message-State: AOAM530tX3DlXyXbrstuUlBNkKdeJdDffS5PRZwJLSUsVuw7vdNnNJuC JKD6tAROHCjLifhBoRcAe/CTQw== X-Received: by 2002:a17:906:7e0e:: with SMTP id e14mr24417917ejr.238.1604497684697; Wed, 04 Nov 2020 05:48:04 -0800 (PST) Received: from apalos.home ([2a02:587:4615:c071:2e56:dcff:fe9a:8f06]) by smtp.gmail.com with ESMTPSA id g1sm1032708ejz.52.2020.11.04.05.48.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Nov 2020 05:48:04 -0800 (PST) From: Ilias Apalodimas To: xypron.glpk@gmx.de Cc: ard.biesheuvel@arm.com, Ilias Apalodimas , Alexander Graf , Simon Glass , Miquel Raynal , Philippe Reynes , Bin Meng , Dhananjay Phadke , u-boot@lists.denx.de Subject: [PATCH 2/2] efi: Add basic EFI_TCG2_PROTOCOL support Date: Wed, 4 Nov 2020 15:47:47 +0200 Message-Id: <20201104134748.810291-2-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201104134748.810291-1-ilias.apalodimas@linaro.org> References: <20201104134748.810291-1-ilias.apalodimas@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean 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 --- The protocol requires mode that GetCapability to be usable. I intend to add support for GetEventLog() and HashLogExtendEvent() once this gets reviewed/merged include/efi_loader.h | 2 + include/efi_tcg2.h | 91 ++++++++ include/tpm-v2.h | 48 ++++ lib/efi_loader/Kconfig | 8 + lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_setup.c | 7 + lib/efi_loader/efi_tcg2.c | 460 +++++++++++++++++++++++++++++++++++++ 7 files changed, 617 insertions(+) create mode 100644 include/efi_tcg2.h create mode 100644 lib/efi_loader/efi_tcg2.c -- 2.29.2 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..9e7b85db058d --- /dev/null +++ b/include/efi_tcg2.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2020, Linaro Limited + */ + +#if !defined _EFI_TCG2_PROTOCOL_H_ +#define _EFI_TCG2_PROTOCOL_H_ + +#include + +#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; + bool 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/include/tpm-v2.h b/include/tpm-v2.h index ee74028ca83b..505b8c96eb92 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -11,6 +11,52 @@ #define TPM2_DIGEST_LEN 32 +#define IMPLEMENTATION_PCR 24 + +/* + * We deviate from this draft of the specification by increasing the value of TPM2_NUM_PCR_BANKS + * from 3 to 16 to ensure compatibility with TPM2 implementations that have enabled a larger than + * typical number of PCR banks. This larger value for TPM2_NUM_PCR_BANKS is expected to be included + * in a future revision of the specification. + */ +#define TPM2_NUM_PCR_BANKS 16 + +/* Table 22 — Definition of (UINT32) TPM_CAP Constants */ +#define TPM_CAP_FIRST 0x00000000U +#define TPM_CAP_ALGS 0x00000000U +#define TPM_CAP_HANDLES 0x00000001U +#define TPM_CAP_COMMANDS 0x00000002U +#define TPM_CAP_PP_COMMANDS 0x00000003U +#define TPM_CAP_AUDIT_COMMANDS 0x00000004U +#define TPM_CAP_PCRS 0x00000005U +#define TPM_CAP_TPM_PROPERTIES 0x00000006U +#define TPM_CAP_PCR_PROPERTIES 0x00000007U +#define TPM_CAP_ECC_CURVES 0x00000008U +#define TPM_CAP_LAST 0x00000008U +#define TPM_CAP_VENDOR_PROPERTY 0x00000100U + +/* Table 23 — Definition of (UINT32) TPM_PT Constants */ +#define TPM_PT_NONE (u32)(0x00000000) +#define PT_GROUP (u32)(0x00000100) +#define PT_FIXED (u32)(PT_GROUP * 1) +#define TPM_PT_MANUFACTURER (u32)(PT_FIXED + 5) +#define TPM_PT_PCR_COUNT (u32)(PT_FIXED + 18) +#define TPM_PT_MAX_COMMAND_SIZE (u32)(PT_FIXED + 30) +#define TPM_PT_MAX_RESPONSE_SIZE (u32)(PT_FIXED + 31) + +/* Definition of TPMS_PCR_SELECTION Structure */ +struct tpms_pcr_selection { + u16 hash; + u8 size_of_select; + u8 pcr_select[(IMPLEMENTATION_PCR + 7) / 8]; +} __packed; + +/* Definition of TPML_PCR_SELECTION Structure */ +struct tpml_pcr_selection { + u32 count; + struct tpms_pcr_selection selection[TPM2_NUM_PCR_BANKS]; +} __packed; + /** * TPM2 Structure Tags for command/response buffers. * @@ -123,11 +169,13 @@ enum tpm2_return_codes { * TPM2 algorithms. */ enum tpm2_algorithms { + TPM2_ALG_SHA1 = 0x04, TPM2_ALG_XOR = 0x0A, TPM2_ALG_SHA256 = 0x0B, TPM2_ALG_SHA384 = 0x0C, TPM2_ALG_SHA512 = 0x0D, TPM2_ALG_NULL = 0x10, + TPM2_ALG_SM3_256 = 0x12, }; /* NV index attributes */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 075481428cdf..5d5074a4bc41 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -184,6 +184,14 @@ 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 + default n + 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..1e12f95b2e41 --- /dev/null +++ b/lib/efi_loader/efi_tcg2.c @@ -0,0 +1,460 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020, Linaro Limited + */ + +#define LOG_CATEGORY LOGC_EFI +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define COMMAND_BUFFER_SIZE 256 + +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); + if (ret) { + log_warning("Unable to get tpm device\n"); + return EFI_DEVICE_ERROR; + } + + *dev = devp; + + return EFI_SUCCESS; +} + +/** + * tpm2_get_max_command_size() - TPM2 command to get the supported max command size + * + * @dev: TPM device + * @max_command_size: output buffer for the size + * + * Return: 0 on success -1 on error + */ +static int tpm2_get_max_command_size(struct udevice *dev, u16 *max_command_size) +{ + u8 response[COMMAND_BUFFER_SIZE]; + u32 ret; + + ret = tpm2_get_capability(dev, TPM_CAP_TPM_PROPERTIES, + TPM_PT_MAX_COMMAND_SIZE, response, 1, false); + if (ret) + return -1; + /* + * On the definition of TPMS_TAGGED_PROPERTY Structure + * property: u32 + * value: u32 + * So advance the response for TPM_CAP_TPM_PROPERTIES by sizeof(u32) + * to get the value + */ + *max_command_size = (uint16_t)get_unaligned_be32(response + sizeof(u32)); + + return 0; +} + +/** + * tpm2_get_max_response_size() - TPM2 command to get the supported max response size + * + * @dev: TPM device + * @max_response_size: output buffer for the size + * + * Return: 0 on success -1 on error + */ +static int tpm2_get_max_response_size(struct udevice *dev, u16 *max_response_size) +{ + u8 response[COMMAND_BUFFER_SIZE]; + u32 ret; + + ret = tpm2_get_capability(dev, TPM_CAP_TPM_PROPERTIES, + TPM_PT_MAX_RESPONSE_SIZE, response, 1, false); + if (ret) + return -1; + /* + * On the definition of TPMS_TAGGED_PROPERTY Structure + * property: u32 + * value: u32 + * So advance the response for TPM_CAP_TPM_PROPERTIES by sizeof(u32) + * to get the value + */ + *max_response_size = (uint16_t)get_unaligned_be32(response + sizeof(u32)); + + return 0; +} + +/** + * tpm2_get_manufacturer_id() - Issue a TPM2 command to get the manufacturer ID + * + * @dev: TPM device + * @manufacturer_id: output buffer for the id + * + * Return: 0 on success -1 on error + */ +static int tpm2_get_manufacturer_id(struct udevice *dev, u32 *manufacturer_id) +{ + u8 response[COMMAND_BUFFER_SIZE]; + u32 ret; + + ret = tpm2_get_capability(dev, TPM_CAP_TPM_PROPERTIES, + TPM_PT_MANUFACTURER, response, 1, false); + if (ret) + return -1; + *manufacturer_id = get_unaligned_be32(response + sizeof(u32)); + + return 0; +} + +/** + * is_active_pcr() - Check if an supported algorithm is active + * + * @dev: TPM device + * @selection: struct of PCR information + * + * Return: true if PCR is active + */ +bool is_active_pcr(struct tpms_pcr_selection *selection) +{ + int i; + /* + * check the pcr_select. If at least one of the PCRs supports the algorithm + * add it on the active ones + */ + for (i = 0; i < selection->size_of_select; i++) { + if (selection->pcr_select[i]) + return true; + } + + return false; +} + +/** + * tpm2_get_pcr_info() - Issue a TPM2 command to get the supported, active PCRs and number of banks + * + * @dev: TPM device + * @supported_pcr: bitmask with the algorithms supported + * @active_pcr: bitmask with the active algorithms + * @pcr_banks: number of PCR banks + * + * Return: 0 on success -1 on error + */ +static int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, + u32 *pcr_banks) +{ + u8 response[COMMAND_BUFFER_SIZE]; + struct tpml_pcr_selection pcrs; + u32 ret; + int i; + + ret = tpm2_get_capability(dev, TPM_CAP_PCRS, 0, response, 1, true); + if (ret) + return -1; + + pcrs.count = get_unaligned_be32(response); + if (pcrs.count > MAX_HASH_COUNT || pcrs.count < 1) + return -1; + + for (i = 0; i < pcrs.count; i++) { + /* + * Definition of TPMS_PCR_SELECTION Structure + * hash: u16 + * size_of_select: u8 + * pcr_select: u8 array + */ + u32 hash_offset = sizeof(pcrs.count) + i * sizeof(pcrs.selection[0]); + u32 size_select_offset = + hash_offset + offsetof(struct tpms_pcr_selection, size_of_select); + u32 pcr_select_offset = + hash_offset + offsetof(struct tpms_pcr_selection, pcr_select); + + pcrs.selection[i].hash = get_unaligned_be16(response + hash_offset); + pcrs.selection[i].size_of_select = + __get_unaligned_be(response + size_select_offset); + /* copy the array of pcr_select */ + memcpy(pcrs.selection[i].pcr_select, response + pcr_select_offset, + pcrs.selection[i].size_of_select); + } + + for (i = 0; i < pcrs.count; i++) { + switch (pcrs.selection[i].hash) { + case TPM2_ALG_SHA1: + *supported_pcr |= EFI_TCG2_BOOT_HASH_ALG_SHA1; + if (is_active_pcr(&pcrs.selection[i])) + *active_pcr |= EFI_TCG2_BOOT_HASH_ALG_SHA1; + break; + case TPM2_ALG_SHA256: + *supported_pcr |= EFI_TCG2_BOOT_HASH_ALG_SHA256; + if (is_active_pcr(&pcrs.selection[i])) + *active_pcr |= EFI_TCG2_BOOT_HASH_ALG_SHA256; + break; + case TPM2_ALG_SHA384: + *supported_pcr |= EFI_TCG2_BOOT_HASH_ALG_SHA384; + if (is_active_pcr(&pcrs.selection[i])) + *active_pcr |= EFI_TCG2_BOOT_HASH_ALG_SHA384; + break; + case TPM2_ALG_SHA512: + *supported_pcr |= EFI_TCG2_BOOT_HASH_ALG_SHA512; + if (is_active_pcr(&pcrs.selection[i])) + *active_pcr |= EFI_TCG2_BOOT_HASH_ALG_SHA512; + break; + case TPM2_ALG_SM3_256: + *supported_pcr |= EFI_TCG2_BOOT_HASH_ALG_SM3_256; + if (is_active_pcr(&pcrs.selection[i])) + *active_pcr |= EFI_TCG2_BOOT_HASH_ALG_SM3_256; + break; + default: + log_err("Unknown algorithm %x\n", pcrs.selection[i].hash); + break; + } + } + + *pcr_banks = pcrs.count; + + return 0; +} + +/** + * get_capability() - provide protocol capability information and state information + * + * @this: TCG2 protocol instance + * @capability: caller allocated memory with size field to the size of the + * structure allocated + + * Return: status code + */ +static efi_status_t EFIAPI +get_capability(struct efi_tcg2_protocol *this, + struct efi_tcg2_boot_service_capability *capability) +{ + struct udevice *dev; + int ret; + + EFI_ENTRY("%p, %p", this, capability); + + if (!this || !capability) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + if (capability->size < boot_service_capability_min) { + capability->size = boot_service_capability_min; + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + + if (capability->size < sizeof(*capability)) { + capability->size = sizeof(*capability); + return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + } + + capability->structure_version.major = 1; + capability->structure_version.minor = 1; + capability->protocol_version.major = 1; + capability->protocol_version.minor = 1; + + ret = platform_get_tpm2_device(&dev); + if (ret != EFI_SUCCESS) { + capability->supported_event_logs = 0; + capability->hash_algorithm_bitmap = 0; + capability->tpm_present_flag = false; + capability->max_command_size = 0; + capability->max_response_size = 0; + capability->manufacturer_id = 0; + capability->number_of_pcr_banks = 0; + capability->active_pcr_banks = 0; + + return EFI_EXIT(EFI_SUCCESS); + } + + /* We only allow a TPMv2 device to register the EFI protocol */ + capability->supported_event_logs = TCG2_EVENT_LOG_FORMAT_TCG_2; + + capability->tpm_present_flag = true; + + /* Supported and active PCRs */ + capability->hash_algorithm_bitmap = 0; + capability->active_pcr_banks = 0; + ret = tpm2_get_pcr_info(dev, &capability->hash_algorithm_bitmap, + &capability->active_pcr_banks, + &capability->number_of_pcr_banks); + if (ret) + return EFI_EXIT(EFI_DEVICE_ERROR); + + /* Max command size */ + ret = tpm2_get_max_command_size(dev, &capability->max_command_size); + if (ret) + return EFI_EXIT(EFI_DEVICE_ERROR); + + /* Max response size */ + ret = tpm2_get_max_response_size(dev, &capability->max_response_size); + if (ret) + return EFI_EXIT(EFI_DEVICE_ERROR); + + /* Manufacturer ID */ + ret = tpm2_get_manufacturer_id(dev, &capability->manufacturer_id); + if (ret) + return EFI_EXIT(EFI_DEVICE_ERROR); + + return EFI_EXIT(EFI_SUCCESS); +} + +/** + * get_eventlog() - retrieve the the address of a given event log and its last entry. + * + * @this: TCG2 protocol instance + * @log_format: type of event log format + * @event_log_location: pointer to the memory address of the event log + * @event_log_last_entry: pointer to the address of the start of the last entry in the + * event log in memory, if log contains more than 1 entry + * @event_log_truncated: set to true, if the Event Log is missing at least one entry + * + * Return: status code + */ +static 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) +{ + return EFI_UNSUPPORTED; +} + +/** + * hash_log_extend_event()- extend and optionally log events + * + * @this: TCG2 protocol instance + * @flags: bitmap providing additional information on the operation + * @data_to_hash: physical address of the start of the data buffer to be hashed + * @data_to_hash_len: the length in bytes of the buffer referenced by data_to_hash + * @efi_tcg_event: pointer to data buffer containing information about the event + * + * Return: status code + */ +static 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) +{ + return EFI_UNSUPPORTED; +} + +/** + * submit_command() - Send command to the TPM + * + * @this: TCG2 protocol instance + * @input_param_block_size: size of the TPM input parameter block + * @input_param_block: pointer to the TPM input parameter block + * @output_param_block_size: size of the TPM output parameter block + * @output_param_block: pointer to the TPM output parameter block + * + * Return: status code + */ +efi_status_t EFIAPI +submit_command(struct efi_tcg2_protocol *this, u32 input_param_block_size, + u8 *input_param_block, u32 output_param_block_size, + u8 *output_param_block) +{ + return EFI_UNSUPPORTED; +} + +/** + * get_active_pcr_banks() - returns the currently active PCR banks + * + * @this: TCG2 protocol instance + * @active_pcr_banks: pointer for receiving the bitmap of currently active PCR banks + * + * Return: status code + */ +efi_status_t EFIAPI +get_active_pcr_banks(struct efi_tcg2_protocol *this, u32 *active_pcr_banks) +{ + return EFI_UNSUPPORTED; +} + +/** + * set_active_pcr_banks() - sets the currently active PCR banks + * + * @this: TCG2 protocol instance + * @active_pcr_banks: bitmap of the requested active PCR banks + * + * Return: status code + */ +efi_status_t EFIAPI +set_active_pcr_banks(struct efi_tcg2_protocol *this, u32 active_pcr_banks) +{ + return EFI_UNSUPPORTED; +} + +/** + * get_result_of_set_active_pcr_banks() - retrieves the result of a previous set_active_pcr_banks() + * + * @this: TCG2 protocol instance + * @operation_present: non-zero value to indicate a set_active_pcr_banks operation was + * invoked during last boot + * @response: result value could be returned + * + * Return: status code + */ +efi_status_t EFIAPI +get_result_of_set_active_pcr_banks(struct efi_tcg2_protocol *this, + u32 *operation_present, u32 *response) +{ + return EFI_UNSUPPORTED; +} + +static const struct efi_tcg2_protocol efi_tcg2_protocol = { + .get_capability = get_capability, + .get_eventlog = get_eventlog, + .hash_log_extend_event = hash_log_extend_event, + .submit_command = submit_command, + .get_active_pcr_banks = get_active_pcr_banks, + .set_active_pcr_banks = set_active_pcr_banks, + .get_result_of_set_active_pcr_banks = get_result_of_set_active_pcr_banks, +}; + +/** + * efi_tcg2_register() - register EFI_TCG2_PROTOCOL + * + * If a TPM2 device is available, the TPM TCG2 Protocol is registered + * + * Return: An error status is only returned if adding the protocol fails. + */ +efi_status_t efi_tcg2_register(void) +{ + int ret; + struct udevice *dev; + enum tpm_version tpm_ver; + + ret = platform_get_tpm2_device(&dev); + if (ret != EFI_SUCCESS) + return EFI_SUCCESS; + + tpm_ver = tpm_get_version(dev); + if (tpm_ver != TPM_V2) { + log_warning("Only TPMv2 supported for EFI_TCG2_PROTOCOL"); + return EFI_SUCCESS; + } + + ret = efi_add_protocol(efi_root, &efi_guid_tcg2_protocol, + (void *)&efi_tcg2_protocol); + if (ret != EFI_SUCCESS) + log_err("Cannot install EFI_TCG2_PROTOCOL"); + + return ret; +}