Coverage Report

Created: 2025-06-22 06:29

/src/fwupd/libfwupdplugin/fu-coswid-common.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2024 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
0
#define G_LOG_DOMAIN "FuFirmware"
8
9
#include "config.h"
10
11
#include <fwupd.h>
12
13
#include "fu-coswid-common.h"
14
15
#ifdef HAVE_CBOR
16
17
/**
18
 * fu_coswid_read_string:
19
 * @item: a #cbor_item_t
20
 * @value: read value
21
 * @error: (nullable): optional return location for an error
22
 *
23
 * Reads a string value. If a bytestring is provided it is converted to a GUID.
24
 *
25
 * Returns: %TRUE for success
26
 *
27
 * Since: 1.9.17
28
 **/
29
gchar *
30
fu_coswid_read_string(cbor_item_t *item, GError **error)
31
30.9k
{
32
30.9k
  g_return_val_if_fail(item != NULL, NULL);
33
30.9k
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
34
35
30.9k
  if (cbor_isa_string(item)) {
36
29.0k
    if (cbor_string_handle(item) == NULL) {
37
0
      g_set_error_literal(error,
38
0
              FWUPD_ERROR,
39
0
              FWUPD_ERROR_INVALID_DATA,
40
0
              "item has no string set");
41
0
      return NULL;
42
0
    }
43
29.0k
    return g_strndup((const gchar *)cbor_string_handle(item), cbor_string_length(item));
44
29.0k
  }
45
1.94k
  if (cbor_isa_bytestring(item) && cbor_bytestring_length(item) == 16) {
46
1.89k
    return fwupd_guid_to_string((const fwupd_guid_t *)cbor_bytestring_handle(item),
47
1.89k
              FWUPD_GUID_FLAG_NONE);
48
1.89k
  }
49
52
  g_set_error_literal(error,
50
52
          FWUPD_ERROR,
51
52
          FWUPD_ERROR_INVALID_DATA,
52
52
          "item is not a string or GUID bytestring");
53
52
  return NULL;
54
1.94k
}
55
56
/**
57
 * fu_coswid_read_byte_array:
58
 * @item: a #cbor_item_t
59
 * @value: read value
60
 * @error: (nullable): optional return location for an error
61
 *
62
 * Reads a bytestring value as a #GByteArray.
63
 *
64
 * Returns: %TRUE for success
65
 *
66
 * Since: 1.9.17
67
 **/
68
GByteArray *
69
fu_coswid_read_byte_array(cbor_item_t *item, GError **error)
70
1.65k
{
71
1.65k
  g_autoptr(GByteArray) buf = g_byte_array_new();
72
73
1.65k
  g_return_val_if_fail(item != NULL, NULL);
74
1.65k
  g_return_val_if_fail(error == NULL || *error == NULL, NULL);
75
76
1.65k
  if (!cbor_isa_bytestring(item)) {
77
13
    g_set_error_literal(error,
78
13
            FWUPD_ERROR,
79
13
            FWUPD_ERROR_INVALID_DATA,
80
13
            "item is not a bytestring");
81
13
    return NULL;
82
13
  }
83
1.64k
  if (cbor_bytestring_handle(item) == NULL) {
84
0
    g_set_error_literal(error,
85
0
            FWUPD_ERROR,
86
0
            FWUPD_ERROR_INVALID_DATA,
87
0
            "item has no bytestring set");
88
0
    return NULL;
89
0
  }
90
1.64k
  g_byte_array_append(buf, cbor_bytestring_handle(item), cbor_bytestring_length(item));
91
1.64k
  return g_steal_pointer(&buf);
92
1.64k
}
93
94
/**
95
 * fu_coswid_read_tag:
96
 * @item: a #cbor_item_t
97
 * @value: read value
98
 * @error: (nullable): optional return location for an error
99
 *
100
 * Reads a tag value.
101
 *
102
 * Returns: %TRUE for success
103
 *
104
 * Since: 1.9.17
105
 **/
106
gboolean
107
fu_coswid_read_tag(cbor_item_t *item, FuCoswidTag *value, GError **error)
108
167k
{
109
167k
  guint64 tmp;
110
111
167k
  g_return_val_if_fail(item != NULL, FALSE);
112
167k
  g_return_val_if_fail(value != NULL, FALSE);
113
167k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
114
115
167k
  if (!cbor_isa_uint(item)) {
116
66
    g_set_error_literal(error,
117
66
            FWUPD_ERROR,
118
66
            FWUPD_ERROR_INVALID_DATA,
119
66
            "tag item is not a uint");
120
66
    return FALSE;
121
66
  }
122
167k
  tmp = cbor_get_int(item);
123
167k
  if (tmp > G_MAXUINT8) {
124
88
    g_set_error(error,
125
88
          FWUPD_ERROR,
126
88
          FWUPD_ERROR_INVALID_DATA,
127
88
          "0x%x is too large for tag",
128
88
          (guint)tmp);
129
88
    return FALSE;
130
88
  }
131
167k
  *value = (FuCoswidTag)tmp;
132
167k
  return TRUE;
133
167k
}
134
135
/**
136
 * fu_coswid_read_version_scheme:
137
 * @item: a #cbor_item_t
138
 * @value: read value
139
 * @error: (nullable): optional return location for an error
140
 *
141
 * Reads a version-scheme value.
142
 *
143
 * Returns: %TRUE for success
144
 *
145
 * Since: 1.9.17
146
 **/
147
gboolean
148
fu_coswid_read_version_scheme(cbor_item_t *item, FuCoswidVersionScheme *value, GError **error)
149
1.12k
{
150
1.12k
  g_return_val_if_fail(item != NULL, FALSE);
151
1.12k
  g_return_val_if_fail(value != NULL, FALSE);
152
1.12k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
153
154
1.12k
  if (!cbor_isa_uint(item)) {
155
1
    g_set_error_literal(error,
156
1
            FWUPD_ERROR,
157
1
            FWUPD_ERROR_INVALID_DATA,
158
1
            "version-scheme item is not a uint");
159
1
    return FALSE;
160
1
  }
161
1.12k
  *value = (FuCoswidVersionScheme)cbor_get_int(item);
162
1.12k
  return TRUE;
163
1.12k
}
164
165
/**
166
 * fu_coswid_read_u8:
167
 * @item: a #cbor_item_t
168
 * @value: read value
169
 * @error: (nullable): optional return location for an error
170
 *
171
 * Reads a #guint8 tag value.
172
 *
173
 * Returns: %TRUE for success
174
 *
175
 * Since: 1.9.17
176
 **/
177
gboolean
178
fu_coswid_read_u8(cbor_item_t *item, guint8 *value, GError **error)
179
26.8k
{
180
26.8k
  guint64 tmp;
181
182
26.8k
  g_return_val_if_fail(item != NULL, FALSE);
183
26.8k
  g_return_val_if_fail(value != NULL, FALSE);
184
26.8k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
185
186
26.8k
  if (!cbor_isa_uint(item)) {
187
17
    g_set_error_literal(error,
188
17
            FWUPD_ERROR,
189
17
            FWUPD_ERROR_INVALID_DATA,
190
17
            "value item is not a uint");
191
17
    return FALSE;
192
17
  }
193
26.8k
  tmp = cbor_get_int(item);
194
26.8k
  if (tmp > G_MAXUINT8) {
195
83
    g_set_error(error,
196
83
          FWUPD_ERROR,
197
83
          FWUPD_ERROR_INVALID_DATA,
198
83
          "0x%x is too large for u8",
199
83
          (guint)tmp);
200
83
    return FALSE;
201
83
  }
202
26.7k
  *value = (guint8)tmp;
203
26.7k
  return TRUE;
204
26.8k
}
205
206
/**
207
 * fu_coswid_read_s8:
208
 * @item: a #cbor_item_t
209
 * @value: read value
210
 * @error: (nullable): optional return location for an error
211
 *
212
 * Reads a #gint8 value.
213
 *
214
 * Returns: %TRUE for success
215
 *
216
 * Since: 1.9.17
217
 **/
218
gboolean
219
fu_coswid_read_s8(cbor_item_t *item, gint8 *value, GError **error)
220
694
{
221
694
  guint64 tmp;
222
223
694
  g_return_val_if_fail(item != NULL, FALSE);
224
694
  g_return_val_if_fail(value != NULL, FALSE);
225
694
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
226
227
694
  if (!cbor_is_int(item)) {
228
1
    g_set_error_literal(error,
229
1
            FWUPD_ERROR,
230
1
            FWUPD_ERROR_INVALID_DATA,
231
1
            "value item is not a int");
232
1
    return FALSE;
233
1
  }
234
693
  tmp = cbor_get_int(item);
235
693
  if (tmp > 127) {
236
80
    g_set_error(error,
237
80
          FWUPD_ERROR,
238
80
          FWUPD_ERROR_INVALID_DATA,
239
80
          "0x%x is too large for s8",
240
80
          (guint)tmp);
241
80
    return FALSE;
242
80
  }
243
613
  *value = cbor_isa_negint(item) ? (gint8)((-1) - tmp) : (gint8)tmp;
244
613
  return TRUE;
245
693
}
246
247
/**
248
 * fu_coswid_read_u64:
249
 * @item: a #cbor_item_t
250
 * @value: read value
251
 * @error: (nullable): optional return location for an error
252
 *
253
 * Reads a #guint64 tag value.
254
 *
255
 * Returns: %TRUE for success
256
 *
257
 * Since: 1.9.17
258
 **/
259
gboolean
260
fu_coswid_read_u64(cbor_item_t *item, guint64 *value, GError **error)
261
831
{
262
831
  g_return_val_if_fail(item != NULL, FALSE);
263
831
  g_return_val_if_fail(value != NULL, FALSE);
264
831
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
265
266
831
  if (!cbor_isa_uint(item)) {
267
1
    g_set_error_literal(error,
268
1
            FWUPD_ERROR,
269
1
            FWUPD_ERROR_INVALID_DATA,
270
1
            "value item is not a uint");
271
1
    return FALSE;
272
1
  }
273
830
  *value = cbor_get_int(item);
274
830
  return TRUE;
275
831
}
276
277
/**
278
 * fu_coswid_write_tag_string:
279
 * @item: a #cbor_item_t
280
 * @tag: a #FuCoswidTag, e.g. %FU_COSWID_TAG_PAYLOAD
281
 * @value: string
282
 *
283
 * Writes a string tag value.
284
 *
285
 * Returns: %TRUE for success
286
 *
287
 * Since: 1.9.17
288
 **/
289
void
290
fu_coswid_write_tag_string(cbor_item_t *item, FuCoswidTag tag, const gchar *value)
291
53.9k
{
292
53.9k
  g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
293
53.9k
  g_autoptr(cbor_item_t) val = cbor_build_string(value);
294
53.9k
  if (!cbor_map_add(item, (struct cbor_pair){.key = key, .value = val}))
295
0
    g_critical("failed to push string to indefinite map");
296
53.9k
}
297
298
/**
299
 * fu_coswid_write_tag_bytestring:
300
 * @item: a #cbor_item_t
301
 * @tag: a #FuCoswidTag, e.g. %FU_COSWID_TAG_PAYLOAD
302
 * @buf: a buffer of data
303
 * @bufsz: sizeof @buf
304
 *
305
 * Writes a bytestring tag value.
306
 *
307
 * Returns: %TRUE for success
308
 *
309
 * Since: 1.9.17
310
 **/
311
void
312
fu_coswid_write_tag_bytestring(cbor_item_t *item, FuCoswidTag tag, const guint8 *buf, gsize bufsz)
313
484
{
314
484
  g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
315
484
  g_autoptr(cbor_item_t) val = cbor_build_bytestring((cbor_data)buf, bufsz);
316
484
  if (!cbor_map_add(item, (struct cbor_pair){.key = key, .value = val}))
317
0
    g_critical("failed to push bytestring to indefinite map");
318
484
}
319
320
/**
321
 * fu_coswid_write_tag_bool:
322
 * @item: a #cbor_item_t
323
 * @tag: a #FuCoswidTag, e.g. %FU_COSWID_TAG_PAYLOAD
324
 * @value: boolean
325
 *
326
 * Writes a #gboolean tag value.
327
 *
328
 * Returns: %TRUE for success
329
 *
330
 * Since: 1.9.17
331
 **/
332
void
333
fu_coswid_write_tag_bool(cbor_item_t *item, FuCoswidTag tag, gboolean value)
334
18.8k
{
335
18.8k
  g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
336
18.8k
  g_autoptr(cbor_item_t) val = cbor_build_bool(value);
337
18.8k
  if (!cbor_map_add(item, (struct cbor_pair){.key = key, .value = val}))
338
0
    g_critical("failed to push bool to indefinite map");
339
18.8k
}
340
341
/**
342
 * fu_coswid_write_tag_u16:
343
 * @item: a #cbor_item_t
344
 * @tag: a #FuCoswidTag, e.g. %FU_COSWID_TAG_PAYLOAD
345
 * @value: unsigned integer
346
 *
347
 * Writes a #guint16 tag value.
348
 *
349
 * Returns: %TRUE for success
350
 *
351
 * Since: 1.9.17
352
 **/
353
void
354
fu_coswid_write_tag_u16(cbor_item_t *item, FuCoswidTag tag, guint16 value)
355
18.6k
{
356
18.6k
  g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
357
18.6k
  g_autoptr(cbor_item_t) val = cbor_build_uint16(value);
358
18.6k
  if (!cbor_map_add(item, (struct cbor_pair){.key = key, .value = val}))
359
0
    g_critical("failed to push u16 to indefinite map");
360
18.6k
}
361
362
/**
363
 * fu_coswid_write_tag_u64:
364
 * @item: a #cbor_item_t
365
 * @tag: a #FuCoswidTag, e.g. %FU_COSWID_TAG_PAYLOAD
366
 * @value: unsigned integer
367
 *
368
 * Writes a #guint64 tag value.
369
 *
370
 * Returns: %TRUE for success
371
 *
372
 * Since: 1.9.17
373
 **/
374
void
375
fu_coswid_write_tag_u64(cbor_item_t *item, FuCoswidTag tag, guint64 value)
376
300
{
377
300
  g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
378
300
  g_autoptr(cbor_item_t) val = cbor_build_uint64(value);
379
300
  if (!cbor_map_add(item, (struct cbor_pair){.key = key, .value = val}))
380
0
    g_critical("failed to push u64 to indefinite map");
381
300
}
382
383
/**
384
 * fu_coswid_write_tag_s8:
385
 * @item: a #cbor_item_t
386
 * @tag: a #FuCoswidTag, e.g. %FU_COSWID_TAG_PAYLOAD
387
 * @value: signed integer
388
 *
389
 * Writes a #gint8 tag value.
390
 *
391
 * Returns: %TRUE for success
392
 *
393
 * Since: 1.9.17
394
 **/
395
void
396
fu_coswid_write_tag_s8(cbor_item_t *item, FuCoswidTag tag, gint8 value)
397
579k
{
398
579k
  g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
399
579k
  g_autoptr(cbor_item_t) val = cbor_new_int8();
400
579k
  if (value >= 0) {
401
579k
    cbor_set_uint8(val, value);
402
579k
  } else {
403
221
    cbor_set_uint8(val, 0xFF - value);
404
221
    cbor_mark_negint(val);
405
221
  }
406
579k
  if (!cbor_map_add(item, (struct cbor_pair){.key = key, .value = val}))
407
0
    g_critical("failed to push s8 to indefinite map");
408
579k
}
409
410
/**
411
 * fu_coswid_write_tag_item:
412
 * @item: a #cbor_item_t
413
 * @tag: a #FuCoswidTag, e.g. %FU_COSWID_TAG_PAYLOAD
414
 * @value: a #cbor_item_t
415
 *
416
 * Writes a raw tag value.
417
 *
418
 * Returns: %TRUE for success
419
 *
420
 * Since: 1.9.17
421
 **/
422
void
423
fu_coswid_write_tag_item(cbor_item_t *item, FuCoswidTag tag, cbor_item_t *value)
424
116k
{
425
116k
  g_autoptr(cbor_item_t) key = cbor_build_uint8(tag);
426
116k
  if (!cbor_map_add(item, (struct cbor_pair){.key = key, .value = value}))
427
0
    g_critical("failed to push item to indefinite map");
428
116k
}
429
430
/**
431
 * fu_coswid_parse_one_or_many:
432
 * @item: a #cbor_item_t
433
 * @func: a function to call with each map value
434
 * @user_data: pointer value to pass to @func
435
 * @error: (nullable): optional return location for an error
436
 *
437
 * Parses an item that *may* be an array, calling @func on each map value.
438
 *
439
 * Returns: %TRUE for success
440
 *
441
 * Since: 1.9.17
442
 **/
443
gboolean
444
fu_coswid_parse_one_or_many(cbor_item_t *item,
445
          FuCoswidItemFunc func,
446
          gpointer user_data,
447
          GError **error)
448
17.9k
{
449
17.9k
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
450
451
  /* one */
452
17.9k
  if (cbor_isa_map(item))
453
6.56k
    return func(item, user_data, error);
454
455
  /* many */
456
11.4k
  if (cbor_isa_array(item)) {
457
2.31M
    for (guint j = 0; j < cbor_array_size(item); j++) {
458
2.30M
      g_autoptr(cbor_item_t) value = cbor_array_get(item, j);
459
2.30M
      if (!cbor_isa_map(value)) {
460
5
        g_set_error_literal(error,
461
5
                FWUPD_ERROR,
462
5
                FWUPD_ERROR_INVALID_DATA,
463
5
                "not an array of a map");
464
5
        return FALSE;
465
5
      }
466
2.30M
      if (!func(value, user_data, error))
467
19
        return FALSE;
468
2.30M
    }
469
11.3k
    return TRUE;
470
11.3k
  }
471
472
  /* not sure what to do */
473
15
  g_set_error_literal(error,
474
15
          FWUPD_ERROR,
475
15
          FWUPD_ERROR_INVALID_DATA,
476
15
          "neither an array or map");
477
15
  return FALSE;
478
11.4k
}
479
480
#endif