diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index bcf372dff..9fff4cc2e 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -11,15 +11,30 @@ #include "fu-tpm-eventlog-device.h" +struct FuPluginData { + GPtrArray *pcr0s; +}; + void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "uefi"); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); } +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->pcr0s != NULL) + g_ptr_array_unref (data->pcr0s); +} + gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { + FuPluginData *data = fu_plugin_get_data (plugin); gsize bufsz = 0; const gchar *fn = "/sys/kernel/security/tpm0/binary_bios_measurements"; g_autofree gchar *str = NULL; @@ -41,6 +56,15 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) if (!fu_device_setup (FU_DEVICE (dev), error)) return FALSE; + /* save this so we can compare against system-firmware */ + data->pcr0s = fu_tpm_eventlog_device_get_checksums (dev, 0, error); + if (data->pcr0s == NULL) + return FALSE; + for (guint i = 0; i < data->pcr0s->len; i++) { + const gchar *csum = g_ptr_array_index (data->pcr0s, i); + fu_device_add_checksum (FU_DEVICE (dev), csum); + } + /* add optional report metadata */ str = fu_tpm_eventlog_device_report_metadata (dev); g_debug ("using TPM event log report data of:\n%s", str); @@ -49,3 +73,33 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) return TRUE; } +void +fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + GPtrArray *checksums; + + /* only care about UEFI devices from ESRT */ + if (g_strcmp0 (fu_device_get_plugin (device), "uefi") != 0) + return; + + /* only the system-firmware device gets checksums */ + checksums = fu_device_get_checksums (device); + if (checksums->len == 0) + return; + for (guint i = 0; i < checksums->len; i++) { + const gchar *checksum = g_ptr_array_index (checksums, i); + for (guint j = 0; j < data->pcr0s->len; j++) { + const gchar *checksum_tmp = g_ptr_array_index (data->pcr0s, j); + if (g_strcmp0 (checksum, checksum_tmp) == 0) { + g_debug ("TPM reconstructed event log matched PCR0 reading"); + return; + } + } + } + + /* urgh, this is unexpected */ + fu_device_set_update_error (device, + "TPM PCR0 differs from reconstruction, " + "please report!"); +} diff --git a/plugins/tpm-eventlog/fu-self-test.c b/plugins/tpm-eventlog/fu-self-test.c index 7d287ca31..0e238f63f 100644 --- a/plugins/tpm-eventlog/fu-self-test.c +++ b/plugins/tpm-eventlog/fu-self-test.c @@ -14,6 +14,7 @@ static void fu_test_tpm_eventlog_parse_v1_func (void) { + const gchar *tmp; gboolean ret; gsize bufsz = 0; g_autofree gchar *fn = NULL; @@ -21,6 +22,7 @@ fu_test_tpm_eventlog_parse_v1_func (void) g_autofree gchar *str = NULL; g_autoptr(FuTpmEventlogDevice) dev = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; fn = g_build_filename (TESTDATADIR, "binary_bios_measurements-v1", NULL); ret = g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error); @@ -34,11 +36,19 @@ fu_test_tpm_eventlog_parse_v1_func (void) g_print ("%s\n", str); g_assert_nonnull (g_strstr_len (str, -1, "231f248f12ef9f38549f1bda7a859b781b5caab0")); g_assert_nonnull (g_strstr_len (str, -1, "9069ca78e7450a285173431b3e52c5c25299e473")); + + pcr0s = fu_tpm_eventlog_device_get_checksums (dev, 0, &error); + g_assert_no_error (error); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 1); + tmp = g_ptr_array_index (pcr0s, 0); + g_assert_cmpstr (tmp, ==, "543ae96e57b6fc4003531cd0dab1d9ba7f8166e0"); } static void fu_test_tpm_eventlog_parse_v2_func (void) { + const gchar *tmp; gboolean ret; gsize bufsz = 0; g_autofree gchar *fn = NULL; @@ -46,6 +56,7 @@ fu_test_tpm_eventlog_parse_v2_func (void) g_autofree gchar *str = NULL; g_autoptr(FuTpmEventlogDevice) dev = NULL; g_autoptr(GError) error = NULL; + g_autoptr(GPtrArray) pcr0s = NULL; fn = g_build_filename (TESTDATADIR, "binary_bios_measurements-v2", NULL); ret = g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error); @@ -60,6 +71,13 @@ fu_test_tpm_eventlog_parse_v2_func (void) g_assert_nonnull (g_strstr_len (str, -1, "19ce8e1347a709d2b485d519695e3ce10b939485")); g_assert_nonnull (g_strstr_len (str, -1, "9069ca78e7450a285173431b3e52c5c25299e473")); g_assert_nonnull (g_strstr_len (str, -1, "Boot Guard Measured")); + + pcr0s = fu_tpm_eventlog_device_get_checksums (dev, 0, &error); + g_assert_no_error (error); + g_assert_nonnull (pcr0s); + g_assert_cmpint (pcr0s->len, ==, 1); + tmp = g_ptr_array_index (pcr0s, 0); + g_assert_cmpstr (tmp, ==, "ebead4b31c7c49e193c440cd6ee90bc1b61a3ca6"); } int diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog-common.c b/plugins/tpm-eventlog/fu-tpm-eventlog-common.c index 961a56740..29b234ab9 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog-common.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog-common.c @@ -162,3 +162,72 @@ fu_tpm_eventlog_blobstr (GBytes *blob) return NULL; return g_string_free (g_steal_pointer (&str), FALSE); } + +GPtrArray * +fu_tpm_eventlog_calc_checksums (GPtrArray *items, guint8 pcr, GError **error) +{ + guint cnt_sha1 = 0; + guint cnt_sha256 = 0; + guint8 digest_sha1[TPM2_SHA1_DIGEST_SIZE] = { 0x0 }; + guint8 digest_sha256[TPM2_SHA256_DIGEST_SIZE] = { 0x0 }; + gsize digest_sha1_len = sizeof(digest_sha1); + gsize digest_sha256_len = sizeof(digest_sha256); + g_autoptr(GPtrArray) csums = g_ptr_array_new_with_free_func (g_free); + + /* sanity check */ + if (items->len == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no event log data"); + return NULL; + } + + /* take existing PCR hash, append new measurement to that, + * hash that with the same algorithm */ + for (guint i = 0; i < items->len; i++) { + FuTpmEventlogItem *item = g_ptr_array_index (items, i); + if (item->pcr != pcr) + continue; + if (item->checksum_sha1 != NULL) { + g_autoptr(GChecksum) csum_sha1 = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (csum_sha1, + (const guchar *) digest_sha1, + digest_sha1_len); + g_checksum_update (csum_sha1, + (const guchar *) g_bytes_get_data (item->checksum_sha1, NULL), + g_bytes_get_size (item->checksum_sha1)); + g_checksum_get_digest (csum_sha1, digest_sha1, &digest_sha1_len); + cnt_sha1++; + } + if (item->checksum_sha256 != NULL) { + g_autoptr(GChecksum) csum_sha256 = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (csum_sha256, + (const guchar *) digest_sha256, + digest_sha256_len); + g_checksum_update (csum_sha256, + (const guchar *) g_bytes_get_data (item->checksum_sha256, NULL), + g_bytes_get_size (item->checksum_sha256)); + g_checksum_get_digest (csum_sha256, digest_sha256, &digest_sha256_len); + cnt_sha256++; + } + } + if (cnt_sha1 == 0 && cnt_sha256 == 0) { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "no SHA1 or SHA256 data"); + return NULL; + } + if (cnt_sha1 > 0) { + g_autoptr(GBytes) blob_sha1 = NULL; + blob_sha1 = g_bytes_new_static (digest_sha1, sizeof(digest_sha1)); + g_ptr_array_add (csums, fu_tpm_eventlog_strhex (blob_sha1)); + } + if (cnt_sha256 > 0) { + g_autoptr(GBytes) blob_sha256 = NULL; + blob_sha256 = g_bytes_new_static (digest_sha256, sizeof(digest_sha256)); + g_ptr_array_add (csums, fu_tpm_eventlog_strhex (blob_sha256)); + } + return g_steal_pointer (&csums); +} diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog-common.h b/plugins/tpm-eventlog/fu-tpm-eventlog-common.h index c34bc0082..3e82e9e27 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog-common.h +++ b/plugins/tpm-eventlog/fu-tpm-eventlog-common.h @@ -56,3 +56,6 @@ guint32 fu_tpm_eventlog_hash_get_size (TPM2_ALG_ID hash_kind); const gchar *fu_tpm_eventlog_item_kind_to_string (FuTpmEventlogItemKind event_type); gchar *fu_tpm_eventlog_strhex (GBytes *blob); gchar *fu_tpm_eventlog_blobstr (GBytes *blob); +GPtrArray *fu_tpm_eventlog_calc_checksums (GPtrArray *items, + guint8 pcr, + GError **error); diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog-device.c b/plugins/tpm-eventlog/fu-tpm-eventlog-device.c index bc5cb8d78..33e572745 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog-device.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog-device.c @@ -20,6 +20,12 @@ struct _FuTpmEventlogDevice { G_DEFINE_TYPE (FuTpmEventlogDevice, fu_tpm_eventlog_device, FU_TYPE_DEVICE) +GPtrArray * +fu_tpm_eventlog_device_get_checksums (FuTpmEventlogDevice *self, guint8 pcr, GError **error) +{ + return fu_tpm_eventlog_calc_checksums (self->items, pcr, error); +} + static void fu_tpm_eventlog_device_to_string (FuDevice *device, guint idt, GString *str) { @@ -37,6 +43,8 @@ gchar * fu_tpm_eventlog_device_report_metadata (FuTpmEventlogDevice *self) { GString *str = g_string_new (""); + g_autoptr(GPtrArray) pcrs = NULL; + for (guint i = 0; i < self->items->len; i++) { FuTpmEventlogItem *item = g_ptr_array_index (self->items, i); g_autofree gchar *blobstr = fu_tpm_eventlog_blobstr (item->blob); @@ -46,6 +54,13 @@ fu_tpm_eventlog_device_report_metadata (FuTpmEventlogDevice *self) g_string_append_printf (str, " [%s]", blobstr); g_string_append (str, "\n"); } + pcrs = fu_tpm_eventlog_calc_checksums (self->items, 0, NULL); + if (pcrs != NULL) { + for (guint j = 0; j < pcrs->len; j++) { + const gchar *csum = g_ptr_array_index (pcrs, j); + g_string_append_printf (str, "PCR0: %s\n", csum); + } + } if (str->len > 0) g_string_truncate (str, str->len - 1); return g_string_free (str, FALSE); diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog-device.h b/plugins/tpm-eventlog/fu-tpm-eventlog-device.h index a77e9a657..408d4162d 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog-device.h +++ b/plugins/tpm-eventlog/fu-tpm-eventlog-device.h @@ -15,3 +15,6 @@ FuTpmEventlogDevice *fu_tpm_eventlog_device_new (const guint8 *buf, gsize bufsz, GError **error); gchar *fu_tpm_eventlog_device_report_metadata (FuTpmEventlogDevice *self); +GPtrArray *fu_tpm_eventlog_device_get_checksums (FuTpmEventlogDevice *self, + guint8 pcr, + GError **error); diff --git a/plugins/tpm-eventlog/fu-tpm-eventlog.c b/plugins/tpm-eventlog/fu-tpm-eventlog.c index ebd3256e5..1524b59db 100644 --- a/plugins/tpm-eventlog/fu-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-tpm-eventlog.c @@ -54,6 +54,17 @@ fu_tmp_eventlog_process (const gchar *fn, gint pcr, GError **error) fu_tpm_eventlog_item_to_string (item, 0, str); g_string_append (str, "\n"); } + fu_common_string_append_kv (str, 0, "PCRs", NULL); + for (guint8 i = 0; i < 10; i++) { + g_autoptr(GPtrArray) pcrs = fu_tpm_eventlog_calc_checksums (items, i, NULL); + if (pcrs == NULL) + continue; + for (guint j = 0; j < pcrs->len; j++) { + const gchar *csum = g_ptr_array_index (pcrs, j); + g_autofree gchar *title = g_strdup_printf ("%u", i); + fu_common_string_append_kv (str, 1, title, csum); + } + } /* success */ g_print ("%s", str->str);