/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 |