diff options
author | Tom Rini <trini@konsulko.com> | 2024-06-30 10:59:42 -0600 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2024-06-30 10:59:42 -0600 |
commit | 2f9603392355e21c379b4adddea7c6b35cf09b9b (patch) | |
tree | 3341b0c0f5a604fe1b55781de81a7cad3f36bc10 | |
parent | 48641bfab793b5ffbf481ee2085fb8c0432da5fa (diff) | |
parent | 636480e4e7088d05d7ff77af72ca00443c62b3e9 (diff) | |
download | u-boot-2f9603392355e21c379b4adddea7c6b35cf09b9b.zip u-boot-2f9603392355e21c379b4adddea7c6b35cf09b9b.tar.gz u-boot-2f9603392355e21c379b4adddea7c6b35cf09b9b.tar.bz2 |
Merge tag 'efi-2024-10-rc1' of https://source.denx.de/u-boot/custodians/u-boot-efi into next
Pull request efi-2024-10-rc1
Documentation:
Update requirements.txt to use current Python module versions
Add a page describing debugging U-Boot with GDB
FIT: describe data-size as a conditionally mandatory property
Correct link to FIT specification in SPL code.
Correct kaslrseed command long text description
UEFI:
Add unit test checking that don't have kaslr-seed when measuring boot
Deduplicate code for measured boot.
Other:
Print size information in fwu command
-rw-r--r-- | boot/Kconfig | 4 | ||||
-rw-r--r-- | boot/bootm.c | 1 | ||||
-rw-r--r-- | cmd/fwu_mdata.c | 1 | ||||
-rw-r--r-- | cmd/kaslrseed.c | 2 | ||||
-rw-r--r-- | common/spl/spl_fit.c | 2 | ||||
-rw-r--r-- | doc/develop/gdb.rst | 171 | ||||
-rw-r--r-- | doc/develop/index.rst | 1 | ||||
-rw-r--r-- | doc/sphinx/requirements.txt | 16 | ||||
-rw-r--r-- | doc/usage/fit/source_file_format.rst | 6 | ||||
-rw-r--r-- | include/efi_tcg2.h | 9 | ||||
-rw-r--r-- | include/tpm-v2.h | 388 | ||||
-rw-r--r-- | include/tpm_tcg2.h | 348 | ||||
-rw-r--r-- | lib/Kconfig | 6 | ||||
-rw-r--r-- | lib/Makefile | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_tcg2.c | 3 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_fdt.c | 7 | ||||
-rw-r--r-- | lib/tpm-v2.c | 767 | ||||
-rw-r--r-- | lib/tpm_tcg2.c | 731 |
18 files changed, 1386 insertions, 1079 deletions
diff --git a/boot/Kconfig b/boot/Kconfig index a212f26..11175fb 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -734,6 +734,10 @@ config LEGACY_IMAGE_FORMAT config MEASURED_BOOT bool "Measure boot images and configuration when booting without EFI" depends on HASH && TPM_V2 + select SHA1 + select SHA256 + select SHA384 + select SHA512 help This option enables measurement of the boot process when booting without UEFI . Measurement involves creating cryptographic hashes diff --git a/boot/bootm.c b/boot/bootm.c index 3de87eb..376d63a 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -24,6 +24,7 @@ #include <asm/io.h> #include <linux/sizes.h> #include <tpm-v2.h> +#include <tpm_tcg2.h> #if defined(CONFIG_CMD_USB) #include <usb.h> #endif diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c index 3c8be57..9c048d6 100644 --- a/cmd/fwu_mdata.c +++ b/cmd/fwu_mdata.c @@ -22,6 +22,7 @@ static void print_mdata(struct fwu_data *data) printf("\tFWU Metadata\n"); printf("crc32: %#x\n", data->crc32); printf("version: %#x\n", data->version); + printf("size: %#x\n", data->metadata_size); printf("active_index: %#x\n", data->active_index); printf("previous_active_index: %#x\n", data->previous_active_index); diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c index 0712097..2ad983a 100644 --- a/cmd/kaslrseed.c +++ b/cmd/kaslrseed.c @@ -33,7 +33,7 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int argc, char *const } U_BOOT_LONGHELP(kaslrseed, - "[n]\n" + "\n" " - append random bytes to chosen kaslr-seed node\n"); U_BOOT_CMD( diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 988125b..2a097f4 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -587,7 +587,7 @@ __weak void *spl_load_simple_fit_fix_load(const void *fit) static void warn_deprecated(const char *msg) { printf("DEPRECATED: %s\n", msg); - printf("\tSee doc/uImage.FIT/source_file_format.txt\n"); + printf("\tSee https://fitspec.osfw.foundation/\n"); } static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node, diff --git a/doc/develop/gdb.rst b/doc/develop/gdb.rst new file mode 100644 index 0000000..4e359c7 --- /dev/null +++ b/doc/develop/gdb.rst @@ -0,0 +1,171 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (c) 2024 Alexander Dahl + +Debugging U-Boot with GDB +========================= + +Using a JTAG adapter it is possible to debug a running U-Boot with GDB. +A common way is to connect a debug adapter to the JTAG connector of your +board, run a GDB server, connect GDB to the GDB server, and use GDB as usual. + +Similarly QEMU can provide a GDB server. + +Preparing build +--------------- + +Building U-Boot with with reduced optimization (-Og) and without link time +optimization is recommended for easier debugging:: + + CONFIG_CC_OPTIMIZE_FOR_DEBUG=y + CONFIG_LTO=n + +Otherwise build, install, and run U-Boot as usual. + +Using OpenOCD as GDB server +--------------------------- + +`OpenOCD <https://openocd.org/>`_ is an open source tool supporting hardware +debug probes, and providing a GDB server. It is readily available in major Linux +distributions or you can build it from source. + +Here is example of starting OpenOCD on Debian using a J-Link adapter and a +board with an AT91 SAMA5D2 SoC: + +.. code-block:: console + + $ openocd -f interface/jlink.cfg -f target/at91sama5d2.cfg -c 'adapter speed 4000' + Open On-Chip Debugger 0.12.0 + Licensed under GNU GPL v2 + For bug reports, read + http://openocd.org/doc/doxygen/bugs.html + Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'. + adapter speed: 4000 kHz + + Info : Listening on port 6666 for tcl connections + Info : Listening on port 4444 for telnet connections + Info : J-Link V10 compiled Jan 30 2023 11:28:07 + Info : Hardware version: 10.10 + Info : VTarget = 3.244 V + Info : clock speed 4000 kHz + Info : JTAG tap: at91sama5d2.cpu tap/device found: 0x5ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x5) + Info : at91sama5d2.cpu_a5.0: hardware has 3 breakpoints, 2 watchpoints + Info : at91sama5d2.cpu_a5.0: MPIDR level2 0, cluster 0, core 0, mono core, no SMT + Info : starting gdb server for at91sama5d2.cpu_a5.0 on 3333 + Info : Listening on port 3333 for gdb connections + +Notice that OpenOCD is listening on port 3333 for GDB connections. + +Using QEMU as GDB server +------------------------ + +When running U-Boot on QEMU you can used the '-gdb' parameter to provide a +GDB server: + + qemu-system-riscv64 -M virt -nographic -gdb tcp::3333 -kernel u-boot + +Running a GDB session +---------------------- + +You need a GDB suited for your target. This can be the GDB coming with your +toolchain or *gdb-multiarch* available in your Linux distribution. + +.. prompt:: bash $ + + gdb-multiarch u-boot + +In the above command-line *u-boot* is the U-boot binary in your build +directory. You may need to adjust the path when calling GDB. + +Connect to the GDB server like this: + +.. code-block:: console + + (gdb) target extended-remote :3333 + Remote debugging using :3333 + 0x27fa9ac6 in ?? () + (gdb) + +This is fine for debugging before U-Boot relocates itself. + +For debugging U-Boot after relocation you need to indicate the relocation +address to GDB. You can retrieve the relocation address from the U-Boot shell +with the command *bdinfo*: + +.. code-block:: console + + U-Boot> bdinfo + boot_params = 0x20000100 + DRAM bank = 0x00000000 + -> start = 0x20000000 + -> size = 0x08000000 + flashstart = 0x00000000 + flashsize = 0x00000000 + flashoffset = 0x00000000 + baudrate = 115200 bps + relocaddr = 0x27f7a000 + reloc off = 0x0607a000 + Build = 32-bit + current eth = ethernet@f8008000 + ethaddr = 00:50:c2:31:58:d4 + IP addr = <NULL> + fdt_blob = 0x27b36060 + new_fdt = 0x27b36060 + fdt_size = 0x00003e40 + lmb_dump_all: + memory.cnt = 0x1 / max = 0x10 + memory[0] [0x20000000-0x27ffffff], 0x08000000 bytes flags: 0 + reserved.cnt = 0x1 / max = 0x10 + reserved[0] [0x27b31d00-0x27ffffff], 0x004ce300 bytes flags: 0 + devicetree = separate + arch_number = 0x00000000 + TLB addr = 0x27ff0000 + irq_sp = 0x27b36050 + sp start = 0x27b36040 + Early malloc usage: cd8 / 2000 + +Look out for the line starting with *relocaddr* which has the address +you need, ``0x27f7a000`` in this case. + +On most architectures (not sandbox, x86, Xtensa) the global data pointer is +stored in a fixed register: + +============ ======== +Architecture Register +============ ======== +arc r25 +arm r9 +arm64 x18 +m68k d7 +microblaze r31 +mips k0 +nios2 gp +powerpc r2 +riscv gp +sh r13 +============ ======== + +On these architecture the relocation address cat be determined by +dereferencing the global data pointer stored in register, *r9* in the example: + +.. code-block:: console + + (gdb) p/x (*(struct global_data*)$r9)->relocaddr + $1 = 0x27f7a000 + +In the GDB shell discard the previously loaded symbol file and add it once +again with the relocation address like this: + +.. code-block:: console + + (gdb) symbol-file + Discard symbol table from `/home/adahl/build/u-boot/v2024.04.x/u-boot'? (y or n) y + No symbol file now. + (gdb) add-symbol-file u-boot 0x27f7a000 + add symbol table from file "u-boot" at + .text_addr = 0x27f7a000 + (y or n) y + Reading symbols from u-boot... + (gdb) + +You can now use GDB as usual, setting breakpoints, printing backtraces, +inspecting variables, stepping through the code, etc. diff --git a/doc/develop/index.rst b/doc/develop/index.rst index f82e148..f9c4bf8 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -60,6 +60,7 @@ Debugging :maxdepth: 1 crash_dumps + gdb trace Packaging diff --git a/doc/sphinx/requirements.txt b/doc/sphinx/requirements.txt index 54eb70a..306b05a 100644 --- a/doc/sphinx/requirements.txt +++ b/doc/sphinx/requirements.txt @@ -1,18 +1,18 @@ alabaster==0.7.16 -Babel==2.14.0 -certifi==2023.11.17 +Babel==2.15.0 +certifi==2024.6.2 charset-normalizer==3.3.2 docutils==0.20.1 idna==3.7 imagesize==1.4.1 Jinja2==3.1.4 -MarkupSafe==2.1.3 -packaging==23.2 -Pygments==2.17.2 -requests==2.32.2 +MarkupSafe==2.1.5 +packaging==24.1 +Pygments==2.18.0 +requests==2.32.3 six==1.16.0 snowballstemmer==2.2.0 -Sphinx==7.2.6 +Sphinx==7.3.7 sphinx-prompt==1.8.0 sphinx-rtd-theme==2.0.0 sphinxcontrib-applehelp==1.0.8 @@ -22,4 +22,4 @@ sphinxcontrib-jquery==4.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.7 sphinxcontrib-serializinghtml==1.1.10 -urllib3==2.1.0 +urllib3==2.2.1 diff --git a/doc/usage/fit/source_file_format.rst b/doc/usage/fit/source_file_format.rst index 7727ab7..15990e3 100644 --- a/doc/usage/fit/source_file_format.rst +++ b/doc/usage/fit/source_file_format.rst @@ -254,9 +254,6 @@ compression zstd zstd compressed ==================== ================== -data-size - size of the data in bytes - Conditionally mandatory property ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -276,6 +273,9 @@ data-position not relative to the loading of the FIT. This is mandatory if external data used with a fixed address. +data-size + Size of the data in bytes. This is mandatory if external data is used. + os OS name, mandatory for types "kernel". Valid OS names are: diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h index a75b5a3..8dfb1bc 100644 --- a/include/efi_tcg2.h +++ b/include/efi_tcg2.h @@ -18,6 +18,7 @@ #include <efi_api.h> #include <tpm-v2.h> +#include <tpm_tcg2.h> /* TPMV2 only */ #define TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002 @@ -25,14 +26,6 @@ #define PE_COFF_IMAGE 0x0000000000000010 #define EFI_TCG2_MAX_PCR_INDEX 23 - -/* 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 - #define EFI_TCG2_FINAL_EVENTS_TABLE_VERSION 1 #define TPM2_EVENT_LOG_SIZE CONFIG_EFI_TCG2_PROTOCOL_EVENTLOG_SIZE diff --git a/include/tpm-v2.h b/include/tpm-v2.h index c9d5cb6..4fd19c5 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -55,59 +55,6 @@ struct udevice; #define TPM2_PT_MAX_COMMAND_SIZE (u32)(TPM2_PT_FIXED + 30) #define TPM2_PT_MAX_RESPONSE_SIZE (u32)(TPM2_PT_FIXED + 31) -/* - * event types, cf. - * "TCG Server Management Domain Firmware Profile Specification", - * rev 1.00, 2020-05-01 - */ -#define EV_POST_CODE ((u32)0x00000001) -#define EV_NO_ACTION ((u32)0x00000003) -#define EV_SEPARATOR ((u32)0x00000004) -#define EV_ACTION ((u32)0x00000005) -#define EV_TAG ((u32)0x00000006) -#define EV_S_CRTM_CONTENTS ((u32)0x00000007) -#define EV_S_CRTM_VERSION ((u32)0x00000008) -#define EV_CPU_MICROCODE ((u32)0x00000009) -#define EV_PLATFORM_CONFIG_FLAGS ((u32)0x0000000A) -#define EV_TABLE_OF_DEVICES ((u32)0x0000000B) -#define EV_COMPACT_HASH ((u32)0x0000000C) - -/* - * event types, cf. - * "TCG PC Client Platform Firmware Profile Specification", Family "2.0" - * Level 00 Version 1.05 Revision 23, May 7, 2021 - */ -#define EV_EFI_EVENT_BASE ((u32)0x80000000) -#define EV_EFI_VARIABLE_DRIVER_CONFIG ((u32)0x80000001) -#define EV_EFI_VARIABLE_BOOT ((u32)0x80000002) -#define EV_EFI_BOOT_SERVICES_APPLICATION ((u32)0x80000003) -#define EV_EFI_BOOT_SERVICES_DRIVER ((u32)0x80000004) -#define EV_EFI_RUNTIME_SERVICES_DRIVER ((u32)0x80000005) -#define EV_EFI_GPT_EVENT ((u32)0x80000006) -#define EV_EFI_ACTION ((u32)0x80000007) -#define EV_EFI_PLATFORM_FIRMWARE_BLOB ((u32)0x80000008) -#define EV_EFI_HANDOFF_TABLES ((u32)0x80000009) -#define EV_EFI_PLATFORM_FIRMWARE_BLOB2 ((u32)0x8000000A) -#define EV_EFI_HANDOFF_TABLES2 ((u32)0x8000000B) -#define EV_EFI_VARIABLE_BOOT2 ((u32)0x8000000C) -#define EV_EFI_HCRTM_EVENT ((u32)0x80000010) -#define EV_EFI_VARIABLE_AUTHORITY ((u32)0x800000E0) -#define EV_EFI_SPDM_FIRMWARE_BLOB ((u32)0x800000E1) -#define EV_EFI_SPDM_FIRMWARE_CONFIG ((u32)0x800000E2) - -#define EFI_CALLING_EFI_APPLICATION \ - "Calling EFI Application from Boot Option" -#define EFI_RETURNING_FROM_EFI_APPLICATION \ - "Returning from EFI Application from Boot Option" -#define EFI_EXIT_BOOT_SERVICES_INVOCATION \ - "Exit Boot Services Invocation" -#define EFI_EXIT_BOOT_SERVICES_FAILED \ - "Exit Boot Services Returned with Failure" -#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED \ - "Exit Boot Services Returned with Success" -#define EFI_DTB_EVENT_STRING \ - "DTB DATA" - /* TPMS_TAGGED_PROPERTY Structure */ struct tpms_tagged_property { u32 property; @@ -150,23 +97,6 @@ struct tpms_capability_data { } __packed; /** - * SHA1 Event Log Entry Format - * - * @pcr_index: PCRIndex event extended to - * @event_type: Type of event (see EFI specs) - * @digest: Value extended into PCR index - * @event_size: Size of event - * @event: Event data - */ -struct tcg_pcr_event { - u32 pcr_index; - u32 event_type; - u8 digest[TPM2_SHA1_DIGEST_SIZE]; - u32 event_size; - u8 event[]; -} __packed; - -/** * Definition of TPMU_HA Union */ union tpmu_ha { @@ -200,67 +130,6 @@ struct tpml_digest_values { } __packed; /** - * Crypto Agile Log Entry Format - * - * @pcr_index: PCRIndex event extended to - * @event_type: Type of event - * @digests: List of digestsextended to PCR index - * @event_size: Size of the event data - * @event: Event data - */ -struct tcg_pcr_event2 { - u32 pcr_index; - u32 event_type; - struct tpml_digest_values digests; - u32 event_size; - 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. * * @TPM2_ST_NO_SESSIONS: the command does not need an authentication. @@ -409,48 +278,40 @@ struct digest_info { #define TCG2_BOOT_HASH_ALG_SM3_256 0x00000010 static const struct digest_info hash_algo_list[] = { +#if IS_ENABLED(CONFIG_SHA1) { "sha1", TPM2_ALG_SHA1, TCG2_BOOT_HASH_ALG_SHA1, TPM2_SHA1_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA256) { "sha256", TPM2_ALG_SHA256, TCG2_BOOT_HASH_ALG_SHA256, TPM2_SHA256_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA384) { "sha384", TPM2_ALG_SHA384, TCG2_BOOT_HASH_ALG_SHA384, TPM2_SHA384_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA512) { "sha512", TPM2_ALG_SHA512, TCG2_BOOT_HASH_ALG_SHA512, TPM2_SHA512_DIGEST_SIZE, }, +#endif }; -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; - } -} - /* NV index attributes */ enum tpm_index_attrs { TPMA_NV_PPWRITE = 1UL << 0, @@ -531,188 +392,6 @@ enum { }; /** - * 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. * * @dev TPM device @@ -835,14 +514,11 @@ u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property, * 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 + * @pcrs: struct tpml_pcr_selection of available PCRs * * @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); +int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs); /** * Issue a TPM2_DictionaryAttackLockReset command. @@ -1029,11 +705,47 @@ enum tpm2_algorithms tpm2_name_to_algorithm(const char *name); const char *tpm2_algorithm_name(enum tpm2_algorithms); /** - * tpm2_algorithm_to_mask() - Get a TCG hash mask for algorithm + * tpm2_algorithm_to_len() - Return an algorithm length for supported algorithm id + * + * @algorithm_id: algorithm defined in enum tpm2_algorithms + * Return: len or 0 if not supported + */ +u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo); + +/* + * When measured boot is enabled via EFI or bootX commands all the algorithms + * above are selected by our Kconfigs. Due to U-Boots nature of being small there + * are cases where we need some functionality from the TPM -- e.g storage or RNG + * but we don't want to support measurements. + * + * The choice of hash algorithms are determined by the platform and the TPM + * configuration. Failing to cap a PCR in a bank which the platform left + * active is a security vulnerability. It permits the unsealing of secrets + * if an attacker can replay a good set of measurements into an unused bank. + * + * On top of that a previous stage bootloader (e.g TF-A), migh pass an eventlog + * since it doesn't have a TPM driver, which U-Boot needs to replace. The algorit h + * choice is a compile time option in that case and we need to make sure we conform. + * + * Add a variable here that sums the supported algorithms U-Boot was compiled + * with so we can refuse to do measurements if we don't support all of them + */ + +/** + * tpm2_allow_extend() - Check if extending PCRs is allowed and safe + * + * @dev: TPM device + * Return: true if allowed + */ +bool tpm2_allow_extend(struct udevice *dev); + +/** + * tpm2_is_active_pcr() - check the pcr_select. If at least one of the PCRs + * supports the algorithm add it on the active ones * - * @hash_alg: TCG defined algorithm - * Return: TCG hashing algorithm bitmaps (or 0 if algo not supported) + * @selection: PCR selection structure + * Return: True if the algorithm is active */ -u32 tpm2_algorithm_to_mask(enum tpm2_algorithms); +bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection); #endif /* __TPM_V2_H */ diff --git a/include/tpm_tcg2.h b/include/tpm_tcg2.h new file mode 100644 index 0000000..6519004 --- /dev/null +++ b/include/tpm_tcg2.h @@ -0,0 +1,348 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Defines APIs and structures that adhere to + * https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ + * https://trustedcomputinggroup.org/resource/tcg-efi-protocol-specification/ + * + * Copyright (c) 2020 Linaro Limited + */ + +#ifndef __TPM_TCG_V2_H +#define __TPM_TCG_V2_H + +#include <tpm-v2.h> + +/* + * event types, cf. + * "TCG Server Management Domain Firmware Profile Specification", + * rev 1.00, 2020-05-01 + */ +#define EV_POST_CODE ((u32)0x00000001) +#define EV_NO_ACTION ((u32)0x00000003) +#define EV_SEPARATOR ((u32)0x00000004) +#define EV_ACTION ((u32)0x00000005) +#define EV_TAG ((u32)0x00000006) +#define EV_S_CRTM_CONTENTS ((u32)0x00000007) +#define EV_S_CRTM_VERSION ((u32)0x00000008) +#define EV_CPU_MICROCODE ((u32)0x00000009) +#define EV_PLATFORM_CONFIG_FLAGS ((u32)0x0000000A) +#define EV_TABLE_OF_DEVICES ((u32)0x0000000B) +#define EV_COMPACT_HASH ((u32)0x0000000C) + +/* + * event types, cf. + * "TCG PC Client Platform Firmware Profile Specification", Family "2.0" + * Level 00 Version 1.05 Revision 23, May 7, 2021 + */ +#define EV_EFI_EVENT_BASE ((u32)0x80000000) +#define EV_EFI_VARIABLE_DRIVER_CONFIG ((u32)0x80000001) +#define EV_EFI_VARIABLE_BOOT ((u32)0x80000002) +#define EV_EFI_BOOT_SERVICES_APPLICATION ((u32)0x80000003) +#define EV_EFI_BOOT_SERVICES_DRIVER ((u32)0x80000004) +#define EV_EFI_RUNTIME_SERVICES_DRIVER ((u32)0x80000005) +#define EV_EFI_GPT_EVENT ((u32)0x80000006) +#define EV_EFI_ACTION ((u32)0x80000007) +#define EV_EFI_PLATFORM_FIRMWARE_BLOB ((u32)0x80000008) +#define EV_EFI_HANDOFF_TABLES ((u32)0x80000009) +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2 ((u32)0x8000000A) +#define EV_EFI_HANDOFF_TABLES2 ((u32)0x8000000B) +#define EV_EFI_VARIABLE_BOOT2 ((u32)0x8000000C) +#define EV_EFI_HCRTM_EVENT ((u32)0x80000010) +#define EV_EFI_VARIABLE_AUTHORITY ((u32)0x800000E0) +#define EV_EFI_SPDM_FIRMWARE_BLOB ((u32)0x800000E1) +#define EV_EFI_SPDM_FIRMWARE_CONFIG ((u32)0x800000E2) + +#define EFI_CALLING_EFI_APPLICATION \ + "Calling EFI Application from Boot Option" +#define EFI_RETURNING_FROM_EFI_APPLICATION \ + "Returning from EFI Application from Boot Option" +#define EFI_EXIT_BOOT_SERVICES_INVOCATION \ + "Exit Boot Services Invocation" +#define EFI_EXIT_BOOT_SERVICES_FAILED \ + "Exit Boot Services Returned with Failure" +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED \ + "Exit Boot Services Returned with Success" +#define EFI_DTB_EVENT_STRING \ + "DTB DATA" + +/** + * 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; + +/** + * SHA1 Event Log Entry Format + * + * @pcr_index: PCRIndex event extended to + * @event_type: Type of event (see EFI specs) + * @digest: Value extended into PCR index + * @event_size: Size of event + * @event: Event data + */ +struct tcg_pcr_event { + u32 pcr_index; + u32 event_type; + u8 digest[TPM2_SHA1_DIGEST_SIZE]; + u32 event_size; + u8 event[]; +} __packed; + +/** + * tcg2_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 tcg2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, + u32 *pcr_banks); + +/** + * Crypto Agile Log Entry Format + * + * @pcr_index: PCRIndex event extended to + * @event_type: Type of event + * @digests: List of digestsextended to PCR index + * @event_size: Size of the event data + * @event: Event data + */ +struct tcg_pcr_event2 { + u32 pcr_index; + u32 event_type; + struct tpml_digest_values digests; + u32 event_size; + u8 event[]; +} __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; + +#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 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); + +/** + * tcg2_algorithm_to_mask() - Get a TCG hash mask for algorithm + * + * @hash_alg: TCG defined algorithm + * Return: TCG hashing algorithm bitmaps (or 0 if algo not supported) + */ +u32 tcg2_algorithm_to_mask(enum tpm2_algorithms); + +#endif /* __TPM_TCG_V2_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 189e6eb..b3baa4b 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -439,9 +439,6 @@ config TPM 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 @@ -449,6 +446,9 @@ config TPM command to interactive the TPM. Driver model support is provided for the low-level TPM interface, but only one TPM is supported at a time by the TPM library. + For size reasons only SHA1 is selected which is supported on TPM1.2. + If you want a fully functional TPM enable all hashing algorithms. + If you enabled measured boot all hashing algorithms are selected. config SPL_TPM bool "Trusted Platform Module (TPM) Support in SPL" diff --git a/lib/Makefile b/lib/Makefile index 2a76acf..e389ad0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -61,6 +61,8 @@ ifeq ($(CONFIG_$(SPL_TPL_)TPM),y) obj-$(CONFIG_TPM) += tpm_api.o obj-$(CONFIG_TPM_V1) += tpm-v1.o obj-$(CONFIG_TPM_V2) += tpm-v2.o +obj-$(CONFIG_EFI_TCG2_PROTOCOL) += tpm_tcg2.o +obj-$(CONFIG_MEASURED_BOOT) += tpm_tcg2.o endif obj-$(CONFIG_$(SPL_TPL_)CRC8) += crc8.o diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index 1400e67..45f451e 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -16,7 +16,6 @@ #include <malloc.h> #include <smbios.h> #include <version_string.h> -#include <tpm-v2.h> #include <tpm_api.h> #include <u-boot/hash-checksum.h> #include <linux/unaligned/be_byteshift.h> @@ -277,7 +276,7 @@ efi_tcg2_get_capability(struct efi_tcg2_protocol *this, /* Supported and active PCRs */ capability->hash_algorithm_bitmap = 0; capability->active_pcr_banks = 0; - ret = tpm2_get_pcr_info(dev, &capability->hash_algorithm_bitmap, + ret = tcg2_get_pcr_info(dev, &capability->hash_algorithm_bitmap, &capability->active_pcr_banks, &capability->number_of_pcr_banks); if (ret) { diff --git a/lib/efi_selftest/efi_selftest_fdt.c b/lib/efi_selftest/efi_selftest_fdt.c index aa3b13a..a4b0cef 100644 --- a/lib/efi_selftest/efi_selftest_fdt.c +++ b/lib/efi_selftest/efi_selftest_fdt.c @@ -227,6 +227,13 @@ static int execute(void) return EFI_ST_FAILURE; } } + if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL_MEASURE_DTB)) { + str = get_property(u"kaslr-seed", u"chosen"); + if (str) { + efi_st_error("kaslr-seed with measured fdt\n"); + return EFI_ST_FAILURE; + } + } if (IS_ENABLED(CONFIG_RISCV)) { u32 fdt_hartid; diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 91526af..59e6cba 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -10,6 +10,7 @@ #include <tpm_api.h> #include <tpm-common.h> #include <tpm-v2.h> +#include <tpm_tcg2.h> #include <u-boot/sha1.h> #include <u-boot/sha256.h> #include <u-boot/sha512.h> @@ -22,668 +23,6 @@ #include "tpm-utils.h" -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(hash_algo_list); ++i) { - if (!(active & hash_algo_list[i].hash_mask)) - continue; - - switch (hash_algo_list[i].hash_alg) { - 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__, - hash_algo_list[i].hash_alg); - continue; - } - - digest_list->digests[digest_list->count].hash_alg = - hash_algo_list[i].hash_alg; - 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; - 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(hash_algo_list); ++i) { - if (!(active & hash_algo_list[i].hash_mask)) - continue; - - switch (hash_algo_list[i].hash_alg) { - 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(hash_algo_list); ++i) { - if (!(active & hash_algo_list[i].hash_mask)) - continue; - - len = hash_algo_list[i].hash_len; - if (!len) - continue; - - put_unaligned_le16(hash_algo_list[i].hash_alg, - &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(hash_algo_list) || - (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(hash_algo_list)) - 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 -ENOBUFS; - - /* - * 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; - fdt_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] = { @@ -857,6 +196,11 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm, if (!digest) return -EINVAL; + + if (!tpm2_allow_extend(dev)) { + log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n"); + return -EINVAL; + } /* * Fill the command structure starting from the first buffer: * - the digest @@ -1056,48 +400,25 @@ static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr) 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) +int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs) { 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); + pcrs->count = get_unaligned_be32(response); /* - * We only support 5 algorithms for now so check against that + * We only support 4 algorithms for now so check against that * instead of TPM2_NUM_PCR_BANKS */ - if (pcrs.count > ARRAY_SIZE(hash_algo_list) || - pcrs.count < 1) { - printf("%s: too many pcrs: %u\n", __func__, pcrs.count); + if (pcrs->count > 4 || pcrs->count < 1) { + printf("%s: too many pcrs: %u\n", __func__, pcrs->count); return -EMSGSIZE; } @@ -1105,7 +426,7 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, if (ret) return ret; - for (i = 0; i < pcrs.count; i++) { + for (i = 0; i < pcrs->count; i++) { /* * Definition of TPMS_PCR_SELECTION Structure * hash: u16 @@ -1125,35 +446,20 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, hash_offset + offsetof(struct tpms_pcr_selection, pcr_select); - pcrs.selection[i].hash = + pcrs->selection[i].hash = get_unaligned_be16(response + hash_offset); - pcrs.selection[i].size_of_select = + pcrs->selection[i].size_of_select = __get_unaligned_be(response + size_select_offset); - if (pcrs.selection[i].size_of_select > TPM2_PCR_SELECT_MAX) { + 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); + 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); + 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; } @@ -1541,6 +847,18 @@ u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, return 0; } +bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection) +{ + int i; + + for (i = 0; i < selection->size_of_select; i++) { + if (selection->pcr_select[i]) + return true; + } + + return false; +} + enum tpm2_algorithms tpm2_name_to_algorithm(const char *name) { size_t i; @@ -1566,14 +884,33 @@ const char *tpm2_algorithm_name(enum tpm2_algorithms algo) return ""; } -u32 tpm2_algorithm_to_mask(enum tpm2_algorithms algo) +u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo) { size_t i; - for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { if (hash_algo_list[i].hash_alg == algo) - return hash_algo_list[i].hash_mask; + return hash_algo_list[i].hash_len; } return 0; } + +bool tpm2_allow_extend(struct udevice *dev) +{ + struct tpml_pcr_selection pcrs; + size_t i; + int rc; + + rc = tpm2_get_pcr_info(dev, &pcrs); + if (rc) + return false; + + for (i = 0; i < pcrs.count; i++) { + if (tpm2_is_active_pcr(&pcrs.selection[i]) && + !tpm2_algorithm_to_len(pcrs.selection[i].hash)) + return false; + } + + return true; +} diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c new file mode 100644 index 0000000..7f868cc --- /dev/null +++ b/lib/tpm_tcg2.c @@ -0,0 +1,731 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 Linaro Limited + */ + +#include <dm.h> +#include <dm/of_access.h> +#include <tpm_api.h> +#include <tpm-common.h> +#include <tpm-v2.h> +#include <tpm_tcg2.h> +#include <u-boot/sha1.h> +#include <u-boot/sha256.h> +#include <u-boot/sha512.h> +#include <version_string.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/unaligned/be_byteshift.h> +#include <linux/unaligned/generic.h> +#include <linux/unaligned/le_byteshift.h> +#include "tpm-utils.h" + +int tcg2_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; + size_t i; + u32 ret; + + *supported_pcr = 0; + *active_pcr = 0; + *pcr_banks = 0; + memset(response, 0, sizeof(response)); + + ret = tpm2_get_pcr_info(dev, &pcrs); + if (ret) + return ret; + + for (i = 0; i < pcrs.count; i++) { + u32 hash_mask = tcg2_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; +} + +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 = tcg2_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(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) + continue; + + switch (hash_algo_list[i].hash_alg) { + 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__, + hash_algo_list[i].hash_alg); + continue; + } + + digest_list->digests[digest_list->count].hash_alg = + hash_algo_list[i].hash_alg; + 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; + 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(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) + continue; + + switch (hash_algo_list[i].hash_alg) { + 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(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) + continue; + + len = hash_algo_list[i].hash_len; + if (!len) + continue; + + put_unaligned_le16(hash_algo_list[i].hash_alg, + &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(hash_algo_list) || + (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(hash_algo_list)) + 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 = tcg2_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 -ENOBUFS; + + /* + * 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; + fdt_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; +} + +u32 tcg2_algorithm_to_mask(enum tpm2_algorithms algo) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { + if (hash_algo_list[i].hash_alg == algo) + return hash_algo_list[i].hash_mask; + } + + return 0; +} + +__weak void tcg2_platform_startup_error(struct udevice *dev, int rc) {} |