summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2023-10-27 19:27:29 -0400
committerTom Rini <[email protected]>2023-10-27 19:27:29 -0400
commitd5d9770f58ce0ba620e4d311bbd756b97839480a (patch)
tree3d7eae28e5a8eb2846c90eb58714bb2ef3c8f5f1 /include
parent913d830cf093c10ca3233038e81c11beb63ec802 (diff)
parent4fd7d27ccb763ce8b836a0e4c5dd005392d38e18 (diff)
Merge tag 'tpm-next-27102023' of https://source.denx.de/u-boot/custodians/u-boot-tpm
bootX measurements and measurement API moved to u-boot core: Up to now, U-Boot could perform measurements and EventLog creation as described by the TCG spec when booting via EFI. The EFI code was residing in lib/efi_loader/efi_tcg2.c and contained both EFI specific code + the API needed to access the TPM, extend PCRs and create an EventLog. The non-EFI part proved modular enough and moving it around to the TPM subsystem was straightforward. With that in place we can have a common API for measuring binaries regardless of the boot command, EFI or boot(m|i|z), and contructing an EventLog. I've tested all of the EFI cases -- booting with an empty EventLog and booting with a previous stage loader providing one and found no regressions. Eddie tested the bootX part. Eddie also fixed the sandbox TPM which couldn't be used for the EFI code and it now supports all the required capabilities. This had a slight sideeffect in our testing since the EFI subsystem initializes the TPM early and 'tpm2 init' failed during some python tests. That code only opens the device though, so we can replace it with 'tpm2 autostart' which doesn't error out and still allows you to perfom the rest of the tests but doesn't report an error if the device is already opened. There's a few minor issues with this PR as well but since testing and verifying the changes takes a considerable amount of time, I prefer merging it now. Heinrich has already sent a PR for -master containing "efi_loader: fix EFI_ENTRY point on get_active_pcr_banks" and I am not sure if that will cause any conflicts, but in any case they should be trivial to resolve. Both the EFI and non-EFI code have a Kconfig for measuring the loaded Device Tree. The reason this is optional is that we can't reason when/if devices add random info like kaslr-seed, mac addresses etc in the DT. In that case measurements are random, board specific and eventually useless. The reason it was difficult to fix it prior to this patchset is because the EFI subsystem and thus measurements was brought up late and DT fixups might have already been applied. With this patchset we can measure the DT really early in the future. Heinrich also pointed out that the two Kconfigs for the DTB measurements can be squashed in a single one and that the documentation only explains the non-EFI case. I agree on both but as I said this is a sane working version, so let's pull this first it's aleady big enough and painful to test.
Diffstat (limited to 'include')
-rw-r--r--include/bootm.h11
-rw-r--r--include/efi_tcg2.h44
-rw-r--r--include/image.h1
-rw-r--r--include/test/suites.h1
-rw-r--r--include/tpm-v2.h263
5 files changed, 274 insertions, 46 deletions
diff --git a/include/bootm.h b/include/bootm.h
index c3c7336207b..10a1bd65a75 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -56,6 +56,17 @@ ulong bootm_disable_interrupts(void);
int bootm_find_images(int flag, int argc, char *const argv[], ulong start,
ulong size);
+/*
+ * Measure the boot images. Measurement is the process of hashing some binary
+ * data and storing it into secure memory, i.e. TPM PCRs. In addition, each
+ * measurement is logged into the platform event log such that the operating
+ * system can access it and perform attestation of the boot.
+ *
+ * @images: The structure containing the various images to boot (linux,
+ * initrd, dts, etc.)
+ */
+int bootm_measure(struct bootm_headers *images);
+
int do_bootm_states(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[], int states, struct bootm_headers *images,
int boot_progress);
diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
index b1c3abd0975..b21c5cb3dd6 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/image.h b/include/image.h
index 5f85bf84a2d..2e3cf839ee3 100644
--- a/include/image.h
+++ b/include/image.h
@@ -409,6 +409,7 @@ struct bootm_headers {
#define BOOTM_STATE_OS_FAKE_GO 0x00000200 /* 'Almost' run the OS */
#define BOOTM_STATE_OS_GO 0x00000400
#define BOOTM_STATE_PRE_LOAD 0x00000800
+#define BOOTM_STATE_MEASURE 0x00001000
int state;
#if defined(CONFIG_LMB) && !defined(USE_HOSTCC)
diff --git a/include/test/suites.h b/include/test/suites.h
index 51acbe47b2f..ad4fc926f48 100644
--- a/include/test/suites.h
+++ b/include/test/suites.h
@@ -46,6 +46,7 @@ int do_ut_lib(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_loadm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_log(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_mbr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
+int do_ut_measurement(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]);
int do_ut_mem(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_optee(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
int do_ut_overlay(struct cmd_tbl *cmdtp, int flag, int argc,
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index 2b6980e441d..33dd103767c 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -169,7 +169,7 @@ struct tcg_pcr_event {
/**
* Definition of TPMU_HA Union
*/
-union tmpu_ha {
+union tpmu_ha {
u8 sha1[TPM2_SHA1_DIGEST_SIZE];
u8 sha256[TPM2_SHA256_DIGEST_SIZE];
u8 sm3_256[TPM2_SM3_256_DIGEST_SIZE];
@@ -185,7 +185,7 @@ union tmpu_ha {
*/
struct tpmt_ha {
u16 hash_alg;
- union tmpu_ha digest;
+ union tpmu_ha digest;
} __packed;
/**
@@ -217,6 +217,50 @@ struct tcg_pcr_event2 {
} __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.
@@ -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,
@@ -422,6 +486,188 @@ 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
@@ -541,6 +787,19 @@ 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.
*
* @dev TPM device