Coverage Report

Created: 2026-09-14 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-tpm-eventlog-v2.c
Line
Count
Source
1
/*
2
 * Copyright 2019 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#define G_LOG_DOMAIN "FuTpmEventlog"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-common.h"
13
#include "fu-input-stream.h"
14
#include "fu-tpm-eventlog-common.h"
15
#include "fu-tpm-eventlog-item.h"
16
#include "fu-tpm-eventlog-v2.h"
17
#include "fu-tpm-struct.h"
18
19
/**
20
 * FuTpmEventlogV2:
21
 *
22
 * Parse the TPM eventlog.
23
 */
24
25
struct _FuTpmEventlogV2 {
26
  FuFirmware parent_instance;
27
};
28
29
1.76k
G_DEFINE_TYPE(FuTpmEventlogV2, fu_tpm_eventlog_v2, FU_TYPE_TPM_EVENTLOG)
30
1.76k
31
1.76k
static guint32
32
1.76k
fu_tpm_eventlog_v2_hash_get_size(FuTpmAlg hash_kind)
33
1.76k
{
34
1.42k
  if (hash_kind == FU_TPM_ALG_SHA1)
35
630
    return FU_TPM_DIGEST_SIZE_SHA1;
36
797
  if (hash_kind == FU_TPM_ALG_SHA256)
37
135
    return FU_TPM_DIGEST_SIZE_SHA256;
38
662
  if (hash_kind == FU_TPM_ALG_SHA384)
39
523
    return FU_TPM_DIGEST_SIZE_SHA384;
40
139
  if (hash_kind == FU_TPM_ALG_SHA512)
41
23
    return FU_TPM_DIGEST_SIZE_SHA512;
42
116
  if (hash_kind == FU_TPM_ALG_SM3_256)
43
65
    return FU_TPM_DIGEST_SIZE_SM3_256;
44
51
  return 0;
45
116
}
46
47
static gboolean
48
fu_tpm_eventlog_v2_parse_item(FuTpmEventlogV2 *self,
49
            FuInputStream *stream,
50
            gsize *idx,
51
            GError **error)
52
120k
{
53
120k
  guint32 pcr;
54
120k
  guint32 digestcnt;
55
120k
  guint32 datasz = 0;
56
120k
  g_autoptr(GBytes) checksum_sha1 = NULL;
57
120k
  g_autoptr(GBytes) checksum_sha256 = NULL;
58
120k
  g_autoptr(GBytes) checksum_sha384 = NULL;
59
120k
  g_autoptr(FuStructTpmEventLog2) st = NULL;
60
120k
  g_autoptr(FuTpmEventlogItem) item = NULL;
61
62
  /* read checksum block */
63
120k
  st = fu_struct_tpm_event_log2_parse_stream(stream, *idx, error);
64
120k
  if (st == NULL)
65
40
    return FALSE;
66
120k
  *idx += st->buf->len;
67
120k
  digestcnt = fu_struct_tpm_event_log2_get_digest_count(st);
68
121k
  for (guint i = 0; i < digestcnt; i++) {
69
1.49k
    guint16 alg_type = 0;
70
1.49k
    guint32 alg_size = 0;
71
1.49k
    g_autoptr(GBytes) checksum = NULL;
72
73
    /* get checksum type */
74
1.49k
    if (!fu_input_stream_read_u16(stream, *idx, &alg_type, G_LITTLE_ENDIAN, error))
75
67
      return FALSE;
76
1.42k
    alg_size = fu_tpm_eventlog_v2_hash_get_size(alg_type);
77
1.42k
    if (alg_size == 0) {
78
51
      g_set_error(error,
79
51
            FWUPD_ERROR,
80
51
            FWUPD_ERROR_NOT_SUPPORTED,
81
51
            "hash algorithm 0x%x size not known",
82
51
            alg_type);
83
51
      return FALSE;
84
51
    }
85
86
    /* build checksum */
87
1.37k
    *idx += sizeof(alg_type);
88
89
    /* copy hash */
90
1.37k
    checksum = fu_input_stream_read_bytes(stream, *idx, alg_size, NULL, error);
91
1.37k
    if (checksum == NULL)
92
5
      return FALSE;
93
94
    /* save this for analysis */
95
1.37k
    if (alg_type == FU_TPM_ALG_SHA1) {
96
629
      if (checksum_sha1 != NULL) {
97
1
        g_set_error(error,
98
1
              FWUPD_ERROR,
99
1
              FWUPD_ERROR_INVALID_DATA,
100
1
              "already have SHA1 value for TPM digest 0x%x",
101
1
              i);
102
1
        return FALSE;
103
1
      }
104
628
      checksum_sha1 = g_bytes_ref(checksum);
105
742
    } else if (alg_type == FU_TPM_ALG_SHA256) {
106
135
      if (checksum_sha256 != NULL) {
107
1
        g_set_error(error,
108
1
              FWUPD_ERROR,
109
1
              FWUPD_ERROR_INVALID_DATA,
110
1
              "already have SHA256 value for TPM digest 0x%x",
111
1
              i);
112
1
        return FALSE;
113
1
      }
114
134
      checksum_sha256 = g_bytes_ref(checksum);
115
607
    } else if (alg_type == FU_TPM_ALG_SHA384) {
116
522
      if (checksum_sha384 != NULL) {
117
2
        g_set_error(error,
118
2
              FWUPD_ERROR,
119
2
              FWUPD_ERROR_INVALID_DATA,
120
2
              "already have SHA384 value for TPM digest 0x%x",
121
2
              i);
122
2
        return FALSE;
123
2
      }
124
520
      checksum_sha384 = g_bytes_ref(checksum);
125
520
    }
126
127
    /* next block */
128
1.36k
    *idx += alg_size;
129
1.36k
  }
130
131
  /* read data block */
132
120k
  if (!fu_input_stream_read_u32(stream, *idx, &datasz, G_LITTLE_ENDIAN, error))
133
22
    return FALSE;
134
120k
  if (datasz > FU_MB) {
135
30
    g_set_error_literal(error,
136
30
            FWUPD_ERROR,
137
30
            FWUPD_ERROR_NOT_SUPPORTED,
138
30
            "event log item too large");
139
30
    return FALSE;
140
30
  }
141
142
  /* save blob */
143
119k
  *idx += sizeof(datasz);
144
119k
  pcr = fu_struct_tpm_event_log2_get_pcr(st);
145
146
  /* build item */
147
119k
  item = fu_tpm_eventlog_item_new();
148
119k
  fu_tpm_eventlog_item_set_pcr(item, pcr);
149
119k
  fu_tpm_eventlog_item_set_kind(item, fu_struct_tpm_event_log2_get_type(st));
150
119k
  if (checksum_sha1 != NULL)
151
616
    fu_tpm_eventlog_item_add_checksum(item, FU_TPM_ALG_SHA1, checksum_sha1);
152
119k
  if (checksum_sha256 != NULL)
153
126
    fu_tpm_eventlog_item_add_checksum(item, FU_TPM_ALG_SHA256, checksum_sha256);
154
119k
  if (checksum_sha384 != NULL)
155
510
    fu_tpm_eventlog_item_add_checksum(item, FU_TPM_ALG_SHA384, checksum_sha384);
156
119k
  if (datasz > 0) {
157
3.19k
    g_autoptr(GBytes) blob = NULL;
158
3.19k
    blob = fu_input_stream_read_bytes(stream, *idx, datasz, NULL, error);
159
3.19k
    if (blob == NULL)
160
51
      return FALSE;
161
3.14k
    fu_firmware_set_bytes(FU_FIRMWARE(item), blob);
162
3.14k
  }
163
119k
  if (!fu_firmware_add_image(FU_FIRMWARE(self), FU_FIRMWARE(item), error))
164
0
    return FALSE;
165
166
  /* next entry */
167
119k
  *idx += datasz;
168
119k
  return TRUE;
169
119k
}
170
171
static gboolean
172
fu_tpm_eventlog_v2_parse(FuFirmware *firmware,
173
       FuInputStream *stream,
174
       FuFirmwareParseFlags flags,
175
       GError **error)
176
880
{
177
880
  FuTpmEventlogV2 *self = FU_TPM_EVENTLOG_V2(firmware);
178
880
  guint32 hdrsz = 0x0;
179
880
  gsize streamsz = 0;
180
880
  g_autoptr(FuStructTpmEventLog2Hdr) st_hdr = NULL;
181
182
  /* look for TCG v2 signature */
183
880
  st_hdr = fu_struct_tpm_event_log2_hdr_parse_stream(stream, 0x0, error);
184
880
  if (st_hdr == NULL)
185
311
    return FALSE;
186
187
  /* advance over the header block */
188
569
  hdrsz = fu_struct_tpm_event_log2_hdr_get_datasz(st_hdr);
189
569
  if (!fu_input_stream_size(stream, &streamsz, error))
190
0
    return FALSE;
191
120k
  for (gsize idx = FU_STRUCT_TPM_EVENT_LOG1_ITEM_SIZE + hdrsz; idx < streamsz;) {
192
120k
    if (!fu_tpm_eventlog_v2_parse_item(self, stream, &idx, error))
193
270
      return FALSE;
194
120k
  }
195
196
  /* success */
197
299
  return TRUE;
198
569
}
199
200
static GByteArray *
201
fu_tpm_eventlog_v2_write_item(FuTpmEventlogItem *item, GError **error)
202
2.27k
{
203
2.27k
  guint32 digest_count = 0;
204
2.27k
  g_autoptr(FuStructTpmEventLog2) st = fu_struct_tpm_event_log2_new();
205
2.27k
  g_autoptr(GBytes) blob = NULL;
206
2.27k
  g_autoptr(GBytes) digest_sha1 = NULL;
207
2.27k
  g_autoptr(GBytes) digest_sha256 = NULL;
208
2.27k
  g_autoptr(GBytes) digest_sha384 = NULL;
209
210
  /* get all the checksums we know about */
211
2.27k
  digest_sha1 = fu_tpm_eventlog_item_get_checksum(item, FU_TPM_ALG_SHA1, NULL);
212
2.27k
  if (digest_sha1 != NULL)
213
342
    digest_count++;
214
2.27k
  digest_sha256 = fu_tpm_eventlog_item_get_checksum(item, FU_TPM_ALG_SHA256, NULL);
215
2.27k
  if (digest_sha256 != NULL)
216
79
    digest_count++;
217
2.27k
  digest_sha384 = fu_tpm_eventlog_item_get_checksum(item, FU_TPM_ALG_SHA384, NULL);
218
2.27k
  if (digest_sha384 != NULL)
219
276
    digest_count++;
220
221
  /* write struct */
222
2.27k
  fu_struct_tpm_event_log2_set_pcr(st, fu_tpm_eventlog_item_get_pcr(item));
223
2.27k
  fu_struct_tpm_event_log2_set_type(st, fu_tpm_eventlog_item_get_kind(item));
224
2.27k
  fu_struct_tpm_event_log2_set_digest_count(st, digest_count);
225
2.27k
  if (digest_sha1 != NULL) {
226
342
    fu_byte_array_append_uint16(st->buf, FU_TPM_ALG_SHA1, G_LITTLE_ENDIAN);
227
342
    fu_byte_array_append_bytes(st->buf, digest_sha1);
228
342
  }
229
2.27k
  if (digest_sha256 != NULL) {
230
79
    fu_byte_array_append_uint16(st->buf, FU_TPM_ALG_SHA256, G_LITTLE_ENDIAN);
231
79
    fu_byte_array_append_bytes(st->buf, digest_sha256);
232
79
  }
233
2.27k
  if (digest_sha384 != NULL) {
234
276
    fu_byte_array_append_uint16(st->buf, FU_TPM_ALG_SHA384, G_LITTLE_ENDIAN);
235
276
    fu_byte_array_append_bytes(st->buf, digest_sha384);
236
276
  }
237
238
  /* write data */
239
2.27k
  blob = fu_firmware_get_bytes(FU_FIRMWARE(item), error);
240
2.27k
  if (blob == NULL)
241
118
    return NULL;
242
2.15k
  fu_byte_array_append_uint32(st->buf, g_bytes_get_size(blob), G_LITTLE_ENDIAN);
243
2.15k
  fu_byte_array_append_bytes(st->buf, blob);
244
245
  /* done, dump */
246
2.15k
  return g_steal_pointer(&st->buf);
247
2.27k
}
248
249
static GByteArray *
250
fu_tpm_eventlog_v2_write(FuFirmware *firmware, GError **error)
251
299
{
252
299
  g_autoptr(GByteArray) buf = g_byte_array_new();
253
299
  g_autoptr(GPtrArray) items = fu_firmware_get_images(firmware);
254
299
  g_autoptr(FuStructTpmEventLog2Hdr) st_hdr = fu_struct_tpm_event_log2_hdr_new();
255
256
  /* header */
257
299
  g_byte_array_append(buf, st_hdr->buf->data, st_hdr->buf->len);
258
259
2.45k
  for (guint i = 0; i < items->len; i++) {
260
2.27k
    FuTpmEventlogItem *item = g_ptr_array_index(items, i);
261
2.27k
    g_autoptr(GByteArray) buf_item = NULL;
262
2.27k
    buf_item = fu_tpm_eventlog_v2_write_item(item, error);
263
2.27k
    if (buf_item == NULL)
264
118
      return NULL;
265
2.15k
    g_byte_array_append(buf, buf_item->data, buf_item->len);
266
2.15k
  }
267
268
  /* success */
269
181
  return g_steal_pointer(&buf);
270
299
}
271
272
static void
273
fu_tpm_eventlog_v2_class_init(FuTpmEventlogV2Class *klass)
274
1
{
275
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
276
1
  fu_firmware_set_size_max(firmware_class, 16 * FU_MB);
277
1
  firmware_class->parse = fu_tpm_eventlog_v2_parse;
278
1
  firmware_class->write = fu_tpm_eventlog_v2_write;
279
1
  fu_firmware_add_image_gtype(firmware_class, FU_TYPE_TPM_EVENTLOG_ITEM);
280
1
}
281
282
static void
283
fu_tpm_eventlog_v2_init(FuTpmEventlogV2 *self)
284
880
{
285
880
}
286
287
/**
288
 * fu_tpm_eventlog_v2_new:
289
 *
290
 * Creates a new object to parse TPMv2 eventlog data.
291
 *
292
 * Returns: a #FuTpmEventlog
293
 *
294
 * Since: 2.1.1
295
 **/
296
FuTpmEventlog *
297
fu_tpm_eventlog_v2_new(void)
298
0
{
299
0
  FuTpmEventlogV2 *self;
300
0
  self = g_object_new(FU_TYPE_TPM_EVENTLOG_V2, NULL);
301
0
  return FU_TPM_EVENTLOG(self);
302
0
}