/src/fwupd/libfwupdplugin/fu-tpm-eventlog-item.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2026 Richard Hughes <richard@hughsie.com> |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | 0 | #define G_LOG_DOMAIN "FuTpmEventlog" |
8 | | |
9 | | #include "config.h" |
10 | | |
11 | | #include "fu-bytes.h" |
12 | | #include "fu-common.h" |
13 | | #include "fu-tpm-eventlog-item.h" |
14 | | |
15 | | const FuTpmAlg algs[] = { |
16 | | FU_TPM_ALG_SHA1, |
17 | | FU_TPM_ALG_SHA256, |
18 | | FU_TPM_ALG_SHA384, |
19 | | }; |
20 | | |
21 | | struct _FuTpmEventlogItem { |
22 | | FuFirmware parent_instance; |
23 | | FuTpmEventlogItemKind kind; |
24 | | guint8 pcr; |
25 | | GBytes *checksums[G_N_ELEMENTS(algs)]; |
26 | | }; |
27 | | |
28 | 0 | G_DEFINE_TYPE(FuTpmEventlogItem, fu_tpm_eventlog_item, FU_TYPE_FIRMWARE) |
29 | 0 |
|
30 | 0 | static guint |
31 | 0 | fu_tpm_eventlog_item_alg_to_idx(FuTpmAlg alg) |
32 | 0 | { |
33 | 0 | for (guint i = 0; i < G_N_ELEMENTS(algs); i++) { |
34 | 0 | if (algs[i] == alg) |
35 | 0 | return i; |
36 | 0 | } |
37 | 0 | return G_MAXUINT; |
38 | 0 | } |
39 | | |
40 | | /** |
41 | | * fu_tpm_eventlog_item_add_checksum: |
42 | | * @self: a #FuTpmEventlogItem |
43 | | * @alg: a #FuTpmAlg, e.g. %FU_TPM_ALG_SHA1 |
44 | | * @checksum: a #GBytes of the raw checksum |
45 | | * |
46 | | * Adds the checksum of a specific type. |
47 | | * |
48 | | * Since: 2.1.1 |
49 | | **/ |
50 | | void |
51 | | fu_tpm_eventlog_item_add_checksum(FuTpmEventlogItem *self, FuTpmAlg alg, GBytes *checksum) |
52 | 0 | { |
53 | 0 | guint csum_idx = fu_tpm_eventlog_item_alg_to_idx(alg); |
54 | 0 | g_return_if_fail(FU_IS_TPM_EVENTLOG_ITEM(self)); |
55 | 0 | g_return_if_fail(csum_idx != G_MAXUINT); |
56 | 0 | g_return_if_fail(checksum != NULL); |
57 | | |
58 | 0 | if (self->checksums[csum_idx] != NULL) |
59 | 0 | g_bytes_unref(self->checksums[csum_idx]); |
60 | 0 | self->checksums[csum_idx] = g_bytes_ref(checksum); |
61 | 0 | } |
62 | | |
63 | | /** |
64 | | * fu_tpm_eventlog_item_get_checksum: |
65 | | * @self: a #FuTpmEventlogItem |
66 | | * @alg: a #FuTpmAlg, e.g. %FU_TPM_ALG_SHA1 |
67 | | * @error: (nullable): optional return location for an error |
68 | | * |
69 | | * Gets the raw checksum of a specific type. |
70 | | * |
71 | | * Returns: a #GBytes, or %NULL on error |
72 | | * |
73 | | * Since: 2.1.1 |
74 | | **/ |
75 | | GBytes * |
76 | | fu_tpm_eventlog_item_get_checksum(FuTpmEventlogItem *self, FuTpmAlg alg, GError **error) |
77 | 0 | { |
78 | 0 | guint csum_idx = fu_tpm_eventlog_item_alg_to_idx(alg); |
79 | 0 | g_return_val_if_fail(FU_IS_TPM_EVENTLOG_ITEM(self), NULL); |
80 | 0 | g_return_val_if_fail(csum_idx != G_MAXUINT, NULL); |
81 | 0 | g_return_val_if_fail(error == NULL || *error == NULL, NULL); |
82 | | |
83 | 0 | if (self->checksums[csum_idx] == NULL) { |
84 | 0 | g_set_error(error, |
85 | 0 | FWUPD_ERROR, |
86 | 0 | FWUPD_ERROR_NOT_SUPPORTED, |
87 | 0 | "checksum %s not set", |
88 | 0 | fu_tpm_alg_to_string(alg)); |
89 | 0 | return NULL; |
90 | 0 | } |
91 | 0 | return g_bytes_ref(self->checksums[csum_idx]); |
92 | 0 | } |
93 | | |
94 | | /** |
95 | | * fu_tpm_eventlog_item_get_kind: |
96 | | * @self: a #FuTpmEventlogItem |
97 | | * |
98 | | * Gets the item kind. |
99 | | * |
100 | | * Returns: a #FuTpmEventlogItemKind, e.g. %FU_TPM_EVENTLOG_ITEM_KIND_EFI_PLATFORM_FIRMWARE_BLOB |
101 | | * |
102 | | * Since: 2.1.1 |
103 | | **/ |
104 | | FuTpmEventlogItemKind |
105 | | fu_tpm_eventlog_item_get_kind(FuTpmEventlogItem *self) |
106 | 0 | { |
107 | 0 | g_return_val_if_fail(FU_IS_TPM_EVENTLOG_ITEM(self), G_MAXUINT); |
108 | 0 | return self->kind; |
109 | 0 | } |
110 | | |
111 | | /** |
112 | | * fu_tpm_eventlog_item_set_kind: |
113 | | * @self: a #FuTpmEventlogItem |
114 | | * @kind: a #FuTpmEventlogItemKind, e.g. %FU_TPM_EVENTLOG_ITEM_KIND_EFI_PLATFORM_FIRMWARE_BLOB |
115 | | * |
116 | | * Sets item kind. |
117 | | * |
118 | | * Since: 2.1.1 |
119 | | **/ |
120 | | void |
121 | | fu_tpm_eventlog_item_set_kind(FuTpmEventlogItem *self, FuTpmEventlogItemKind kind) |
122 | 0 | { |
123 | 0 | g_return_if_fail(FU_IS_TPM_EVENTLOG_ITEM(self)); |
124 | 0 | self->kind = kind; |
125 | 0 | } |
126 | | |
127 | | /** |
128 | | * fu_tpm_eventlog_item_get_pcr: |
129 | | * @self: a #FuTpmEventlogItem |
130 | | * |
131 | | * Gets the PCR register. |
132 | | * |
133 | | * Returns: value |
134 | | * |
135 | | * Since: 2.1.1 |
136 | | **/ |
137 | | guint8 |
138 | | fu_tpm_eventlog_item_get_pcr(FuTpmEventlogItem *self) |
139 | 0 | { |
140 | 0 | g_return_val_if_fail(FU_IS_TPM_EVENTLOG_ITEM(self), G_MAXUINT8); |
141 | 0 | return self->pcr; |
142 | 0 | } |
143 | | |
144 | | /** |
145 | | * fu_tpm_eventlog_item_set_pcr: |
146 | | * @self: a #FuTpmEventlogItem |
147 | | * @pcr: a value |
148 | | * |
149 | | * Sets the PCR register. |
150 | | * |
151 | | * Since: 2.1.1 |
152 | | **/ |
153 | | void |
154 | | fu_tpm_eventlog_item_set_pcr(FuTpmEventlogItem *self, guint8 pcr) |
155 | 0 | { |
156 | 0 | g_return_if_fail(FU_IS_TPM_EVENTLOG_ITEM(self)); |
157 | 0 | self->pcr = pcr; |
158 | 0 | } |
159 | | |
160 | | static guint |
161 | | fu_tpm_eventlog_item_csum_kind_to_idx(GChecksumType csum_kind) |
162 | 0 | { |
163 | 0 | if (csum_kind == G_CHECKSUM_SHA1) |
164 | 0 | return fu_tpm_eventlog_item_alg_to_idx(FU_TPM_ALG_SHA1); |
165 | 0 | if (csum_kind == G_CHECKSUM_SHA256) |
166 | 0 | return fu_tpm_eventlog_item_alg_to_idx(FU_TPM_ALG_SHA256); |
167 | 0 | if (csum_kind == G_CHECKSUM_SHA384) |
168 | 0 | return fu_tpm_eventlog_item_alg_to_idx(FU_TPM_ALG_SHA384); |
169 | 0 | return G_MAXUINT; |
170 | 0 | } |
171 | | |
172 | | static gchar * |
173 | | fu_tpm_eventlog_item_get_checksum_string(FuFirmware *firmware, |
174 | | GChecksumType csum_kind, |
175 | | GError **error) |
176 | 0 | { |
177 | 0 | FuTpmEventlogItem *self = FU_TPM_EVENTLOG_ITEM(firmware); |
178 | 0 | guint csum_idx = fu_tpm_eventlog_item_csum_kind_to_idx(csum_kind); |
179 | | |
180 | | /* unset */ |
181 | 0 | if (csum_idx == G_MAXUINT) { |
182 | 0 | g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "not supported"); |
183 | 0 | return NULL; |
184 | 0 | } |
185 | 0 | if (self->checksums[csum_idx] == NULL) { |
186 | 0 | g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "not set"); |
187 | 0 | return NULL; |
188 | 0 | } |
189 | 0 | return fu_bytes_to_string(self->checksums[csum_idx]); |
190 | 0 | } |
191 | | |
192 | | static gboolean |
193 | | fu_tpm_eventlog_item_build(FuFirmware *firmware, XbNode *n, GError **error) |
194 | 0 | { |
195 | 0 | FuTpmEventlogItem *self = FU_TPM_EVENTLOG_ITEM(firmware); |
196 | 0 | const gchar *tmp; |
197 | 0 | guint64 tmp64; |
198 | | |
199 | | /* simple properties */ |
200 | 0 | tmp = xb_node_query_text(n, "kind", NULL); |
201 | 0 | if (tmp != NULL) |
202 | 0 | fu_tpm_eventlog_item_set_kind(self, fu_tpm_eventlog_item_kind_from_string(tmp)); |
203 | 0 | tmp64 = xb_node_query_text_as_uint(n, "pcr", NULL); |
204 | 0 | if (tmp64 != G_MAXUINT64) |
205 | 0 | fu_tpm_eventlog_item_set_pcr(self, tmp64); |
206 | | |
207 | | /* checksums */ |
208 | 0 | for (guint i = 0; i < G_N_ELEMENTS(algs); i++) { |
209 | 0 | tmp = xb_node_query_text(n, fu_tpm_alg_to_string(algs[i]), NULL); |
210 | 0 | if (tmp != NULL) { |
211 | 0 | g_autoptr(GBytes) blob = fu_bytes_from_string(tmp, error); |
212 | 0 | if (blob == NULL) |
213 | 0 | return FALSE; |
214 | 0 | fu_tpm_eventlog_item_add_checksum(self, algs[i], blob); |
215 | 0 | } |
216 | 0 | } |
217 | | |
218 | | /* success */ |
219 | 0 | return TRUE; |
220 | 0 | } |
221 | | |
222 | | static void |
223 | | fu_tpm_eventlog_item_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn) |
224 | 0 | { |
225 | 0 | FuTpmEventlogItem *self = FU_TPM_EVENTLOG_ITEM(firmware); |
226 | 0 | fu_xmlb_builder_insert_kv(bn, "kind", fu_tpm_eventlog_item_kind_to_string(self->kind)); |
227 | 0 | fu_xmlb_builder_insert_kx(bn, "pcr", self->pcr); |
228 | 0 | for (guint i = 0; i < G_N_ELEMENTS(algs); i++) { |
229 | 0 | if (self->checksums[i] != NULL) { |
230 | 0 | g_autofree gchar *value = fu_bytes_to_string(self->checksums[i]); |
231 | 0 | fu_xmlb_builder_insert_kv(bn, fu_tpm_alg_to_string(algs[i]), value); |
232 | 0 | } |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | | static void |
237 | | fu_tpm_eventlog_item_finalize(GObject *object) |
238 | 0 | { |
239 | 0 | FuTpmEventlogItem *self = FU_TPM_EVENTLOG_ITEM(object); |
240 | |
|
241 | 0 | for (guint i = 0; i < G_N_ELEMENTS(self->checksums); i++) { |
242 | 0 | if (self->checksums[i] != NULL) |
243 | 0 | g_bytes_unref(self->checksums[i]); |
244 | 0 | } |
245 | |
|
246 | 0 | G_OBJECT_CLASS(fu_tpm_eventlog_item_parent_class)->finalize(object); |
247 | 0 | } |
248 | | |
249 | | static void |
250 | | fu_tpm_eventlog_item_class_init(FuTpmEventlogItemClass *klass) |
251 | 0 | { |
252 | 0 | FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass); |
253 | 0 | GObjectClass *object_class = G_OBJECT_CLASS(klass); |
254 | 0 | object_class->finalize = fu_tpm_eventlog_item_finalize; |
255 | 0 | firmware_class->get_checksum = fu_tpm_eventlog_item_get_checksum_string; |
256 | 0 | firmware_class->build = fu_tpm_eventlog_item_build; |
257 | 0 | firmware_class->export = fu_tpm_eventlog_item_export; |
258 | 0 | } |
259 | | |
260 | | static void |
261 | | fu_tpm_eventlog_item_init(FuTpmEventlogItem *self) |
262 | 0 | { |
263 | 0 | } |
264 | | |
265 | | /** |
266 | | * fu_tpm_eventlog_item_new: |
267 | | * |
268 | | * Returns: (transfer full): a #FuTpmEventlogItem |
269 | | * |
270 | | * Since: 2.1.1 |
271 | | **/ |
272 | | FuTpmEventlogItem * |
273 | | fu_tpm_eventlog_item_new(void) |
274 | 0 | { |
275 | 0 | return g_object_new(FU_TYPE_TPM_EVENTLOG_ITEM, NULL); |
276 | 0 | } |