feat!: enable crypto-agile measurement
Some platforms rely on the event log library to encapsulate the
measurement of images. Now we support the crypto agile event log format,
update the interfaces to enable users to leverage this if they so wish.
Make MAX_HASH_COUNT and MAX_DIGEST_SIZE configurable via CMake.
Register a single hash backend func; compute all configured digests.
BREAKING-CHANGE: The signatures for `event_log_measure` and
`event_log_measure_and_record` have have changed. The `HASH_ALGORITHM`
option has also been removed from the build system.
Change-Id: I835e6691ea4572ba51c5d4e49038b3c8e7769f15
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8abe101..96e8be1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,16 +37,9 @@
set(DEBUG_BACKEND_HEADER "log_backend_tf.h" CACHE STRING "Path to debug backend header")
add_compile_definitions(DEBUG_BACKEND_HEADER="${DEBUG_BACKEND_HEADER}")
-if(HASH_ALGORITHM STREQUAL "SHA512")
- add_compile_definitions(TPM_ALG_ID=TPM_ALG_SHA512)
- add_compile_definitions(TCG_DIGEST_SIZE=64U)
-elseif(HASH_ALGORITHM STREQUAL "SHA384")
- add_compile_definitions(TPM_ALG_ID=TPM_ALG_SHA384)
- add_compile_definitions(TCG_DIGEST_SIZE=48U)
-else()
- add_compile_definitions(TPM_ALG_ID=TPM_ALG_SHA256)
- add_compile_definitions(TCG_DIGEST_SIZE=32U)
-endif()
+# Allow user to set values from the command line
+set(MAX_HASH_COUNT 24 CACHE STRING "Maximum number of hashes")
+set(MAX_DIGEST_SIZE 64 CACHE STRING "Maximum digest length")
add_library(eventlog STATIC
${PROJECT_SOURCE_DIR}/src/event_log.c
@@ -54,6 +47,11 @@
${PROJECT_SOURCE_DIR}/src/digest.c
)
+target_compile_definitions(eventlog PRIVATE
+ MAX_HASH_COUNT=${MAX_HASH_COUNT}
+ MAX_DIGEST_SIZE=${MAX_DIGEST_SIZE}
+)
+
target_include_directories(eventlog PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
diff --git a/include/event_log.h b/include/event_log.h
index e5870ad..3057035 100644
--- a/include/event_log.h
+++ b/include/event_log.h
@@ -10,15 +10,24 @@
#include <stddef.h>
#include <stdint.h>
+#include "sha_common_macros.h"
#include <tcg.h>
/* Number of hashing algorithms supported */
+#ifndef MAX_HASH_COUNT
#define HASH_ALG_COUNT 1U
-
-#define EVLOG_INVALID_ID UINT32_MAX
+#else
+#define HASH_ALG_COUNT MAX_HASH_COUNT
+#endif /* !HASH_ALG_COUNT */
/* Maximum digest size based on the strongest hash algorithm i.e. SHA-512. */
-#define MAX_DIGEST_SIZE 64U
+#ifndef MAX_DIGEST_SIZE
+#define MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
+#endif /* !MAX_DIGEST_SIZE */
+
+#define MAX_TPML_BUFFER_SIZE \
+ (sizeof(tpml_digest_values) + \
+ (HASH_ALG_COUNT * (sizeof(tpmt_ha) + MAX_DIGEST_SIZE)))
#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
diff --git a/include/event_measure.h b/include/event_measure.h
index 64d5be4..997409b 100644
--- a/include/event_measure.h
+++ b/include/event_measure.h
@@ -19,11 +19,7 @@
typedef int (*evlog_hash_func_t)(uint32_t alg, void *data, unsigned int len,
uint8_t *digest);
-struct event_log_hash_info {
- evlog_hash_func_t func;
- const uint32_t *ids;
- size_t count;
-};
+#define EVLOG_INVALID_ID UINT32_MAX
/**
* Initialize the Event Log and register supported hash functions.
@@ -36,50 +32,50 @@
* @param[in] start Pointer to the beginning of the Event Log buffer.
* @param[in] finish Pointer to the end of the Event Log buffer.
* @param[in] pos Previous cursor position.
- * @param[in] hash_info Pointer to a structure containing the hash function
+ * @param[in] hash_func Pointer to a structure containing the hash function
* pointer and associated algorithm identifiers.
*
- * @return 0 on success,
- * -EEXIST if hash functions have already been registered,
- *
- * -EINVAL if the input parameters are invalid,
- * or a negative error code from the underlying initialization logic.
- */
-int event_log_init_and_reg(uint8_t *start, uint8_t *finish, size_t pos,
- const struct event_log_hash_info *hash_info);
-
-/**
- * Measure input data and log its hash to the Event Log.
- *
- * Computes the cryptographic hash of the specified data and records it
- * in the Event Log as a TCG_PCR_EVENT2 structure using event type EV_POST_CODE.
- * Useful for firmware or image attestation.
- *
- * @param[in] data_base Pointer to the base of the data to be measured.
- * @param[in] data_size Size of the data in bytes.
- * @param[in] data_id Identifier used to match against metadata.
- * @param[in] metadata_ptr Pointer to an array of event_log_metadata_t.
- *
* @return 0 on success, or a negative error code on failure.
*/
-int event_log_measure_and_record(uintptr_t data_base, uint32_t data_size,
- uint32_t data_id,
- const event_log_metadata_t *metadata_ptr);
+int event_log_init_and_reg(uint8_t *start, uint8_t *finish, size_t pos,
+ evlog_hash_func_t hash_func);
/**
- * Measure the input data and return its hash.
+ * @brief Measure a memory region and record a TCG event.
*
- * Computes the cryptographic hash of the specified memory region using
- * the default hashing algorithm configured in the Event Log subsystem.
+ * Computes one or more cryptographic digests over the byte range
+ * [data_base, data_base + data_size) using the library's currently
+ * configured digest algorithm set, then appends an event to the
+ * platform event log associated with PCR @p pcr. The event payload is
+ * the caller-provided @p event_data buffer (copied as-is).
*
- * @param[in] data_base Pointer to the base of the data to be measured.
- * @param[in] data_size Size of the data in bytes.
- * @param[out] hash_data Buffer to hold the resulting hash output
- * (must be at least CRYPTO_MD_MAX_SIZE bytes).
+ * @param[in] data_base Pointer to the base of the data to be measured.
+ * @param[in] data_size Size of the data in bytes.
+ * @param[in] data_id Identifier used to match against metadata.
+ * @param[in] event_data Pointer to event data.
+ * @param[in] event_data_size Size of event data in bytes.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+int event_log_measure_and_record(uint32_t pcr, uintptr_t data_base,
+ uint32_t data_size, const void *event_data,
+ size_t event_data_size);
+
+/**
+ * @brief Compute a cryptographic hash of a memory region.
+ *
+ * Hashes the byte range [data_base, data_base + data_size) using the
+ * configured digest algorithms using a user specified cryptographic backend,
+ * and writes the resulting digest to @p hash_buf.
+ *
+ * @param[in] data_base Pointer to the base of the data to be measured.
+ * @param[in] data_size Size of the data in bytes.
+ * @param[out] hash_buf Buffer to hold the resulting hash output
+ * @param[in] hash_buf_size Size of the hash buffer in bytes.
*
* @return 0 on success, or an error code on failure.
*/
-int event_log_measure(uintptr_t data_base, uint32_t data_size,
- unsigned char *hash_data);
+int event_log_measure(uintptr_t data_base, size_t data_size, uint8_t *hash_buf,
+ size_t hash_buf_size);
#endif /* EVENT_MEASURE_H */
diff --git a/src/event_log.c b/src/event_log.c
index 83afcdd..cebc6d1 100644
--- a/src/event_log.c
+++ b/src/event_log.c
@@ -15,6 +15,7 @@
#include "event_log.h"
#include "event_measure.h"
#include "event_record.h"
+#include "tcg.h"
/* Running Event Log Pointer */
static uint8_t *log_ptr;
@@ -26,17 +27,10 @@
static uintptr_t log_end;
/* Hash function for event log operations set by user. */
-static const struct event_log_hash_info *crypto_hash_info;
+static evlog_hash_func_t event_log_hash_func;
static const tcg_efi_spec_id_event_t *spec_id_header;
-/* Message digest algorithm */
-enum crypto_md_algo {
- CRYPTO_MD_SHA256,
- CRYPTO_MD_SHA384,
- CRYPTO_MD_SHA512,
-};
-
/* size lookup from your spec_id_header table */
static inline uint16_t digest_size_for_alg(uint16_t alg)
{
@@ -451,61 +445,100 @@
return 0;
}
-int event_log_measure(uintptr_t data_base, uint32_t data_size,
- unsigned char *hash_data)
+int event_log_measure(uintptr_t data_base, size_t data_size, uint8_t *hash_buf,
+ size_t hash_buf_size)
{
- if (crypto_hash_info == NULL) {
+ int rc;
+ uint8_t *digest_buf;
+ uint8_t *hash_buf_end = hash_buf + hash_buf_size;
+ const id_event_algorithm_size_t *event_log_algo;
+
+ if (event_log_hash_func == NULL) {
+ ERROR("No hash function registered for measurement.\n");
return -EINVAL;
}
- return crypto_hash_info->func(crypto_hash_info->ids[0],
- (void *)data_base, data_size, hash_data);
+ if (hash_buf == NULL || hash_buf_size == sizeof(tpml_digest_values)) {
+ ERROR("Invalid hash buffer or insufficient space.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Write the digest count into hash buffer, the buffer should have
+ * sufficient space to hold the count and count * sizeof(tpmt_ha)
+ * digests.
+ */
+ ((tpml_digest_values *)hash_buf)->count =
+ spec_id_header->number_of_algorithms;
+ digest_buf =
+ (uint8_t *)hash_buf + offsetof(tpml_digest_values, digests);
+
+ for (size_t i = 0; i < spec_id_header->number_of_algorithms; i++) {
+ event_log_algo = &spec_id_header->digest_size[i];
+ assert(event_log_algo->digest_size != 0U);
+
+ if (digest_buf > hash_buf_end - (sizeof(tpmt_ha) +
+ event_log_algo->digest_size)) {
+ ERROR("Not enough memory in allocated hash buffer.\n");
+ return -ENOMEM;
+ }
+
+ ((tpmt_ha *)digest_buf)->algorithm_id =
+ event_log_algo->algorithm_id;
+
+ rc = event_log_hash_func(((tpmt_ha *)digest_buf)->algorithm_id,
+ (void *)data_base, data_size,
+ ((tpmt_ha *)digest_buf)->digest);
+ if (rc < 0) {
+ ERROR("Image measurement failed (%d).\n", rc);
+ return rc;
+ }
+
+ digest_buf += sizeof(tpmt_ha) + event_log_algo->digest_size;
+ }
+
+ return 0;
}
int event_log_init_and_reg(uint8_t *start, uint8_t *finish, size_t pos,
- const struct event_log_hash_info *hash_info)
+ evlog_hash_func_t hash_func)
{
int rc = event_log_init_from_pos(start, finish, pos);
if (rc < 0) {
return rc;
}
- if (hash_info == NULL || hash_info->func == NULL ||
- hash_info->count == 0U || hash_info->count > HASH_ALG_COUNT) {
- return -EINVAL;
+ if (hash_func == NULL) {
+ WARN("No hash backend provided, skipping registration.\n");
+ } else {
+ event_log_hash_func = hash_func;
}
- crypto_hash_info = hash_info;
return 0;
}
-int event_log_measure_and_record(uintptr_t data_base, uint32_t data_size,
- uint32_t data_id,
- const event_log_metadata_t *metadata_ptr)
+int event_log_measure_and_record(uint32_t pcr, uintptr_t data_base,
+ uint32_t data_size, const void *event_data,
+ size_t event_data_size)
{
- unsigned char hash_data[MAX_DIGEST_SIZE];
+ uint8_t hash_buf[MAX_TPML_BUFFER_SIZE];
int rc;
- if (metadata_ptr == NULL) {
+ if (log_ptr == NULL || spec_id_header == NULL) {
+ ERROR("Cannot call library function, initialization not completed.\n");
return -EINVAL;
}
- /* Get the metadata associated with this image. */
- while (metadata_ptr->id != data_id) {
- if (metadata_ptr->id == EVLOG_INVALID_ID) {
- return -EINVAL;
- }
-
- metadata_ptr++;
- }
-
/* Measure the payload with algorithm selected by EventLog driver */
- rc = event_log_measure(data_base, data_size, hash_data);
+ rc = event_log_measure(data_base, data_size, hash_buf,
+ sizeof(hash_buf));
if (rc != 0) {
return rc;
}
- rc = event_log_record(hash_data, EV_POST_CODE, metadata_ptr);
+ rc = event_log_write_pcr_event2(pcr, EV_POST_CODE,
+ (const tpml_digest_values *)hash_buf,
+ event_data, event_data_size);
if (rc != 0) {
return rc;
}