Coverage Report

Created: 2026-01-10 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-efi-signature.c
Line
Count
Source
1
/*
2
 * Copyright 2020 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#include "config.h"
8
9
#include "fu-byte-array.h"
10
#include "fu-bytes.h"
11
#include "fu-common.h"
12
#include "fu-efi-signature-private.h"
13
14
/**
15
 * FuEfiSignature:
16
 *
17
 * A UEFI Signature as found in an `EFI_SIGNATURE_LIST`.
18
 *
19
 * See also: [class@FuFirmware]
20
 */
21
22
typedef struct {
23
  FuEfiSignatureKind kind;
24
  gchar *owner;
25
} FuEfiSignaturePrivate;
26
27
0
G_DEFINE_TYPE_WITH_PRIVATE(FuEfiSignature, fu_efi_signature, FU_TYPE_FIRMWARE)
28
0
#define GET_PRIVATE(o) (fu_efi_signature_get_instance_private(o))
29
30
static void
31
fu_efi_signature_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn)
32
0
{
33
0
  FuEfiSignature *self = FU_EFI_SIGNATURE(firmware);
34
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
35
36
0
  fu_xmlb_builder_insert_kv(bn, "kind", fu_efi_signature_kind_to_string(priv->kind));
37
0
  fu_xmlb_builder_insert_kv(bn, "owner", priv->owner);
38
39
  /* special case: this is *literally* a hash */
40
0
  if (priv->kind == FU_EFI_SIGNATURE_KIND_SHA256) {
41
0
    g_autoptr(GBytes) blob = fu_firmware_get_bytes(firmware, NULL);
42
0
    if (blob != NULL) {
43
0
      g_autofree gchar *str = fu_bytes_to_string(blob);
44
0
      fu_xmlb_builder_insert_kv(bn, "checksum", str);
45
0
    }
46
0
  }
47
0
}
48
49
/**
50
 * fu_efi_signature_new: (skip):
51
 * @kind: A #FuEfiSignatureKind
52
 *
53
 * Creates a new EFI_SIGNATURE.
54
 *
55
 * Returns: (transfer full): signature
56
 *
57
 * Since: 2.0.5
58
 **/
59
FuEfiSignature *
60
fu_efi_signature_new(FuEfiSignatureKind kind)
61
0
{
62
0
  g_autoptr(FuEfiSignature) self = g_object_new(FU_TYPE_EFI_SIGNATURE, NULL);
63
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
64
0
  priv->kind = kind;
65
0
  return g_steal_pointer(&self);
66
0
}
67
68
/**
69
 * fu_efi_signature_get_kind:
70
 * @self: A #FuEfiSignature
71
 *
72
 * Returns the signature kind.
73
 *
74
 * Returns: #FuEfiSignatureKind, e.g. %FU_EFI_SIGNATURE_KIND_SHA256
75
 *
76
 * Since: 1.5.5
77
 **/
78
FuEfiSignatureKind
79
fu_efi_signature_get_kind(FuEfiSignature *self)
80
0
{
81
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
82
0
  g_return_val_if_fail(FU_IS_EFI_SIGNATURE(self), FU_EFI_SIGNATURE_KIND_UNKNOWN);
83
0
  return priv->kind;
84
0
}
85
86
/* private */
87
void
88
fu_efi_signature_set_kind(FuEfiSignature *self, FuEfiSignatureKind kind)
89
0
{
90
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
91
0
  g_return_if_fail(FU_IS_EFI_SIGNATURE(self));
92
0
  priv->kind = kind;
93
0
}
94
95
/**
96
 * fu_efi_signature_get_owner:
97
 * @self: A #FuEfiSignature
98
 *
99
 * Returns the GUID of the signature owner.
100
 *
101
 * Returns: GUID owner, perhaps %FU_EFI_SIGNATURE_GUID_MICROSOFT
102
 *
103
 * Since: 1.5.5
104
 **/
105
const gchar *
106
fu_efi_signature_get_owner(FuEfiSignature *self)
107
0
{
108
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
109
0
  g_return_val_if_fail(FU_IS_EFI_SIGNATURE(self), NULL);
110
0
  return priv->owner;
111
0
}
112
113
static gboolean
114
fu_efi_signature_parse(FuFirmware *firmware,
115
           GInputStream *stream,
116
           FuFirmwareParseFlags flags,
117
           GError **error)
118
0
{
119
0
  FuEfiSignature *self = FU_EFI_SIGNATURE(firmware);
120
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
121
0
  fwupd_guid_t guid = {0};
122
0
  gsize size = fu_firmware_get_size(firmware);
123
0
  g_autoptr(GBytes) data = NULL;
124
125
  /* sanity check */
126
0
  if (size <= sizeof(fwupd_guid_t)) {
127
0
    g_set_error(error,
128
0
          FWUPD_ERROR,
129
0
          FWUPD_ERROR_INVALID_DATA,
130
0
          "SignatureSize invalid: 0x%x",
131
0
          (guint)size);
132
0
    return FALSE;
133
0
  }
134
135
  /* GUID */
136
0
  if (!fu_input_stream_read_safe(stream,
137
0
               (guint8 *)&guid,
138
0
               sizeof(guid),
139
0
               0x0, /* seek to */
140
0
               0x0, /* offset */
141
0
               sizeof(guid),
142
0
               error)) {
143
0
    g_prefix_error_literal(error, "failed to read signature GUID: ");
144
0
    return FALSE;
145
0
  }
146
0
  priv->owner = fwupd_guid_to_string(&guid, FWUPD_GUID_FLAG_MIXED_ENDIAN);
147
148
  /* if data size is unspecified, we'll use the stream size */
149
0
  data = fu_input_stream_read_bytes(stream,
150
0
            sizeof(fwupd_guid_t),
151
0
            size - sizeof(fwupd_guid_t),
152
0
            NULL,
153
0
            error);
154
0
  if (data == NULL) {
155
0
    g_prefix_error_literal(error, "failed to read signature data: ");
156
0
    return FALSE;
157
0
  }
158
0
  fu_firmware_set_bytes(firmware, data);
159
160
  /* success */
161
0
  return TRUE;
162
0
}
163
164
static GByteArray *
165
fu_efi_signature_write(FuFirmware *firmware, GError **error)
166
0
{
167
0
  FuEfiSignature *self = FU_EFI_SIGNATURE(firmware);
168
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
169
0
  fwupd_guid_t owner = {0};
170
0
  g_autoptr(GByteArray) buf = g_byte_array_new();
171
0
  g_autoptr(GBytes) data = NULL;
172
173
  /* optional owner */
174
0
  if (priv->owner != NULL) {
175
0
    if (!fwupd_guid_from_string(priv->owner,
176
0
              &owner,
177
0
              FWUPD_GUID_FLAG_MIXED_ENDIAN,
178
0
              error))
179
0
      return NULL;
180
0
  }
181
0
  g_byte_array_append(buf, owner, sizeof(owner));
182
183
  /* data */
184
0
  data = fu_firmware_get_bytes_with_patches(firmware, error);
185
0
  if (data == NULL)
186
0
    return NULL;
187
0
  fu_byte_array_append_bytes(buf, data);
188
189
  /* success */
190
0
  return g_steal_pointer(&buf);
191
0
}
192
193
static gboolean
194
fu_efi_signature_build(FuFirmware *firmware, XbNode *n, GError **error)
195
0
{
196
0
  FuEfiSignature *self = FU_EFI_SIGNATURE(firmware);
197
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
198
0
  const gchar *tmp;
199
200
  /* optional properties */
201
0
  tmp = xb_node_query_text(n, "kind", NULL);
202
0
  if (tmp != NULL) {
203
0
    priv->kind = fu_efi_signature_kind_from_string(tmp);
204
0
    if (priv->kind == FU_EFI_SIGNATURE_KIND_UNKNOWN) {
205
0
      g_set_error(error,
206
0
            FWUPD_ERROR,
207
0
            FWUPD_ERROR_INVALID_DATA,
208
0
            "invalid kind: %s",
209
0
            tmp);
210
0
      return FALSE;
211
0
    }
212
0
  }
213
0
  tmp = xb_node_query_text(n, "owner", NULL);
214
0
  if (tmp != NULL) {
215
0
    if (!fwupd_guid_from_string(tmp, NULL, FWUPD_GUID_FLAG_MIXED_ENDIAN, error)) {
216
0
      g_prefix_error(error, "failed to parse owner %s, expected GUID: ", tmp);
217
0
      return FALSE;
218
0
    }
219
0
    g_free(priv->owner);
220
0
    priv->owner = g_strdup(tmp);
221
0
  }
222
0
  tmp = xb_node_query_text(n, "checksum", NULL);
223
0
  if (tmp != NULL) {
224
0
    g_autoptr(GBytes) data = NULL;
225
0
    data = fu_bytes_from_string(tmp, error);
226
0
    if (data == NULL)
227
0
      return FALSE;
228
0
    fu_firmware_set_bytes(firmware, data);
229
0
  }
230
231
  /* success */
232
0
  return TRUE;
233
0
}
234
235
static gchar *
236
fu_efi_signature_get_checksum(FuFirmware *firmware, GChecksumType csum_kind, GError **error)
237
0
{
238
0
  FuEfiSignature *self = FU_EFI_SIGNATURE(firmware);
239
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
240
0
  g_autoptr(GBytes) data = fu_firmware_get_bytes_with_patches(firmware, error);
241
0
  if (data == NULL)
242
0
    return NULL;
243
244
  /* special case: this is *literally* a hash */
245
0
  if (priv->kind == FU_EFI_SIGNATURE_KIND_SHA256 && csum_kind == G_CHECKSUM_SHA256)
246
0
    return fu_bytes_to_string(data);
247
248
  /* fallback */
249
0
  return g_compute_checksum_for_bytes(csum_kind, data);
250
0
}
251
252
static void
253
fu_efi_signature_finalize(GObject *obj)
254
0
{
255
0
  FuEfiSignature *self = FU_EFI_SIGNATURE(obj);
256
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
257
0
  g_free(priv->owner);
258
0
  G_OBJECT_CLASS(fu_efi_signature_parent_class)->finalize(obj);
259
0
}
260
261
static void
262
fu_efi_signature_class_init(FuEfiSignatureClass *klass)
263
0
{
264
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
265
0
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
266
0
  object_class->finalize = fu_efi_signature_finalize;
267
0
  firmware_class->export = fu_efi_signature_export;
268
0
  firmware_class->parse = fu_efi_signature_parse;
269
0
  firmware_class->write = fu_efi_signature_write;
270
0
  firmware_class->build = fu_efi_signature_build;
271
0
  firmware_class->get_checksum = fu_efi_signature_get_checksum;
272
0
}
273
274
static void
275
fu_efi_signature_init(FuEfiSignature *self)
276
0
{
277
0
  FuEfiSignaturePrivate *priv = GET_PRIVATE(self);
278
0
  priv->kind = FU_EFI_SIGNATURE_KIND_SHA256;
279
0
}