mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-06 09:00:55 +00:00
tpm-eventlog: Replay the TPM event log to get the PCRx values
In theory, these should always match the reported PCRx values from the TPM. If the reconstructed event log checksum does not match the TPM value then something is either implemented wrongly, or something bad has happened.
This commit is contained in:
parent
ca3e785c40
commit
59d947ac24
@ -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!");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user