From patchwork Wed May 10 07:43:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 680507 Delivered-To: patch@linaro.org Received: by 2002:a5d:4a41:0:0:0:0:0 with SMTP id v1csp2697089wrs; Wed, 10 May 2023 00:44:51 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5fX7NoNPosg0laaLTsmkv5fe/HdIG23LVJbDtYnC7iDoawCZD5stFq65x6jzwARpfSNdCJ X-Received: by 2002:a05:6a20:3d09:b0:100:5f62:be76 with SMTP id y9-20020a056a203d0900b001005f62be76mr12476044pzi.54.1683704691406; Wed, 10 May 2023 00:44:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683704691; cv=none; d=google.com; s=arc-20160816; b=wGRc0Mo1RUY2iwzoo1+dGFKrRUPZNSgSmc2x9g+AdDxNunyUI6/n0B6Rag38RmB81L 1Y/Dv9G3pyQplDjwses00+HyMMsrM57JRutJL4l4ukSSNQmRqo87vaY8NLJ1MmxLwg6Q yVvUqNt7gTQr+LbxrzKooCKBbBMMN4GHbTP+qXRTHLLcHj/XH29e/OdOD8n1d4/t/YyI ypNmRD85iBudLa8SZ6gn7KVJGRSxZwTd3dE4XrjnWM+omvg+WeENockX4NK2VFlPNwlj 4r0GqJP7joJOjcU82WMf6ApqfRyCXrZrogIvuTubXWuCU+Pbo6VYepVL48jki6FjUbhd JuhQ== 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=pHig0HbJS5vmI57xK5rAXbLTncwScoc+Rf6GlnQlB6I=; b=NXogcvlubCyzhBAw6qgqYe1+rc/kDWQRmQmvgDAS3L/PfW/EfiBGtjIE0pW2+o1APL rMwAJxHa+Aelt7uaEzctuYZiwHhsXfROp0L/yQ1m78HJLwbgWsvr5Ff+aYEirQ9/l/P2 FE6218LU/FX7XI83uQAuin0I6qDnG3WueLy4S2IsJU6bFlz/g4pcz9nuEI6u41gLjY/J UAG/tjmoiGTXNcfXodmGCluXELqrwnJPXg4FKCI4xwHI7YGmOTZ97rBmbU8+byUqNE0s RavtKzdc/7HukBWkzuB5hLnALHjczHGo05Q68NeetWUYhHw6lRMuVp0+GWmlx1soNW6R yRJw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LEULwLmd; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 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. [85.214.62.61]) by mx.google.com with ESMTPS id i70-20020a638749000000b0051b930ef847si3445954pge.134.2023.05.10.00.44.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 May 2023 00:44:51 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LEULwLmd; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 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 A5D1686055; Wed, 10 May 2023 09:44:33 +0200 (CEST) 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="LEULwLmd"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id D0CCA86074; Wed, 10 May 2023 09:44:31 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.2 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) (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 3B8338602F for ; Wed, 10 May 2023 09:44:24 +0200 (CEST) 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-wr1-x42b.google.com with SMTP id ffacd0b85a97d-30786c6082dso2933819f8f.2 for ; Wed, 10 May 2023 00:44:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1683704663; x=1686296663; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=pHig0HbJS5vmI57xK5rAXbLTncwScoc+Rf6GlnQlB6I=; b=LEULwLmdhxvcMJ0d2XSmfyQ1YQrvJ1DkWlDnX9yGlnY1q1bQFFOKXyIDqfCBuoShYn jwTYEpzM/UPx15uoTZXrjPW9RS8l09XBh/LRtL6fYbYbRBFsvMkxEsXKzWmV+nmPA8s8 URYKpEGYTmeXZEc1nYKw+sKhF3pFGybVhuCLxfHv4qEAanrG04sWOpM4GgX7lGyLtPO3 fgNkzp2di9SQJVGcX4as8ZoY2PB8zpWdwvjmiPqql9OcNvhsyWEnRrCNIIy2iN/PaMrB fNJErTtDvFp999d3/JmeyFviV4FrjIQSdp0ljQ3ArEYmjVRWXvV7xeqyIap9SAy7pc48 /Olw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1683704663; x=1686296663; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=pHig0HbJS5vmI57xK5rAXbLTncwScoc+Rf6GlnQlB6I=; b=TpCI8npgORxDAe/Zq6NY4u5Xxwf38bRNXWlTah1Skqe/lqBAOPesAuYXAV5SYJlajY eAhQGKnm2i9Es6ktfXbp807eo76//fenJy0QHs8qkyzhktUnlXriR/QItSjVD2QwbDm7 djr94JdhNlQvQ68yuSG3i7SQn2ORNmt+7gfL65rnzY1mk54KvR4Fb8s+2cpTiRIUpn+i PLxJkeETtCjfCORDesAs6HPejnDjD5unoL3bSOKN0GH2p3y7Q2atw+QC/nPLYpBym1QJ t8dncnBfuAKs7R1M1XoHexH59um+oQLGX/WL2OAndjzMTyNF0Sle+28Pp7PMfSK76jwL zg8g== X-Gm-Message-State: AC+VfDzTp5YqoRrCF5BuR0dBrPUMPvyRF4wRARh1RzuplMoTPqwiNJxq 3V2B4UI9IhFeE67KS4BVucnDl4MgIOsz4vRstcaZtg== X-Received: by 2002:a5d:44cd:0:b0:2f4:6574:5a93 with SMTP id z13-20020a5d44cd000000b002f465745a93mr11379376wrr.4.1683704663260; Wed, 10 May 2023 00:44:23 -0700 (PDT) Received: from localhost.localdomain (ppp176092130041.access.hol.gr. [176.92.130.41]) by smtp.gmail.com with ESMTPSA id p20-20020a1c7414000000b003f435652aaesm2022446wmc.11.2023.05.10.00.44.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 May 2023 00:44:22 -0700 (PDT) From: Ilias Apalodimas To: u-boot@lists.denx.de Cc: Eddie James , Simon Glass , Ilias Apalodimas , Heinrich Schuchardt , Robert Marko , Dzmitry Sankouski , Michal Suchanek , Rasmus Villemoes , Sean Anderson , Nikhil M Jain , Abdellatif El Khlifi , Andrew Davis , Daniel Golle , Mattijs Korpershoek , Safae Ouajih , Roger Knecht , Sughosh Ganu , Steven Lawrance , Marek Vasut , Rui Miguel Silva , Linus Walleij , Stephen Carlson , Kautuk Consul , Leo Yu-Chi Liang , Brandon Maier , Patrick Delaunay Subject: [PATCH 3/9] tpm: Support boot measurements Date: Wed, 10 May 2023 10:43:51 +0300 Message-Id: <20230510074359.2837818-3-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230510074359.2837818-1-ilias.apalodimas@linaro.org> References: <20230510074359.2837818-1-ilias.apalodimas@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 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.103.8 at phobos.denx.de X-Virus-Status: Clean From: Eddie James Add TPM2 functions to support boot measurement. This includes starting up the TPM, initializing/appending the event log, and measuring the U-Boot version. Much of the code was used in the EFI subsystem, so remove it there and use the common functions. Signed-off-by: Eddie James --- include/efi_tcg2.h | 44 -- include/tpm-v2.h | 259 +++++++++ lib/Kconfig | 4 + lib/efi_loader/efi_tcg2.c | 1056 +++---------------------------------- lib/tpm-v2.c | 814 ++++++++++++++++++++++++++++ 5 files changed, 1155 insertions(+), 1022 deletions(-) diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h index b1c3abd0975b..b21c5cb3dd67 100644 --- a/include/efi_tcg2.h +++ b/include/efi_tcg2.h @@ -129,50 +129,6 @@ struct efi_tcg2_boot_service_capability { #define BOOT_SERVICE_CAPABILITY_MIN \ offsetof(struct efi_tcg2_boot_service_capability, number_of_pcr_banks) -#define TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03 "Spec ID Event03" -#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2 2 -#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 0 -#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2 2 - -/** - * struct TCG_EfiSpecIdEventAlgorithmSize - hashing algorithm information - * - * @algorithm_id: algorithm defined in enum tpm2_algorithms - * @digest_size: size of the algorithm - */ -struct tcg_efi_spec_id_event_algorithm_size { - u16 algorithm_id; - u16 digest_size; -} __packed; - -/** - * struct TCG_EfiSpecIDEventStruct - content of the event log header - * - * @signature: signature, set to Spec ID Event03 - * @platform_class: class defined in TCG ACPI Specification - * Client Common Header. - * @spec_version_minor: minor version - * @spec_version_major: major version - * @spec_version_errata: major version - * @uintn_size: size of the efi_uintn_t fields used in various - * data structures used in this specification. - * 0x01 indicates u32 and 0x02 indicates u64 - * @number_of_algorithms: hashing algorithms used in this event log - * @digest_sizes: array of number_of_algorithms pairs - * 1st member defines the algorithm id - * 2nd member defines the algorithm size - */ -struct tcg_efi_spec_id_event { - u8 signature[16]; - u32 platform_class; - u8 spec_version_minor; - u8 spec_version_major; - u8 spec_errata; - u8 uintn_size; - u32 number_of_algorithms; - struct tcg_efi_spec_id_event_algorithm_size digest_sizes[]; -} __packed; - /** * struct tdEFI_TCG2_FINAL_EVENTS_TABLE - log entries after Get Event Log * @version: version number for this structure diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 6684033debef..33dd103767c4 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -216,6 +216,50 @@ struct tcg_pcr_event2 { u8 event[]; } __packed; +/** + * struct TCG_EfiSpecIdEventAlgorithmSize - hashing algorithm information + * + * @algorithm_id: algorithm defined in enum tpm2_algorithms + * @digest_size: size of the algorithm + */ +struct tcg_efi_spec_id_event_algorithm_size { + u16 algorithm_id; + u16 digest_size; +} __packed; + +#define TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03 "Spec ID Event03" +#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2 2 +#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 0 +#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2 2 + +/** + * struct TCG_EfiSpecIDEventStruct - content of the event log header + * + * @signature: signature, set to Spec ID Event03 + * @platform_class: class defined in TCG ACPI Specification + * Client Common Header. + * @spec_version_minor: minor version + * @spec_version_major: major version + * @spec_version_errata: major version + * @uintn_size: size of the efi_uintn_t fields used in various + * data structures used in this specification. + * 0x01 indicates u32 and 0x02 indicates u64 + * @number_of_algorithms: hashing algorithms used in this event log + * @digest_sizes: array of number_of_algorithms pairs + * 1st member defines the algorithm id + * 2nd member defines the algorithm size + */ +struct tcg_efi_spec_id_event { + u8 signature[16]; + u32 platform_class; + u8 spec_version_minor; + u8 spec_version_major; + u8 spec_errata; + u8 uintn_size; + u32 number_of_algorithms; + struct tcg_efi_spec_id_event_algorithm_size digest_sizes[]; +} __packed; + /** * TPM2 Structure Tags for command/response buffers. * @@ -342,6 +386,26 @@ enum tpm2_algorithms { TPM2_ALG_SM3_256 = 0x12, }; +extern const enum tpm2_algorithms tpm2_supported_algorithms[4]; + +static inline u16 tpm2_algorithm_to_len(enum tpm2_algorithms a) +{ + switch (a) { + case TPM2_ALG_SHA1: + return TPM2_SHA1_DIGEST_SIZE; + case TPM2_ALG_SHA256: + return TPM2_SHA256_DIGEST_SIZE; + case TPM2_ALG_SHA384: + return TPM2_SHA384_DIGEST_SIZE; + case TPM2_ALG_SHA512: + return TPM2_SHA512_DIGEST_SIZE; + default: + return 0; + } +} + +#define tpm2_algorithm_to_mask(a) (1 << (a)) + /* NV index attributes */ enum tpm_index_attrs { TPMA_NV_PPWRITE = 1UL << 0, @@ -421,6 +485,188 @@ enum { HR_NV_INDEX = TPM_HT_NV_INDEX << HR_SHIFT, }; +/** + * struct tcg2_event_log - Container for managing the platform event log + * + * @log: Address of the log + * @log_position: Current entry position + * @log_size: Log space available + * @found: Boolean indicating if an existing log was discovered + */ +struct tcg2_event_log { + u8 *log; + u32 log_position; + u32 log_size; + bool found; +}; + +/** + * Create a list of digests of the supported PCR banks for a given input data + * + * @dev TPM device + * @input Data + * @length Length of the data to calculate the digest + * @digest_list List of digests to fill in + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length, + struct tpml_digest_values *digest_list); + +/** + * Get the event size of the specified digests + * + * @digest_list List of digests for the event + * + * Return: Size in bytes of the event + */ +u32 tcg2_event_get_size(struct tpml_digest_values *digest_list); + +/** + * tcg2_get_active_pcr_banks + * + * @dev TPM device + * @active_pcr_banks Bitmask of PCR algorithms supported + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks); + +/** + * tcg2_log_append - Append an event to an event log + * + * @pcr_index Index of the PCR + * @event_type Type of event + * @digest_list List of digests to add + * @size Size of event + * @event Event data + * @log Log buffer to append the event to + */ +void tcg2_log_append(u32 pcr_index, u32 event_type, + struct tpml_digest_values *digest_list, u32 size, + const u8 *event, u8 *log); + +/** + * Extend the PCR with specified digests + * + * @dev TPM device + * @pcr_index Index of the PCR + * @digest_list List of digests to extend + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list); + +/** + * Read the PCR into a list of digests + * + * @dev TPM device + * @pcr_index Index of the PCR + * @digest_list List of digests to extend + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_pcr_read(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list); + +/** + * Measure data into the TPM PCRs and the platform event log. + * + * @dev TPM device + * @log Platform event log + * @pcr_index Index of the PCR + * @size Size of the data or 0 for event only + * @data Pointer to the data or NULL for event only + * @event_type Event log type + * @event_size Size of the event + * @event Pointer to the event + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog, + u32 pcr_index, u32 size, const u8 *data, u32 event_type, + u32 event_size, const u8 *event); + +#define tcg2_measure_event(dev, elog, pcr_index, event_type, size, event) \ + tcg2_measure_data(dev, elog, pcr_index, 0, NULL, event_type, size, \ + event) + +/** + * Prepare the event log buffer. This function tries to discover an existing + * event log in memory from a previous bootloader stage. If such a log exists + * and the PCRs are not extended, the log is "replayed" to extend the PCRs. + * If no log is discovered, create the log header. + * + * @dev TPM device + * @elog Platform event log. The log pointer and log_size + * members must be initialized to either 0 or to a valid + * memory region, in which case any existing log + * discovered will be copied to the specified memory + * region. + * @ignore_existing_log Boolean to indicate whether or not to ignore an + * existing platform log in memory + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, + bool ignore_existing_log); + +/** + * Begin measurements. + * + * @dev TPM device + * @elog Platform event log. The log pointer and log_size + * members must be initialized to either 0 or to a valid + * memory region, in which case any existing log + * discovered will be copied to the specified memory + * region. + * @ignore_existing_log Boolean to indicate whether or not to ignore an + * existing platform log in memory + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog, + bool ignore_existing_log); + +/** + * Stop measurements and record separator events. + * + * @dev TPM device + * @elog Platform event log + * @error Boolean to indicate whether an error ocurred or not + */ +void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog, + bool error); + +/** + * Get the platform event log address and size. + * + * @dev TPM device + * @addr Address of the log + * @size Size of the log + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size); + +/** + * Get the first TPM2 device found. + * + * @dev TPM device + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_platform_get_tpm2(struct udevice **dev); + +/** + * Platform-specific function for handling TPM startup errors + * + * @dev TPM device + * @rc The TPM response code + */ +void tcg2_platform_startup_error(struct udevice *dev, int rc); + /** * Issue a TPM2_Startup command. * @@ -540,6 +786,19 @@ u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz, u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property, void *buf, size_t prop_count); +/** + * tpm2_get_pcr_info() - 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, code of operation or negative errno on failure + */ +int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, + u32 *pcr_banks); + /** * Issue a TPM2_DictionaryAttackLockReset command. * diff --git a/lib/Kconfig b/lib/Kconfig index d8dac09ea843..8bf738f358d2 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -415,6 +415,10 @@ config TPM bool "Trusted Platform Module (TPM) Support" depends on DM imply DM_RNG + select SHA1 + select SHA256 + select SHA384 + select SHA512 help This enables support for TPMs which can be used to provide security features for your board. The TPM can be connected via LPC or I2C diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index a83ae7a46cf3..829bae74364c 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -66,35 +66,6 @@ static bool tcg2_efi_app_invoked; static const efi_guid_t efi_guid_tcg2_protocol = EFI_TCG2_PROTOCOL_GUID; static const efi_guid_t efi_guid_final_events = EFI_TCG2_FINAL_EVENTS_TABLE_GUID; -struct digest_info { - u16 hash_alg; - u32 hash_mask; - u16 hash_len; -}; - -static const struct digest_info hash_algo_list[] = { - { - TPM2_ALG_SHA1, - EFI_TCG2_BOOT_HASH_ALG_SHA1, - TPM2_SHA1_DIGEST_SIZE, - }, - { - TPM2_ALG_SHA256, - EFI_TCG2_BOOT_HASH_ALG_SHA256, - TPM2_SHA256_DIGEST_SIZE, - }, - { - TPM2_ALG_SHA384, - EFI_TCG2_BOOT_HASH_ALG_SHA384, - TPM2_SHA384_DIGEST_SIZE, - }, - { - TPM2_ALG_SHA512, - EFI_TCG2_BOOT_HASH_ALG_SHA512, - TPM2_SHA512_DIGEST_SIZE, - }, -}; - struct variable_info { const u16 *name; bool accept_empty; @@ -113,46 +84,6 @@ static struct variable_info secure_variables[] = { {u"AuditMode", false, 1}, }; -#define MAX_HASH_COUNT ARRAY_SIZE(hash_algo_list) - -/** - * alg_to_mask - Get a TCG hash mask for algorithms - * - * @hash_alg: TCG defined algorithm - * - * @Return: TCG hashing algorithm bitmaps, 0 if the algorithm is not supported - */ -static u32 alg_to_mask(u16 hash_alg) -{ - size_t i; - - for (i = 0; i < MAX_HASH_COUNT; i++) { - if (hash_algo_list[i].hash_alg == hash_alg) - return hash_algo_list[i].hash_mask; - } - - return 0; -} - -/** - * alg_to_len - Get a TCG hash len for algorithms - * - * @hash_alg: TCG defined algorithm - * - * @Return: len of chosen algorithm, 0 if the algorithm is not supported - */ -static u16 alg_to_len(u16 hash_alg) -{ - size_t i; - - for (i = 0; i < MAX_HASH_COUNT; i++) { - if (hash_algo_list[i].hash_alg == hash_alg) - return hash_algo_list[i].hash_len; - } - - return 0; -} - static bool is_tcg2_protocol_installed(void) { struct efi_handler *handler; @@ -162,145 +93,6 @@ static bool is_tcg2_protocol_installed(void) return ret == EFI_SUCCESS; } -static u32 tcg_event_final_size(struct tpml_digest_values *digest_list) -{ - u32 len; - size_t i; - - len = offsetof(struct tcg_pcr_event2, digests); - len += offsetof(struct tpml_digest_values, digests); - for (i = 0; i < digest_list->count; i++) { - u16 hash_alg = digest_list->digests[i].hash_alg; - - len += offsetof(struct tpmt_ha, digest); - len += alg_to_len(hash_alg); - } - len += sizeof(u32); /* tcg_pcr_event2 event_size*/ - - return len; -} - -/* tcg2_pcr_extend - Extend PCRs for a TPM2 device for a given tpml_digest_values - * - * @dev: device - * @digest_list: list of digest algorithms to extend - * - * @Return: status code - */ -static efi_status_t tcg2_pcr_extend(struct udevice *dev, u32 pcr_index, - struct tpml_digest_values *digest_list) -{ - u32 rc; - size_t i; - - for (i = 0; i < digest_list->count; i++) { - u32 alg = digest_list->digests[i].hash_alg; - - rc = tpm2_pcr_extend(dev, pcr_index, alg, - (u8 *)&digest_list->digests[i].digest, - alg_to_len(alg)); - if (rc) { - EFI_PRINT("Failed to extend PCR\n"); - return EFI_DEVICE_ERROR; - } - } - - return EFI_SUCCESS; -} - -/* tcg2_pcr_read - Read PCRs for a TPM2 device for a given tpml_digest_values - * - * @dev: device - * @pcr_index: PCR index - * @digest_list: list of digest algorithms to extend - * - * @Return: status code - */ -static efi_status_t tcg2_pcr_read(struct udevice *dev, u32 pcr_index, - struct tpml_digest_values *digest_list) -{ - struct tpm_chip_priv *priv; - unsigned int updates, pcr_select_min; - u32 rc; - size_t i; - - priv = dev_get_uclass_priv(dev); - if (!priv) - return EFI_DEVICE_ERROR; - - pcr_select_min = priv->pcr_select_min; - - for (i = 0; i < digest_list->count; i++) { - u16 hash_alg = digest_list->digests[i].hash_alg; - u8 *digest = (u8 *)&digest_list->digests[i].digest; - - rc = tpm2_pcr_read(dev, pcr_index, pcr_select_min, - hash_alg, digest, alg_to_len(hash_alg), - &updates); - if (rc) { - EFI_PRINT("Failed to read PCR\n"); - return EFI_DEVICE_ERROR; - } - } - - return EFI_SUCCESS; -} - -/* put_event - Append an agile event to an eventlog - * - * @pcr_index: PCR index - * @event_type: type of event added - * @digest_list: list of digest algorithms to add - * @size: size of event - * @event: event to add - * @log: log buffer to append the event - * - */ -static void put_event(u32 pcr_index, u32 event_type, - struct tpml_digest_values *digest_list, u32 size, - u8 event[], void *log) -{ - size_t pos; - size_t i; - u32 event_size; - - /* - * size refers to the length of event[] only, we need to check against - * the final tcg_pcr_event2 size - */ - event_size = size + tcg_event_final_size(digest_list); - - put_unaligned_le32(pcr_index, log); - pos = offsetof(struct tcg_pcr_event2, event_type); - put_unaligned_le32(event_type, (void *)((uintptr_t)log + pos)); - pos = offsetof(struct tcg_pcr_event2, digests); /* count */ - put_unaligned_le32(digest_list->count, (void *)((uintptr_t)log + pos)); - - pos += offsetof(struct tpml_digest_values, digests); - for (i = 0; i < digest_list->count; i++) { - u16 hash_alg = digest_list->digests[i].hash_alg; - u8 *digest = (u8 *)&digest_list->digests[i].digest; - - put_unaligned_le16(hash_alg, (void *)((uintptr_t)log + pos)); - pos += offsetof(struct tpmt_ha, digest); - memcpy((void *)((uintptr_t)log + pos), digest, alg_to_len(hash_alg)); - pos += alg_to_len(hash_alg); - } - - put_unaligned_le32(size, (void *)((uintptr_t)log + pos)); - pos += sizeof(u32); /* tcg_pcr_event2 event_size*/ - memcpy((void *)((uintptr_t)log + pos), event, size); - pos += size; - - /* - * make sure the calculated buffer is what we checked against - * This check should never fail. It checks the code above is - * calculating the right length for the event we are adding - */ - if (pos != event_size) - log_err("Appending to the EventLog failed\n"); -} - /* tcg2_agile_log_append - Append an agile event to an eventlog * * @pcr_index: PCR index @@ -317,7 +109,7 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type, u32 size, u8 event[]) { void *log = (void *)((uintptr_t)event_log.buffer + event_log.pos); - u32 event_size = size + tcg_event_final_size(digest_list); + u32 event_size = size + tcg2_event_get_size(digest_list); struct efi_tcg2_final_events_table *final_event; efi_status_t ret = EFI_SUCCESS; @@ -328,7 +120,7 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type, event_log.truncated = true; return EFI_VOLUME_FULL; } - put_event(pcr_index, event_type, digest_list, size, event, log); + tcg2_log_append(pcr_index, event_type, digest_list, size, event, log); event_log.pos += event_size; event_log.last_event_size = event_size; } @@ -341,7 +133,7 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type, return EFI_VOLUME_FULL; log = (void *)((uintptr_t)event_log.final_buffer + event_log.final_pos); - put_event(pcr_index, event_type, digest_list, size, event, log); + tcg2_log_append(pcr_index, event_type, digest_list, size, event, log); final_event = event_log.final_buffer; final_event->number_of_events++; @@ -350,66 +142,6 @@ static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type, return ret; } -/** - * 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) -{ - for_each_tpm_device(*dev) { - /* Only support TPMv2 devices */ - if (tpm_get_version(*dev) == TPM_V2) - return EFI_SUCCESS; - } - - return EFI_NOT_FOUND; -} - -/** - * platform_get_eventlog() - retrieve the eventlog address and size - * - * This function retrieves the eventlog address and size if the underlying - * firmware has done some measurements and passed them. - * - * This function may be overridden based on platform specific method of - * passing the eventlog address and size. - * - * @dev: udevice - * @addr: eventlog address - * @sz: eventlog size - * Return: status code - */ -__weak efi_status_t platform_get_eventlog(struct udevice *dev, u64 *addr, - u32 *sz) -{ - const u64 *basep; - const u32 *sizep; - - basep = dev_read_prop(dev, "tpm_event_log_addr", NULL); - if (!basep) - return EFI_NOT_FOUND; - - *addr = be64_to_cpup((__force __be64 *)basep); - - sizep = dev_read_prop(dev, "tpm_event_log_size", NULL); - if (!sizep) - return EFI_NOT_FOUND; - - *sz = be32_to_cpup((__force __be32 *)sizep); - if (*sz == 0) { - log_debug("event log empty\n"); - return EFI_NOT_FOUND; - } - - return EFI_SUCCESS; -} - /** * tpm2_get_max_command_size() - get the supported max command size * @@ -485,239 +217,6 @@ static int tpm2_get_manufacturer_id(struct udevice *dev, u32 *manufacturer_id) return 0; } -/** - * tpm2_get_num_pcr() - get the number of PCRs - * - * @dev: TPM device - * @manufacturer_id: output buffer for the number - * - * Return: 0 on success, -1 on error - */ -static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr) -{ - u8 response[TPM2_RESPONSE_BUFFER_SIZE]; - u32 ret; - - memset(response, 0, sizeof(response)); - ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES, - TPM2_PT_PCR_COUNT, response, 1); - if (ret) - return -1; - - *num_pcr = get_unaligned_be32(response + properties_offset); - if (*num_pcr > TPM2_MAX_PCRS) - return -1; - - return 0; -} - -/** - * is_active_pcr() - Check if a supported algorithm is active - * - * @dev: TPM device - * @selection: struct of PCR information - * - * Return: true if PCR is active - */ -static 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() - 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[TPM2_RESPONSE_BUFFER_SIZE]; - struct tpml_pcr_selection pcrs; - u32 ret, num_pcr; - size_t i; - int tpm_ret; - - *supported_pcr = 0; - *active_pcr = 0; - *pcr_banks = 0; - memset(response, 0, sizeof(response)); - ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1); - if (ret) - goto out; - - pcrs.count = get_unaligned_be32(response); - /* - * We only support 5 algorithms for now so check against that - * instead of TPM2_NUM_PCR_BANKS - */ - if (pcrs.count > MAX_HASH_COUNT || pcrs.count < 1) - goto out; - - tpm_ret = tpm2_get_num_pcr(dev, &num_pcr); - if (tpm_ret) - goto out; - - for (i = 0; i < pcrs.count; i++) { - /* - * Definition of TPMS_PCR_SELECTION Structure - * hash: u16 - * size_of_select: u8 - * pcr_select: u8 array - * - * The offsets depend on the number of the device PCRs - * so we have to calculate them based on that - */ - u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) + - i * offsetof(struct tpms_pcr_selection, pcr_select) + - i * ((num_pcr + 7) / 8); - 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); - if (pcrs.selection[i].size_of_select > TPM2_PCR_SELECT_MAX) - goto out; - /* 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++) { - u32 hash_mask = alg_to_mask(pcrs.selection[i].hash); - - if (hash_mask) { - *supported_pcr |= hash_mask; - if (is_active_pcr(&pcrs.selection[i])) - *active_pcr |= hash_mask; - } else { - EFI_PRINT("Unknown algorithm %x\n", pcrs.selection[i].hash); - } - } - - *pcr_banks = pcrs.count; - - return 0; -out: - return -1; -} - -/** - * __get_active_pcr_banks() - returns the currently active PCR banks - * - * @active_pcr_banks: pointer for receiving the bitmap of currently - * active PCR banks - * - * Return: status code - */ -static efi_status_t __get_active_pcr_banks(u32 *active_pcr_banks) -{ - struct udevice *dev; - u32 active = 0, supported = 0, pcr_banks = 0; - efi_status_t ret; - int err; - - ret = platform_get_tpm2_device(&dev); - if (ret != EFI_SUCCESS) - goto out; - - err = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks); - if (err) { - ret = EFI_DEVICE_ERROR; - goto out; - } - - *active_pcr_banks = active; - -out: - return ret; -} - -/* tcg2_create_digest - create a list of digests of the supported PCR banks - * for a given memory range - * - * @input: input memory - * @length: length of buffer to calculate the digest - * @digest_list: list of digests to fill in - * - * Return: status code - */ -static efi_status_t tcg2_create_digest(const u8 *input, u32 length, - struct tpml_digest_values *digest_list) -{ - sha1_context ctx; - sha256_context ctx_256; - sha512_context ctx_512; - u8 final[TPM2_SHA512_DIGEST_SIZE]; - efi_status_t ret; - u32 active; - size_t i; - - ret = __get_active_pcr_banks(&active); - if (ret != EFI_SUCCESS) - return ret; - - digest_list->count = 0; - for (i = 0; i < MAX_HASH_COUNT; i++) { - u16 hash_alg = hash_algo_list[i].hash_alg; - - if (!(active & alg_to_mask(hash_alg))) - continue; - switch (hash_alg) { - case TPM2_ALG_SHA1: - sha1_starts(&ctx); - sha1_update(&ctx, input, length); - sha1_finish(&ctx, final); - break; - case TPM2_ALG_SHA256: - sha256_starts(&ctx_256); - sha256_update(&ctx_256, input, length); - sha256_finish(&ctx_256, final); - break; - case TPM2_ALG_SHA384: - sha384_starts(&ctx_512); - sha384_update(&ctx_512, input, length); - sha384_finish(&ctx_512, final); - break; - case TPM2_ALG_SHA512: - sha512_starts(&ctx_512); - sha512_update(&ctx_512, input, length); - sha512_finish(&ctx_512, final); - break; - default: - EFI_PRINT("Unsupported algorithm %x\n", hash_alg); - return EFI_INVALID_PARAMETER; - } - digest_list->digests[digest_list->count].hash_alg = hash_alg; - memcpy(&digest_list->digests[digest_list->count].digest, final, - (u32)alg_to_len(hash_alg)); - digest_list->count++; - } - - return EFI_SUCCESS; -} - /** * efi_tcg2_get_capability() - protocol capability information and state information * @@ -759,7 +258,7 @@ efi_tcg2_get_capability(struct efi_tcg2_protocol *this, capability->protocol_version.major = 1; capability->protocol_version.minor = 1; - efi_ret = platform_get_tpm2_device(&dev); + efi_ret = tcg2_platform_get_tpm2(&dev); if (efi_ret != EFI_SUCCESS) { capability->supported_event_logs = 0; capability->hash_algorithm_bitmap = 0; @@ -855,7 +354,7 @@ efi_tcg2_get_eventlog(struct efi_tcg2_protocol *this, goto out; } - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) { event_log_location = NULL; event_log_last_entry = NULL; @@ -890,6 +389,7 @@ static efi_status_t tcg2_hash_pe_image(void *efi, u64 efi_size, struct efi_image_regions *regs = NULL; void *new_efi = NULL; u8 hash[TPM2_SHA512_DIGEST_SIZE]; + struct udevice *dev; efi_status_t ret; u32 active; int i; @@ -905,16 +405,20 @@ static efi_status_t tcg2_hash_pe_image(void *efi, u64 efi_size, goto out; } - ret = __get_active_pcr_banks(&active); + ret = tcg2_platform_get_tpm2(&dev); + if (ret != EFI_SUCCESS) + goto out; + + ret = tcg2_get_active_pcr_banks(dev, &active); if (ret != EFI_SUCCESS) { goto out; } digest_list->count = 0; - for (i = 0; i < MAX_HASH_COUNT; i++) { - u16 hash_alg = hash_algo_list[i].hash_alg; + for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); i++) { + u16 hash_alg = tpm2_supported_algorithms[i]; - if (!(active & alg_to_mask(hash_alg))) + if (!(active & tpm2_algorithm_to_mask(hash_alg))) continue; switch (hash_alg) { case TPM2_ALG_SHA1: @@ -935,7 +439,7 @@ static efi_status_t tcg2_hash_pe_image(void *efi, u64 efi_size, } digest_list->digests[digest_list->count].hash_alg = hash_alg; memcpy(&digest_list->digests[digest_list->count].digest, hash, - (u32)alg_to_len(hash_alg)); + (u32)tpm2_algorithm_to_len(hash_alg)); digest_list->count++; } @@ -975,7 +479,7 @@ efi_status_t tcg2_measure_pe_image(void *efi, u64 efi_size, if (!is_tcg2_protocol_installed()) return EFI_SUCCESS; - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) return EFI_SECURITY_VIOLATION; @@ -1084,7 +588,7 @@ efi_tcg2_hash_log_extend_event(struct efi_tcg2_protocol *this, u64 flags, goto out; } - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) goto out; @@ -1119,7 +623,7 @@ efi_tcg2_hash_log_extend_event(struct efi_tcg2_protocol *this, u64 flags, ret = tcg2_hash_pe_image((void *)(uintptr_t)data_to_hash, data_to_hash_len, &digest_list); } else { - ret = tcg2_create_digest((u8 *)(uintptr_t)data_to_hash, + ret = tcg2_create_digest(dev, (u8 *)(uintptr_t)data_to_hash, data_to_hash_len, &digest_list); } @@ -1182,7 +686,7 @@ efi_tcg2_submit_command(struct efi_tcg2_protocol *this, goto out; } - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) goto out; @@ -1211,15 +715,20 @@ static efi_status_t EFIAPI efi_tcg2_get_active_pcr_banks(struct efi_tcg2_protocol *this, u32 *active_pcr_banks) { + struct udevice *dev; efi_status_t ret; + EFI_ENTRY("%p, %p", this, active_pcr_banks); + if (!this || !active_pcr_banks) { ret = EFI_INVALID_PARAMETER; goto out; } + ret = tcg2_platform_get_tpm2(&dev); + if (ret != EFI_SUCCESS) + goto out; - EFI_ENTRY("%p, %p", this, active_pcr_banks); - ret = __get_active_pcr_banks(active_pcr_banks); + ret = tcg2_get_active_pcr_banks(dev, active_pcr_banks); out: return EFI_EXIT(ret); @@ -1270,397 +779,6 @@ static const struct efi_tcg2_protocol efi_tcg2_protocol = { .get_result_of_set_active_pcr_banks = efi_tcg2_get_result_of_set_active_pcr_banks, }; -/** - * parse_event_log_header() - Parse and verify the event log header fields - * - * @buffer: Pointer to the start of the eventlog - * @size: Size of the eventlog - * @pos: Return offset of the next event in buffer right - * after the event header i.e specID - * - * Return: status code - */ -static efi_status_t parse_event_log_header(void *buffer, u32 size, u32 *pos) -{ - struct tcg_pcr_event *event_header = (struct tcg_pcr_event *)buffer; - int i = 0; - - if (size < sizeof(*event_header)) - return EFI_COMPROMISED_DATA; - - if (get_unaligned_le32(&event_header->pcr_index) != 0 || - get_unaligned_le32(&event_header->event_type) != EV_NO_ACTION) - return EFI_COMPROMISED_DATA; - - for (i = 0; i < sizeof(event_header->digest); i++) { - if (event_header->digest[i]) - return EFI_COMPROMISED_DATA; - } - - *pos += sizeof(*event_header); - - return EFI_SUCCESS; -} - -/** - * parse_specid_event() - Parse and verify the specID Event in the eventlog - * - * @dev: udevice - * @buffer: Pointer to the start of the eventlog - * @log_size: Size of the eventlog - * @pos: [in] Offset of specID event in the eventlog buffer - * [out] Return offset of the next event in the buffer - * after the specID - * @digest_list: list of digests in the event - * - * Return: status code - * @pos Offset in the eventlog where the specID event ends - * @digest_list: list of digests in the event - */ -static efi_status_t parse_specid_event(struct udevice *dev, void *buffer, - u32 log_size, u32 *pos, - struct tpml_digest_values *digest_list) -{ - struct tcg_efi_spec_id_event *spec_event; - struct tcg_pcr_event *event_header = (struct tcg_pcr_event *)buffer; - size_t spec_event_size; - u32 active = 0, supported = 0, pcr_count = 0, alg_count = 0; - u32 spec_active = 0; - u16 hash_alg; - u8 vendor_sz; - int err, i; - - if (*pos >= log_size || (*pos + sizeof(*spec_event)) > log_size) - return EFI_COMPROMISED_DATA; - - /* Check specID event data */ - spec_event = (struct tcg_efi_spec_id_event *)((uintptr_t)buffer + *pos); - /* Check for signature */ - if (memcmp(spec_event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, - sizeof(TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03))) { - log_err("specID Event: Signature mismatch\n"); - return EFI_COMPROMISED_DATA; - } - - if (spec_event->spec_version_minor != - TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 || - spec_event->spec_version_major != - TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2) - return EFI_COMPROMISED_DATA; - - if (spec_event->number_of_algorithms > MAX_HASH_COUNT || - spec_event->number_of_algorithms < 1) { - log_err("specID Event: Number of algorithms incorrect\n"); - return EFI_COMPROMISED_DATA; - } - - alg_count = spec_event->number_of_algorithms; - - err = tpm2_get_pcr_info(dev, &supported, &active, &pcr_count); - if (err) - return EFI_DEVICE_ERROR; - - digest_list->count = 0; - /* - * We have to take care that the sequence of algorithms that we record - * in digest_list matches the sequence in eventlog. - */ - for (i = 0; i < alg_count; i++) { - hash_alg = - get_unaligned_le16(&spec_event->digest_sizes[i].algorithm_id); - - if (!(supported & alg_to_mask(hash_alg))) { - log_err("specID Event: Unsupported algorithm\n"); - return EFI_COMPROMISED_DATA; - } - digest_list->digests[digest_list->count++].hash_alg = hash_alg; - - spec_active |= alg_to_mask(hash_alg); - } - - /* - * TCG specification expects the event log to have hashes for all - * active PCR's - */ - if (spec_active != active) { - /* - * Previous stage bootloader should know all the active PCR's - * and use them in the Eventlog. - */ - log_err("specID Event: All active hash alg not present\n"); - return EFI_COMPROMISED_DATA; - } - - /* - * the size of the spec event and placement of vendor_info_size - * depends on supported algoriths - */ - spec_event_size = - offsetof(struct tcg_efi_spec_id_event, digest_sizes) + - alg_count * sizeof(spec_event->digest_sizes[0]); - - if (*pos + spec_event_size >= log_size) - return EFI_COMPROMISED_DATA; - - vendor_sz = *(uint8_t *)((uintptr_t)buffer + *pos + spec_event_size); - - spec_event_size += sizeof(vendor_sz) + vendor_sz; - *pos += spec_event_size; - - if (get_unaligned_le32(&event_header->event_size) != spec_event_size) { - log_err("specID event: header event size mismatch\n"); - /* Right way to handle this can be to call SetActive PCR's */ - return EFI_COMPROMISED_DATA; - } - - return EFI_SUCCESS; -} - -/** - * tcg2_parse_event() - Parse the event in the eventlog - * - * @dev: udevice - * @buffer: Pointer to the start of the eventlog - * @log_size: Size of the eventlog - * @offset: [in] Offset of the event in the eventlog buffer - * [out] Return offset of the next event in the buffer - * @digest_list: list of digests in the event - * @pcr Index of the PCR in the event - * - * Return: status code - */ -static efi_status_t tcg2_parse_event(struct udevice *dev, void *buffer, - u32 log_size, u32 *offset, - struct tpml_digest_values *digest_list, - u32 *pcr) -{ - struct tcg_pcr_event2 *event = NULL; - u32 count, size, event_size; - size_t pos; - - event_size = tcg_event_final_size(digest_list); - if (*offset >= log_size || *offset + event_size > log_size) { - log_err("Event exceeds log size\n"); - return EFI_COMPROMISED_DATA; - } - - event = (struct tcg_pcr_event2 *)((uintptr_t)buffer + *offset); - *pcr = get_unaligned_le32(&event->pcr_index); - - /* get the count */ - count = get_unaligned_le32(&event->digests.count); - if (count != digest_list->count) - return EFI_COMPROMISED_DATA; - - pos = offsetof(struct tcg_pcr_event2, digests); - pos += offsetof(struct tpml_digest_values, digests); - - for (int i = 0; i < digest_list->count; i++) { - u16 alg; - u16 hash_alg = digest_list->digests[i].hash_alg; - u8 *digest = (u8 *)&digest_list->digests[i].digest; - - alg = get_unaligned_le16((void *)((uintptr_t)event + pos)); - - if (alg != hash_alg) - return EFI_COMPROMISED_DATA; - - pos += offsetof(struct tpmt_ha, digest); - memcpy(digest, (void *)((uintptr_t)event + pos), alg_to_len(hash_alg)); - pos += alg_to_len(hash_alg); - } - - size = get_unaligned_le32((void *)((uintptr_t)event + pos)); - event_size += size; - pos += sizeof(u32); /* tcg_pcr_event2 event_size*/ - pos += size; - - /* make sure the calculated buffer is what we checked against */ - if (pos != event_size) - return EFI_COMPROMISED_DATA; - - if (pos > log_size) - return EFI_COMPROMISED_DATA; - - *offset += pos; - - return EFI_SUCCESS; -} - -/** - * tcg2_get_fw_eventlog() - Get the eventlog address and size - * - * If the previous firmware has passed some eventlog, this function get it's - * location and check for it's validity. - * - * @dev: udevice - * @log_buffer: eventlog address - * @log_sz: eventlog size - * - * Return: status code - */ -static efi_status_t tcg2_get_fw_eventlog(struct udevice *dev, void *log_buffer, - size_t *log_sz) -{ - struct tpml_digest_values digest_list; - void *buffer; - efi_status_t ret; - u32 pcr, pos; - u64 base; - u32 sz; - bool extend_pcr = false; - int i; - - ret = platform_get_eventlog(dev, &base, &sz); - if (ret != EFI_SUCCESS) - return ret; - - if (sz > TPM2_EVENT_LOG_SIZE) - return EFI_VOLUME_FULL; - - buffer = (void *)(uintptr_t)base; - pos = 0; - /* Parse the eventlog to check for its validity */ - ret = parse_event_log_header(buffer, sz, &pos); - if (ret) - return ret; - - ret = parse_specid_event(dev, buffer, sz, &pos, &digest_list); - if (ret) { - log_err("Error parsing SPEC ID Event\n"); - return ret; - } - - ret = tcg2_pcr_read(dev, 0, &digest_list); - if (ret) { - log_err("Error reading PCR 0\n"); - return ret; - } - - /* - * If PCR0 is 0, previous firmware didn't have the capability - * to extend the PCR. In this scenario, extend the PCR as - * the eventlog is parsed. - */ - for (i = 0; i < digest_list.count; i++) { - u8 hash_buf[TPM2_SHA512_DIGEST_SIZE] = { 0 }; - u16 hash_alg = digest_list.digests[i].hash_alg; - - if (!memcmp((u8 *)&digest_list.digests[i].digest, hash_buf, - alg_to_len(hash_alg))) - extend_pcr = true; - } - - while (pos < sz) { - ret = tcg2_parse_event(dev, buffer, sz, &pos, &digest_list, - &pcr); - if (ret) { - log_err("Error parsing event\n"); - return ret; - } - if (extend_pcr) { - ret = tcg2_pcr_extend(dev, pcr, &digest_list); - if (ret != EFI_SUCCESS) { - log_err("Error in extending PCR\n"); - return ret; - } - - /* Clear the digest for next event */ - for (i = 0; i < digest_list.count; i++) { - u16 hash_alg = digest_list.digests[i].hash_alg; - u8 *digest = - (u8 *)&digest_list.digests[i].digest; - - memset(digest, 0, alg_to_len(hash_alg)); - } - } - } - - memcpy(log_buffer, buffer, sz); - *log_sz = sz; - - return ret; -} - -/** - * create_specid_event() - Create the first event in the eventlog - * - * @dev: tpm device - * @event_header: Pointer to the final event header - * @event_size: final spec event size - * - * Return: status code - */ -static efi_status_t create_specid_event(struct udevice *dev, void *buffer, - size_t *event_size) -{ - struct tcg_efi_spec_id_event *spec_event; - size_t spec_event_size; - efi_status_t ret = EFI_DEVICE_ERROR; - u32 active = 0, supported = 0, pcr_count = 0, alg_count = 0; - int err; - size_t i; - - /* - * Create Spec event. This needs to be the first event in the log - * according to the TCG EFI protocol spec - */ - - /* Setup specID event data */ - spec_event = (struct tcg_efi_spec_id_event *)buffer; - memcpy(spec_event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, - sizeof(spec_event->signature)); - put_unaligned_le32(0, &spec_event->platform_class); /* type client */ - spec_event->spec_version_minor = - TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2; - spec_event->spec_version_major = - TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2; - spec_event->spec_errata = - TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2; - spec_event->uintn_size = sizeof(efi_uintn_t) / sizeof(u32); - - err = tpm2_get_pcr_info(dev, &supported, &active, &pcr_count); - - if (err) - goto out; - - for (i = 0; i < pcr_count; i++) { - u16 hash_alg = hash_algo_list[i].hash_alg; - u16 hash_len = hash_algo_list[i].hash_len; - - if (active & alg_to_mask(hash_alg)) { - put_unaligned_le16(hash_alg, - &spec_event->digest_sizes[alg_count].algorithm_id); - put_unaligned_le16(hash_len, - &spec_event->digest_sizes[alg_count].digest_size); - alg_count++; - } - } - - spec_event->number_of_algorithms = alg_count; - if (spec_event->number_of_algorithms > MAX_HASH_COUNT || - spec_event->number_of_algorithms < 1) - goto out; - - /* - * the size of the spec event and placement of vendor_info_size - * depends on supported algoriths - */ - spec_event_size = - offsetof(struct tcg_efi_spec_id_event, digest_sizes) + - spec_event->number_of_algorithms * sizeof(spec_event->digest_sizes[0]); - /* no vendor info for us */ - memset(buffer + spec_event_size, 0, 1); - /* add a byte for vendor_info_size in the spec event */ - spec_event_size += 1; - *event_size = spec_event_size; - - return EFI_SUCCESS; - -out: - return ret; -} - /** * tcg2_uninit - remove the final event table and free efi memory on failures */ @@ -1722,7 +840,7 @@ out: } /** - * tcg2_measure_event() - common function to add event log and extend PCR + * measure_event() - common function to add event log and extend PCR * * @dev: TPM device * @pcr_index: PCR index @@ -1732,14 +850,13 @@ out: * * Return: status code */ -static efi_status_t -tcg2_measure_event(struct udevice *dev, u32 pcr_index, u32 event_type, - u32 size, u8 event[]) +static efi_status_t measure_event(struct udevice *dev, u32 pcr_index, + u32 event_type, u32 size, u8 event[]) { struct tpml_digest_values digest_list; efi_status_t ret; - ret = tcg2_create_digest(event, size, &digest_list); + ret = tcg2_create_digest(dev, event, size, &digest_list); if (ret != EFI_SUCCESS) goto out; @@ -1766,9 +883,8 @@ static efi_status_t efi_append_scrtm_version(struct udevice *dev) { efi_status_t ret; - ret = tcg2_measure_event(dev, 0, EV_S_CRTM_VERSION, - strlen(version_string) + 1, - (u8 *)version_string); + ret = measure_event(dev, 0, EV_S_CRTM_VERSION, + strlen(version_string) + 1, (u8 *)version_string); return ret; } @@ -1784,12 +900,11 @@ static efi_status_t efi_init_event_log(void) * vendor_info_size is currently set to 0, we need to change the length * and allocate the flexible array member if this changes */ - struct tcg_pcr_event *event_header = NULL; + struct tcg2_event_log elog; struct udevice *dev; - size_t spec_event_size; efi_status_t ret; - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) return ret; @@ -1808,7 +923,6 @@ static efi_status_t efi_init_event_log(void) * The log header is defined to be in SHA1 event log entry format. * Setup event header */ - event_header = (struct tcg_pcr_event *)event_log.buffer; event_log.pos = 0; event_log.last_event_size = 0; event_log.get_event_called = false; @@ -1819,34 +933,20 @@ static efi_status_t efi_init_event_log(void) * Check if earlier firmware have passed any eventlog. Different * platforms can use different ways to do so. */ - ret = tcg2_get_fw_eventlog(dev, event_log.buffer, &event_log.pos); + elog.log = event_log.buffer; + elog.log_size = TPM2_EVENT_LOG_SIZE; + ret = tcg2_log_prepare_buffer(dev, &elog, false); + if (ret != EFI_SUCCESS) + goto free_pool; + + event_log.pos = elog.log_position; + /* - * If earlier firmware hasn't passed any eventlog, go ahead and - * create the eventlog header. + * Add SCRTM version to the log if previous firmmware + * doesn't pass an eventlog. */ - if (ret == EFI_NOT_FOUND) { - put_unaligned_le32(0, &event_header->pcr_index); - put_unaligned_le32(EV_NO_ACTION, &event_header->event_type); - memset(&event_header->digest, 0, sizeof(event_header->digest)); - ret = create_specid_event(dev, - (void *)((uintptr_t)event_log.buffer + - sizeof(*event_header)), - &spec_event_size); - if (ret != EFI_SUCCESS) - goto free_pool; - put_unaligned_le32(spec_event_size, &event_header->event_size); - event_log.pos = spec_event_size + sizeof(*event_header); - event_log.last_event_size = event_log.pos; - - /* - * Add SCRTM version to the log if previous firmmware - * doesn't pass an eventlog. - */ + if (!elog.found) ret = efi_append_scrtm_version(dev); - } - - if (ret != EFI_SUCCESS) - goto free_pool; ret = create_final_event(); if (ret != EFI_SUCCESS) @@ -1899,8 +999,8 @@ static efi_status_t tcg2_measure_variable(struct udevice *dev, u32 pcr_index, memcpy((u16 *)event->unicode_name + event->unicode_name_length, data, data_size); } - ret = tcg2_measure_event(dev, pcr_index, event_type, event_size, - (u8 *)event); + ret = measure_event(dev, pcr_index, event_type, event_size, + (u8 *)event); free(event); return ret; } @@ -2011,8 +1111,8 @@ tcg2_measure_smbios(struct udevice *dev, smbios_prepare_measurement(entry, smbios_copy); - ret = tcg2_measure_event(dev, 1, EV_EFI_HANDOFF_TABLES2, event_size, - (u8 *)event); + ret = measure_event(dev, 1, EV_EFI_HANDOFF_TABLES2, event_size, + (u8 *)event); if (ret != EFI_SUCCESS) goto out; @@ -2163,7 +1263,7 @@ tcg2_measure_gpt_data(struct udevice *dev, gpt_e = (gpt_entry *)((u8 *)gpt_e + gpt_h->sizeof_partition_entry); } - ret = tcg2_measure_event(dev, 5, EV_EFI_GPT_EVENT, event_size, (u8 *)event); + ret = measure_event(dev, 5, EV_EFI_GPT_EVENT, event_size, (u8 *)event); out2: free(gpt_h); @@ -2217,7 +1317,7 @@ efi_status_t efi_tcg2_measure_dtb(void *dtb) if (!is_tcg2_protocol_installed()) return EFI_SUCCESS; - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) return EFI_SECURITY_VIOLATION; @@ -2242,7 +1342,7 @@ efi_status_t efi_tcg2_measure_dtb(void *dtb) sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_mem_rsvmap(dtb), rsvmap_size); sha256_finish(&hash_ctx, blob->data + blob->blob_description_size); - ret = tcg2_measure_event(dev, 0, EV_POST_CODE, event_size, (u8 *)blob); + ret = measure_event(dev, 0, EV_POST_CODE, event_size, (u8 *)blob); free(blob); return ret; @@ -2267,7 +1367,7 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *ha if (tcg2_efi_app_invoked) return EFI_SUCCESS; - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) return EFI_SECURITY_VIOLATION; @@ -2275,9 +1375,9 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *ha if (ret != EFI_SUCCESS) goto out; - ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION, - strlen(EFI_CALLING_EFI_APPLICATION), - (u8 *)EFI_CALLING_EFI_APPLICATION); + ret = measure_event(dev, 4, EV_EFI_ACTION, + strlen(EFI_CALLING_EFI_APPLICATION), + (u8 *)EFI_CALLING_EFI_APPLICATION); if (ret != EFI_SUCCESS) goto out; @@ -2293,8 +1393,8 @@ efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *ha goto out; for (pcr_index = 0; pcr_index <= 7; pcr_index++) { - ret = tcg2_measure_event(dev, pcr_index, EV_SEPARATOR, - sizeof(event), (u8 *)&event); + ret = measure_event(dev, pcr_index, EV_SEPARATOR, + sizeof(event), (u8 *)&event); if (ret != EFI_SUCCESS) goto out; } @@ -2317,13 +1417,13 @@ efi_status_t efi_tcg2_measure_efi_app_exit(void) if (!is_tcg2_protocol_installed()) return EFI_SUCCESS; - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) return ret; - ret = tcg2_measure_event(dev, 4, EV_EFI_ACTION, - strlen(EFI_RETURNING_FROM_EFI_APPLICATION), - (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION); + ret = measure_event(dev, 4, EV_EFI_ACTION, + strlen(EFI_RETURNING_FROM_EFI_APPLICATION), + (u8 *)EFI_RETURNING_FROM_EFI_APPLICATION); return ret; } @@ -2348,19 +1448,19 @@ efi_tcg2_notify_exit_boot_services(struct efi_event *event, void *context) goto out; } - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) goto out; - ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION, - strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION), - (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION); + ret = measure_event(dev, 5, EV_EFI_ACTION, + strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION), + (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION); if (ret != EFI_SUCCESS) goto out; - ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION, - strlen(EFI_EXIT_BOOT_SERVICES_SUCCEEDED), - (u8 *)EFI_EXIT_BOOT_SERVICES_SUCCEEDED); + ret = measure_event(dev, 5, EV_EFI_ACTION, + strlen(EFI_EXIT_BOOT_SERVICES_SUCCEEDED), + (u8 *)EFI_EXIT_BOOT_SERVICES_SUCCEEDED); out: EFI_EXIT(ret); @@ -2380,19 +1480,19 @@ efi_status_t efi_tcg2_notify_exit_boot_services_failed(void) if (!is_tcg2_protocol_installed()) return EFI_SUCCESS; - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) goto out; - ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION, - strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION), - (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION); + ret = measure_event(dev, 5, EV_EFI_ACTION, + strlen(EFI_EXIT_BOOT_SERVICES_INVOCATION), + (u8 *)EFI_EXIT_BOOT_SERVICES_INVOCATION); if (ret != EFI_SUCCESS) goto out; - ret = tcg2_measure_event(dev, 5, EV_EFI_ACTION, - strlen(EFI_EXIT_BOOT_SERVICES_FAILED), - (u8 *)EFI_EXIT_BOOT_SERVICES_FAILED); + ret = measure_event(dev, 5, EV_EFI_ACTION, + strlen(EFI_EXIT_BOOT_SERVICES_FAILED), + (u8 *)EFI_EXIT_BOOT_SERVICES_FAILED); out: return ret; @@ -2462,7 +1562,7 @@ efi_status_t efi_tcg2_do_initial_measurement(void) if (!is_tcg2_protocol_installed()) return EFI_SUCCESS; - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) return EFI_SECURITY_VIOLATION; @@ -2488,7 +1588,7 @@ efi_status_t efi_tcg2_register(void) struct efi_event *event; u32 err; - ret = platform_get_tpm2_device(&dev); + ret = tcg2_platform_get_tpm2(&dev); if (ret != EFI_SUCCESS) { log_warning("Missing TPMv2 device for EFI_TCG_PROTOCOL\n"); return EFI_SUCCESS; diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 9ab5b46df177..d22e21985b01 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -1,16 +1,705 @@ // SPDX-License-Identifier: GPL-2.0+ /* + * Copyright (c) 2023 Linaro Limited * Copyright (c) 2018 Bootlin * Author: Miquel Raynal */ #include #include +#include +#include #include #include +#include +#include +#include +#include +#include #include +#include +#include +#include + #include "tpm-utils.h" +const enum tpm2_algorithms tpm2_supported_algorithms[4] = { + TPM2_ALG_SHA1, + TPM2_ALG_SHA256, + TPM2_ALG_SHA384, + TPM2_ALG_SHA512, +}; + +int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks) +{ + u32 supported = 0; + u32 pcr_banks = 0; + u32 active = 0; + int rc; + + rc = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks); + if (rc) + return rc; + + *active_pcr_banks = active; + + return 0; +} + +u32 tcg2_event_get_size(struct tpml_digest_values *digest_list) +{ + u32 len; + size_t i; + + len = offsetof(struct tcg_pcr_event2, digests); + len += offsetof(struct tpml_digest_values, digests); + for (i = 0; i < digest_list->count; ++i) { + u16 l = tpm2_algorithm_to_len(digest_list->digests[i].hash_alg); + + if (!l) + continue; + + len += l + offsetof(struct tpmt_ha, digest); + } + len += sizeof(u32); + + return len; +} + +int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length, + struct tpml_digest_values *digest_list) +{ + u8 final[sizeof(union tpmu_ha)]; + sha256_context ctx_256; + sha512_context ctx_512; + sha1_context ctx; + u32 active; + size_t i; + u32 len; + int rc; + + rc = tcg2_get_active_pcr_banks(dev, &active); + if (rc) + return rc; + + digest_list->count = 0; + for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) { + u32 mask = + tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]); + + if (!(active & mask)) + continue; + + switch (tpm2_supported_algorithms[i]) { + case TPM2_ALG_SHA1: + sha1_starts(&ctx); + sha1_update(&ctx, input, length); + sha1_finish(&ctx, final); + len = TPM2_SHA1_DIGEST_SIZE; + break; + case TPM2_ALG_SHA256: + sha256_starts(&ctx_256); + sha256_update(&ctx_256, input, length); + sha256_finish(&ctx_256, final); + len = TPM2_SHA256_DIGEST_SIZE; + break; + case TPM2_ALG_SHA384: + sha384_starts(&ctx_512); + sha384_update(&ctx_512, input, length); + sha384_finish(&ctx_512, final); + len = TPM2_SHA384_DIGEST_SIZE; + break; + case TPM2_ALG_SHA512: + sha512_starts(&ctx_512); + sha512_update(&ctx_512, input, length); + sha512_finish(&ctx_512, final); + len = TPM2_SHA512_DIGEST_SIZE; + break; + default: + printf("%s: unsupported algorithm %x\n", __func__, + tpm2_supported_algorithms[i]); + continue; + } + + digest_list->digests[digest_list->count].hash_alg = + tpm2_supported_algorithms[i]; + memcpy(&digest_list->digests[digest_list->count].digest, final, + len); + digest_list->count++; + } + + return 0; +} + +void tcg2_log_append(u32 pcr_index, u32 event_type, + struct tpml_digest_values *digest_list, u32 size, + const u8 *event, u8 *log) +{ + size_t len; + size_t pos; + u32 i; + + pos = offsetof(struct tcg_pcr_event2, pcr_index); + put_unaligned_le32(pcr_index, log); + pos = offsetof(struct tcg_pcr_event2, event_type); + put_unaligned_le32(event_type, log + pos); + pos = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, count); + put_unaligned_le32(digest_list->count, log + pos); + + pos = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, digests); + for (i = 0; i < digest_list->count; ++i) { + u16 hash_alg = digest_list->digests[i].hash_alg; + + len = tpm2_algorithm_to_len(hash_alg); + if (!len) + continue; + + pos += offsetof(struct tpmt_ha, hash_alg); + put_unaligned_le16(hash_alg, log + pos); + pos += offsetof(struct tpmt_ha, digest); + memcpy(log + pos, (u8 *)&digest_list->digests[i].digest, len); + pos += len; + } + + put_unaligned_le32(size, log + pos); + pos += sizeof(u32); + memcpy(log + pos, event, size); +} + +static int tcg2_log_append_check(struct tcg2_event_log *elog, u32 pcr_index, + u32 event_type, + struct tpml_digest_values *digest_list, + u32 size, const u8 *event) +{ + u32 event_size; + u8 *log; + + event_size = size + tcg2_event_get_size(digest_list); + if (elog->log_position + event_size > elog->log_size) { + printf("%s: log too large: %u + %u > %u\n", __func__, + elog->log_position, event_size, elog->log_size); + return -ENOBUFS; + } + + log = elog->log + elog->log_position; + elog->log_position += event_size; + + tcg2_log_append(pcr_index, event_type, digest_list, size, event, log); + + return 0; +} + +static int tcg2_log_init(struct udevice *dev, struct tcg2_event_log *elog) +{ + struct tcg_efi_spec_id_event *ev; + struct tcg_pcr_event *log; + u32 event_size; + u32 count = 0; + u32 log_size; + u32 active; + u32 mask; + size_t i; + u16 len; + int rc; + + rc = tcg2_get_active_pcr_banks(dev, &active); + if (rc) + return rc; + + event_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes); + for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) { + mask = tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]); + + if (!(active & mask)) + continue; + + switch (tpm2_supported_algorithms[i]) { + case TPM2_ALG_SHA1: + case TPM2_ALG_SHA256: + case TPM2_ALG_SHA384: + case TPM2_ALG_SHA512: + count++; + break; + default: + continue; + } + } + + event_size += 1 + + (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count); + log_size = offsetof(struct tcg_pcr_event, event) + event_size; + + if (log_size > elog->log_size) { + printf("%s: log too large: %u > %u\n", __func__, log_size, + elog->log_size); + return -ENOBUFS; + } + + log = (struct tcg_pcr_event *)elog->log; + put_unaligned_le32(0, &log->pcr_index); + put_unaligned_le32(EV_NO_ACTION, &log->event_type); + memset(&log->digest, 0, sizeof(log->digest)); + put_unaligned_le32(event_size, &log->event_size); + + ev = (struct tcg_efi_spec_id_event *)log->event; + strlcpy((char *)ev->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, + sizeof(ev->signature)); + put_unaligned_le32(0, &ev->platform_class); + ev->spec_version_minor = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2; + ev->spec_version_major = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2; + ev->spec_errata = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2; + ev->uintn_size = sizeof(size_t) / sizeof(u32); + put_unaligned_le32(count, &ev->number_of_algorithms); + + count = 0; + for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) { + mask = tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]); + + if (!(active & mask)) + continue; + + len = tpm2_algorithm_to_len(tpm2_supported_algorithms[i]); + if (!len) + continue; + + put_unaligned_le16(tpm2_supported_algorithms[i], + &ev->digest_sizes[count].algorithm_id); + put_unaligned_le16(len, &ev->digest_sizes[count].digest_size); + count++; + } + + *((u8 *)ev + (event_size - 1)) = 0; + elog->log_position = log_size; + + return 0; +} + +static int tcg2_replay_eventlog(struct tcg2_event_log *elog, + struct udevice *dev, + struct tpml_digest_values *digest_list, + u32 log_position) +{ + const u32 offset = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, digests); + u32 event_size; + u32 count; + u16 algo; + u32 pcr; + u32 pos; + u16 len; + u8 *log; + int rc; + u32 i; + + while (log_position + offset < elog->log_size) { + log = elog->log + log_position; + + pos = offsetof(struct tcg_pcr_event2, pcr_index); + pcr = get_unaligned_le32(log + pos); + pos = offsetof(struct tcg_pcr_event2, event_type); + if (!get_unaligned_le32(log + pos)) + return 0; + + pos = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, count); + count = get_unaligned_le32(log + pos); + if (count > ARRAY_SIZE(tpm2_supported_algorithms) || + (digest_list->count && digest_list->count != count)) + return 0; + + pos = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, digests); + for (i = 0; i < count; ++i) { + pos += offsetof(struct tpmt_ha, hash_alg); + if (log_position + pos + sizeof(u16) >= elog->log_size) + return 0; + + algo = get_unaligned_le16(log + pos); + pos += offsetof(struct tpmt_ha, digest); + switch (algo) { + case TPM2_ALG_SHA1: + case TPM2_ALG_SHA256: + case TPM2_ALG_SHA384: + case TPM2_ALG_SHA512: + len = tpm2_algorithm_to_len(algo); + break; + default: + return 0; + } + + if (digest_list->count) { + if (algo != digest_list->digests[i].hash_alg || + log_position + pos + len >= elog->log_size) + return 0; + + memcpy(digest_list->digests[i].digest.sha512, + log + pos, len); + } + + pos += len; + } + + if (log_position + pos + sizeof(u32) >= elog->log_size) + return 0; + + event_size = get_unaligned_le32(log + pos); + pos += event_size + sizeof(u32); + if (log_position + pos > elog->log_size) + return 0; + + if (digest_list->count) { + rc = tcg2_pcr_extend(dev, pcr, digest_list); + if (rc) + return rc; + } + + log_position += pos; + } + + elog->log_position = log_position; + elog->found = true; + return 0; +} + +static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) +{ + struct tpml_digest_values digest_list; + struct tcg_efi_spec_id_event *event; + struct tcg_pcr_event *log; + u32 log_active; + u32 calc_size; + u32 active; + u32 count; + u32 evsz; + u32 mask; + u16 algo; + u16 len; + int rc; + u32 i; + u16 j; + + if (elog->log_size <= offsetof(struct tcg_pcr_event, event)) + return 0; + + log = (struct tcg_pcr_event *)elog->log; + if (get_unaligned_le32(&log->pcr_index) != 0 || + get_unaligned_le32(&log->event_type) != EV_NO_ACTION) + return 0; + + for (i = 0; i < sizeof(log->digest); i++) { + if (log->digest[i]) + return 0; + } + + evsz = get_unaligned_le32(&log->event_size); + if (evsz < offsetof(struct tcg_efi_spec_id_event, digest_sizes) || + evsz + offsetof(struct tcg_pcr_event, event) > elog->log_size) + return 0; + + event = (struct tcg_efi_spec_id_event *)log->event; + if (memcmp(event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, + sizeof(TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03))) + return 0; + + if (event->spec_version_minor != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 || + event->spec_version_major != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2) + return 0; + + count = get_unaligned_le32(&event->number_of_algorithms); + if (count > ARRAY_SIZE(tpm2_supported_algorithms)) + return 0; + + calc_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes) + + (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count) + + 1; + if (evsz != calc_size) + return 0; + + rc = tcg2_get_active_pcr_banks(dev, &active); + if (rc) + return rc; + + digest_list.count = 0; + log_active = 0; + + for (i = 0; i < count; ++i) { + algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id); + mask = tpm2_algorithm_to_mask(algo); + + if (!(active & mask)) + return 0; + + switch (algo) { + case TPM2_ALG_SHA1: + case TPM2_ALG_SHA256: + case TPM2_ALG_SHA384: + case TPM2_ALG_SHA512: + len = get_unaligned_le16(&event->digest_sizes[i].digest_size); + if (tpm2_algorithm_to_len(algo) != len) + return 0; + digest_list.digests[digest_list.count++].hash_alg = algo; + break; + default: + return 0; + } + + log_active |= mask; + } + + /* Ensure the previous firmware extended all the PCRs. */ + if (log_active != active) + return 0; + + /* Read PCR0 to check if previous firmware extended the PCRs or not. */ + rc = tcg2_pcr_read(dev, 0, &digest_list); + if (rc) + return rc; + + for (i = 0; i < digest_list.count; ++i) { + len = tpm2_algorithm_to_len(digest_list.digests[i].hash_alg); + for (j = 0; j < len; ++j) { + if (digest_list.digests[i].digest.sha512[j]) + break; + } + + /* PCR is non-zero; it has been extended, so skip extending. */ + if (j != len) { + digest_list.count = 0; + break; + } + } + + return tcg2_replay_eventlog(elog, dev, &digest_list, + offsetof(struct tcg_pcr_event, event) + + evsz); +} + +int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list) +{ + u32 rc; + u32 i; + + for (i = 0; i < digest_list->count; i++) { + u32 alg = digest_list->digests[i].hash_alg; + + rc = tpm2_pcr_extend(dev, pcr_index, alg, + (u8 *)&digest_list->digests[i].digest, + tpm2_algorithm_to_len(alg)); + if (rc) { + printf("%s: error pcr:%u alg:%08x\n", __func__, + pcr_index, alg); + return rc; + } + } + + return 0; +} + +int tcg2_pcr_read(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list) +{ + struct tpm_chip_priv *priv; + u32 rc; + u32 i; + + priv = dev_get_uclass_priv(dev); + if (!priv) + return -ENODEV; + + for (i = 0; i < digest_list->count; i++) { + u32 alg = digest_list->digests[i].hash_alg; + u8 *digest = (u8 *)&digest_list->digests[i].digest; + + rc = tpm2_pcr_read(dev, pcr_index, priv->pcr_select_min, alg, + digest, tpm2_algorithm_to_len(alg), NULL); + if (rc) { + printf("%s: error pcr:%u alg:%08x\n", __func__, + pcr_index, alg); + return rc; + } + } + + return 0; +} + +int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog, + u32 pcr_index, u32 size, const u8 *data, u32 event_type, + u32 event_size, const u8 *event) +{ + struct tpml_digest_values digest_list; + int rc; + + if (data) + rc = tcg2_create_digest(dev, data, size, &digest_list); + else + rc = tcg2_create_digest(dev, event, event_size, &digest_list); + if (rc) + return rc; + + rc = tcg2_pcr_extend(dev, pcr_index, &digest_list); + if (rc) + return rc; + + return tcg2_log_append_check(elog, pcr_index, event_type, &digest_list, + event_size, event); +} + +int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, + bool ignore_existing_log) +{ + struct tcg2_event_log log; + int rc; + + elog->log_position = 0; + elog->found = false; + + rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size); + if (!rc) { + log.log_position = 0; + log.found = false; + + if (!ignore_existing_log) { + rc = tcg2_log_parse(dev, &log); + if (rc) + return rc; + } + + if (elog->log_size) { + if (log.found) { + if (elog->log_size < log.log_position) + return -ENOSPC; + + /* + * Copy the discovered log into the user buffer + * if there's enough space. + */ + memcpy(elog->log, log.log, log.log_position); + } + + unmap_physmem(log.log, MAP_NOCACHE); + } else { + elog->log = log.log; + elog->log_size = log.log_size; + } + + elog->log_position = log.log_position; + elog->found = log.found; + } + + /* + * Initialize the log buffer if no log was discovered and the buffer is + * valid. User's can pass in their own buffer as a fallback if no + * memory region is found. + */ + if (!elog->found && elog->log_size) + rc = tcg2_log_init(dev, elog); + + return rc; +} + +int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog, + bool ignore_existing_log) +{ + int rc; + + rc = tcg2_platform_get_tpm2(dev); + if (rc) + return rc; + + rc = tpm_auto_start(*dev); + if (rc) + return rc; + + rc = tcg2_log_prepare_buffer(*dev, elog, ignore_existing_log); + if (rc) { + tcg2_measurement_term(*dev, elog, true); + return rc; + } + + rc = tcg2_measure_event(*dev, elog, 0, EV_S_CRTM_VERSION, + strlen(version_string) + 1, + (u8 *)version_string); + if (rc) { + tcg2_measurement_term(*dev, elog, true); + return rc; + } + + return 0; +} + +void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog, + bool error) +{ + u32 event = error ? 0x1 : 0xffffffff; + int i; + + for (i = 0; i < 8; ++i) + tcg2_measure_event(dev, elog, i, EV_SEPARATOR, sizeof(event), + (const u8 *)&event); + + if (elog->log) + unmap_physmem(elog->log, MAP_NOCACHE); +} + +__weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size) +{ + const __be32 *addr_prop; + const __be32 *size_prop; + int asize; + int ssize; + + *addr = NULL; + *size = 0; + + addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize); + if (!addr_prop) + addr_prop = dev_read_prop(dev, "linux,sml-base", &asize); + + size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize); + if (!size_prop) + size_prop = dev_read_prop(dev, "linux,sml-size", &ssize); + + if (addr_prop && size_prop) { + u64 a = of_read_number(addr_prop, asize / sizeof(__be32)); + u64 s = of_read_number(size_prop, ssize / sizeof(__be32)); + + *addr = map_physmem(a, s, MAP_NOCACHE); + *size = (u32)s; + } else { + struct ofnode_phandle_args args; + phys_addr_t a; + phys_size_t s; + + if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0, + 0, &args)) + return -ENODEV; + + a = ofnode_get_addr_size(args.node, "reg", &s); + if (a == FDT_ADDR_T_NONE) + return -ENOMEM; + + *addr = map_physmem(a, s, MAP_NOCACHE); + *size = (u32)s; + } + + return 0; +} + +__weak int tcg2_platform_get_tpm2(struct udevice **dev) +{ + for_each_tpm_device(*dev) { + if (tpm_get_version(*dev) == TPM_V2) + return 0; + } + + return -ENODEV; +} + +__weak void tcg2_platform_startup_error(struct udevice *dev, int rc) {} + u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode) { const u8 command_v2[12] = { @@ -359,6 +1048,131 @@ u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property, return 0; } +static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr) +{ + u8 response[(sizeof(struct tpms_capability_data) - + offsetof(struct tpms_capability_data, data))]; + u32 properties_offset = + offsetof(struct tpml_tagged_tpm_property, tpm_property) + + offsetof(struct tpms_tagged_property, value); + u32 ret; + + memset(response, 0, sizeof(response)); + ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES, + TPM2_PT_PCR_COUNT, response, 1); + if (ret) + return ret; + + *num_pcr = get_unaligned_be32(response + properties_offset); + if (*num_pcr > TPM2_MAX_PCRS) { + printf("%s: too many pcrs: %u\n", __func__, *num_pcr); + return -E2BIG; + } + + return 0; +} + +static bool tpm2_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; +} + +int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, + u32 *pcr_banks) +{ + u8 response[(sizeof(struct tpms_capability_data) - + offsetof(struct tpms_capability_data, data))]; + struct tpml_pcr_selection pcrs; + u32 num_pcr; + size_t i; + u32 ret; + + *supported_pcr = 0; + *active_pcr = 0; + *pcr_banks = 0; + memset(response, 0, sizeof(response)); + ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1); + if (ret) + return ret; + + pcrs.count = get_unaligned_be32(response); + /* + * We only support 5 algorithms for now so check against that + * instead of TPM2_NUM_PCR_BANKS + */ + if (pcrs.count > ARRAY_SIZE(tpm2_supported_algorithms) || + pcrs.count < 1) { + printf("%s: too many pcrs: %u\n", __func__, pcrs.count); + return -EMSGSIZE; + } + + ret = tpm2_get_num_pcr(dev, &num_pcr); + if (ret) + return ret; + + for (i = 0; i < pcrs.count; i++) { + /* + * Definition of TPMS_PCR_SELECTION Structure + * hash: u16 + * size_of_select: u8 + * pcr_select: u8 array + * + * The offsets depend on the number of the device PCRs + * so we have to calculate them based on that + */ + u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) + + i * offsetof(struct tpms_pcr_selection, pcr_select) + + i * ((num_pcr + 7) / 8); + 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); + if (pcrs.selection[i].size_of_select > TPM2_PCR_SELECT_MAX) { + printf("%s: pcrs selection too large: %u\n", __func__, + pcrs.selection[i].size_of_select); + return -ENOBUFS; + } + /* 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++) { + u32 hash_mask = tpm2_algorithm_to_mask(pcrs.selection[i].hash); + + if (hash_mask) { + *supported_pcr |= hash_mask; + if (tpm2_is_active_pcr(&pcrs.selection[i])) + *active_pcr |= hash_mask; + } else { + printf("%s: unknown algorithm %x\n", __func__, + pcrs.selection[i].hash); + } + } + + *pcr_banks = pcrs.count; + + return 0; +} + u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz) { u8 command_v2[COMMAND_BUFFER_SIZE] = {