aboutsummaryrefslogtreecommitdiff
path: root/services/std_svc/drtm/drtm_measurements.c
diff options
context:
space:
mode:
Diffstat (limited to 'services/std_svc/drtm/drtm_measurements.c')
-rw-r--r--services/std_svc/drtm/drtm_measurements.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/services/std_svc/drtm/drtm_measurements.c b/services/std_svc/drtm/drtm_measurements.c
new file mode 100644
index 0000000000..cfc0fbbd36
--- /dev/null
+++ b/services/std_svc/drtm/drtm_measurements.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * DRTM measurements into TPM PCRs.
+ *
+ * Authors:
+ * Lucian Paul-Trifu <lucian.paultrifu@gmail.com>
+ *
+ */
+#include <assert.h>
+
+#include <mbedtls/md.h>
+
+#include <common/debug.h>
+#include <drivers/auth/mbedtls/mbedtls_common.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include "drtm_main.h"
+#include "drtm_measurements.h"
+
+#define XLAT_PAGE_SIZE PAGE_SIZE
+#if XLAT_PAGE_SIZE != DRTM_PAGE_SIZE
+#warning "xlat library page size differs from DRTM page size;"\
+ " mmap_add_dynamic_region() calls to the xlat library might fail"
+#endif
+
+
+#define DRTM_EVENT_ARM_BASE 0x9000U
+#define DRTM_EVENT_TYPE(n) (DRTM_EVENT_ARM_BASE + (unsigned int)(n))
+
+#define DRTM_EVENT_ARM_PCR_SCHEMA DRTM_EVENT_TYPE(1)
+#define DRTM_EVENT_ARM_DCE DRTM_EVENT_TYPE(2)
+#define DRTM_EVENT_ARM_DCE_PUBKEY DRTM_EVENT_TYPE(3)
+#define DRTM_EVENT_ARM_DLME DRTM_EVENT_TYPE(4)
+#define DRTM_EVENT_ARM_DLME_EP DRTM_EVENT_TYPE(5)
+#define DRTM_EVENT_ARM_DEBUG_CONFIG DRTM_EVENT_TYPE(6)
+#define DRTM_EVENT_ARM_NONSECURE_CONFIG DRTM_EVENT_TYPE(7)
+#define DRTM_EVENT_ARM_DCE_SECONDARY DRTM_EVENT_TYPE(8)
+#define DRTM_EVENT_ARM_TZFW DRTM_EVENT_TYPE(9)
+#define DRTM_EVENT_ARM_SEPARATOR DRTM_EVENT_TYPE(10)
+
+#define DRTM_NULL_DATA ((unsigned char []){ 0 })
+#define DRTM_EVENT_ARM_SEP_DATA \
+ (const unsigned char []){'A', 'R', 'M', '_', 'D', 'R', 'T', 'M' }
+
+#if !defined(DRTM_TPM_HASH_ALG)
+/*
+ * This is an error condition. However, avoid emitting a further error message,
+ * since an explanatory one will have already been emitted by the header file.
+ */
+#define DRTM_TPM_HASH_ALG TPM_ALG_NONE
+#define DRTM_MBEDTLS_HASH_ALG MBEDTLS_MD_NONE
+#else
+#define DRTM_MBEDTLS_HASH_ALG \
+ EXPAND_AND_COMBINE(MBEDTLS_MD_SHA, DRTM_SHA_ALG)
+#endif
+
+
+#define CHECK_RC(rc, func_call) { \
+ if ((rc)) { \
+ ERROR("%s(): " #func_call "failed unexpectedly rc=%d\n", \
+ __func__, rc); \
+ panic(); \
+ } \
+}
+
+
+int drtm_measurements_init(void)
+{
+ mbedtls_init();
+
+ return 0;
+}
+
+#define calc_hash(data_ptr, data_len, output) \
+ mbedtls_md(mbedtls_md_info_from_type((mbedtls_md_type_t)DRTM_MBEDTLS_HASH_ALG),\
+ data_ptr, data_len, output)
+
+enum drtm_retc drtm_take_measurements(const struct_drtm_dl_args *a,
+ struct drtm_event_log *log)
+{
+ struct tpm_log_1digest_shaX {
+ struct tpm_log_digests digests_1;
+ struct tpm_log_digest d;
+ unsigned char digest[MBEDTLS_MD_MAX_SIZE];
+ } __packed __aligned(__alignof(struct tpm_log_digests));
+ struct tpm_log_1digest_shaX digests_buf = {
+ .digests_1 = {
+ .count = 1,
+ },
+ .d = (struct tpm_log_digest) {
+ .h_alg = DRTM_TPM_HASH_ALG,
+ .buf_bytes = sizeof(((struct tpm_log_1digest_shaX *)0)->digest),
+ },
+ {0}
+ };
+ int rc;
+ uint8_t pcr_schema;
+ tpm_log_info_t *const tpm_log_info = &log->tpm_log_info;
+
+ rc = tpm_log_init(log->tpm_log_mem, sizeof(log->tpm_log_mem),
+ (enum tpm_hash_alg[]){ DRTM_TPM_HASH_ALG }, 1,
+ tpm_log_info);
+ CHECK_RC(rc, tpm_log_init);
+
+ /**
+ * Measurements extended into PCR-17.
+ *
+ * PCR-17: Measure the DCE image. Extend digest of (char)0 into PCR-17
+ * since the D-CRTM and the DCE are not separate.
+ */
+ rc = calc_hash(DRTM_NULL_DATA, sizeof(DRTM_NULL_DATA), digests_buf.digest);
+ CHECK_RC(rc, calc_hash(NULL_DATA_1));
+
+ rc = tpm_log_add_event(tpm_log_info, DRTM_EVENT_ARM_DCE, TPM_PCR_17,
+ &digests_buf.digests_1, NULL, 0);
+ CHECK_RC(rc, tpm_log_add_event_arm_dce);
+
+ /* PCR-17: Measure the PCR schema DRTM launch argument. */
+ pcr_schema = DL_ARGS_GET_PCR_SCHEMA(a);
+ rc = calc_hash(&pcr_schema, sizeof(pcr_schema), digests_buf.digest);
+ CHECK_RC(rc, calc_hash(pcr_schema));
+
+ rc = tpm_log_add_event(tpm_log_info, DRTM_EVENT_ARM_PCR_SCHEMA, TPM_PCR_17,
+ &digests_buf.digests_1, NULL, 0);
+ CHECK_RC(rc, tpm_log_add_event(ARM_PCR_SCHEMA_17));
+
+ /* PCR-17: Measure the enable state of external-debug, and trace. */
+ /*
+ * TODO: Measure the enable state of external-debug and trace. This should
+ * be returned through a platform-specific hook.
+ */
+
+ /* PCR-17: Measure the security lifecycle state. */
+ /*
+ * TODO: Measure the security lifecycle state. This is an implementation-
+ * defined value, retrieved through an implementation-defined mechanisms.
+ */
+
+ /*
+ * PCR-17: Optionally measure the NWd DCE.
+ * It is expected that such subsequent DCE stages are signed and verified.
+ * Whether they are measured in addition to signing is implementation
+ * -defined.
+ * Here the choice is to not measure any NWd DCE, in favour of PCR value
+ * resilience to any NWd DCE updates.
+ */
+
+ /* PCR-17: End of DCE measurements. */
+ rc = calc_hash(DRTM_EVENT_ARM_SEP_DATA, sizeof(DRTM_EVENT_ARM_SEP_DATA),
+ digests_buf.digest);
+ CHECK_RC(rc, calc_hash(ARM_SEP_DATA_17));
+
+ rc = tpm_log_add_event(tpm_log_info, DRTM_EVENT_ARM_SEPARATOR, TPM_PCR_17,
+ &digests_buf.digests_1,
+ DRTM_EVENT_ARM_SEP_DATA, sizeof(DRTM_EVENT_ARM_SEP_DATA));
+ CHECK_RC(rc, tpm_log_add_event(ARM_SEPARATOR_17));
+
+ /**
+ * Measurements extended into PCR-18.
+ *
+ * PCR-18: Measure the PCR schema DRTM launch argument.
+ */
+ pcr_schema = DL_ARGS_GET_PCR_SCHEMA(a);
+ rc = calc_hash(&pcr_schema, sizeof(pcr_schema), digests_buf.digest);
+ CHECK_RC(rc, calc_hash(pcr_schema));
+
+ rc = tpm_log_add_event(tpm_log_info, DRTM_EVENT_ARM_PCR_SCHEMA, TPM_PCR_18,
+ &digests_buf.digests_1, NULL, 0);
+ CHECK_RC(rc, tpm_log_add_event(ARM_PCR_SCHEMA_17));
+
+ /*
+ * PCR-18: Measure the public key used to verify DCE image(s) signatures.
+ * Extend digest of (char)0, since we do not expect the NWd DCE to be
+ * present.
+ */
+ assert(a->dce_nwd_size == 0);
+ rc = calc_hash(DRTM_NULL_DATA, sizeof(DRTM_NULL_DATA), digests_buf.digest);
+ CHECK_RC(rc, calc_hash(NULL_DATA_2));
+
+ rc = tpm_log_add_event(tpm_log_info, DRTM_EVENT_ARM_DCE_PUBKEY, TPM_PCR_18,
+ &digests_buf.digests_1, NULL, 0);
+ CHECK_RC(rc, tpm_log_add_event(ARM_DCE_PUBKEY));
+
+ /* PCR-18: Measure the DLME image. */
+ uintptr_t dlme_img_mapping;
+ size_t dlme_img_mapping_bytes;
+
+ dlme_img_mapping_bytes = ALIGNED_UP(a->dlme_img_size, DRTM_PAGE_SIZE);
+ rc = mmap_add_dynamic_region_alloc_va(a->dlme_paddr + a->dlme_img_off,
+ &dlme_img_mapping,
+ dlme_img_mapping_bytes, MT_RO_DATA | MT_NS);
+ if (rc) {
+ WARN("DRTM: %s: mmap_add_dynamic_region() failed rc=%d\n", __func__, rc);
+ return INTERNAL_ERROR;
+ }
+
+ rc = calc_hash((void *)dlme_img_mapping, a->dlme_img_size,
+ digests_buf.digest);
+ CHECK_RC(rc, calc_hash(dlme_img));
+
+ rc = tpm_log_add_event(tpm_log_info, DRTM_EVENT_ARM_DLME, TPM_PCR_18,
+ &digests_buf.digests_1, NULL, 0);
+ CHECK_RC(rc, tpm_log_add_event(ARM_DLME));
+
+ rc = mmap_remove_dynamic_region(dlme_img_mapping, dlme_img_mapping_bytes);
+ CHECK_RC(rc, mmap_remove_dynamic_region);
+
+ /* PCR-18: Measure the DLME image entry point. */
+ uint64_t dlme_img_ep = DL_ARGS_GET_DLME_ENTRY_POINT(a);
+
+ rc = calc_hash((unsigned char *)&dlme_img_ep, sizeof(dlme_img_ep),
+ digests_buf.digest);
+ CHECK_RC(rc, calc_hash(dlme_img_ep_off));
+
+ rc = tpm_log_add_event(tpm_log_info, DRTM_EVENT_ARM_DLME_EP, TPM_PCR_18,
+ &digests_buf.digests_1, NULL, 0);
+ CHECK_RC(rc, tpm_log_add_event(ARM_DLME_EP));
+
+ /* PCR-18: End of DCE measurements. */
+ rc = calc_hash(DRTM_EVENT_ARM_SEP_DATA, sizeof(DRTM_EVENT_ARM_SEP_DATA),
+ digests_buf.digest);
+ CHECK_RC(rc, calc_hash(ARM_SEP_DATA_18));
+
+ rc = tpm_log_add_event(tpm_log_info, DRTM_EVENT_ARM_SEPARATOR, TPM_PCR_18,
+ &digests_buf.digests_1,
+ DRTM_EVENT_ARM_SEP_DATA, sizeof(DRTM_EVENT_ARM_SEP_DATA));
+ CHECK_RC(rc, tpm_log_add_event(ARM_SEPARATOR_18));
+
+ /*
+ * If the DCE is unable to log a measurement because there is no available
+ * space in the event log region, the DCE must extend a hash of the value
+ * 0xFF (1 byte in size) into PCR[17] and PCR[18] and enter remediation.
+ */
+ return SUCCESS;
+}
+
+void drtm_serialise_event_log(char *dst, const struct drtm_event_log *src,
+ size_t *event_log_size_out)
+{
+ if (src) {
+ tpm_log_serialise(dst, &src->tpm_log_info, event_log_size_out);
+ } else {
+ if (dst != NULL) {
+ ERROR("%s(): cannot serialise the unexpected NULL event log\n",
+ __func__);
+ panic();
+ }
+ if (event_log_size_out) {
+ /*
+ * DRTM Beta0: Note that the advertised minimum required size ought
+ * to be 64KiB, rather than a more economical size of our choosing.
+ */
+ *event_log_size_out = DRTM_EVENT_LOG_INIT_SIZE;
+ }
+ }
+}