From d3d2c2c39fd3fd54ee7550fdc6a4cd87874b14b6 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Wed, 10 Oct 2018 20:01:05 +0100 Subject: [PATCH] Don't use AppStream-glib for the GUID helpers Long term we want to wean ourselves away from libappstream-glib. --- plugins/dell/fu-plugin-dell.c | 5 +- plugins/udev/fu-rom.c | 4 +- src/fu-common-guid.c | 129 ++++++++++++++++++++++++++++++++++ src/fu-common-guid.h | 19 +++++ src/fu-device.c | 17 ++--- src/fu-engine.c | 7 +- src/fu-hwids.c | 10 +-- src/fu-quirks.c | 6 +- src/fu-self-test.c | 25 +++++++ src/meson.build | 10 +++ 10 files changed, 209 insertions(+), 23 deletions(-) create mode 100644 src/fu-common-guid.c create mode 100644 src/fu-common-guid.h diff --git a/plugins/dell/fu-plugin-dell.c b/plugins/dell/fu-plugin-dell.c index 707aef12d..4c9364b3d 100644 --- a/plugins/dell/fu-plugin-dell.c +++ b/plugins/dell/fu-plugin-dell.c @@ -13,6 +13,7 @@ #include #include +#include "fu-common-guid.h" #include "fu-plugin-dell.h" #include "fu-plugin-vfuncs.h" #include "fu-device-metadata.h" @@ -597,11 +598,11 @@ fu_plugin_dell_detect_tpm (FuPlugin *plugin, GError **error) } tpm_guid_raw = g_strdup_printf ("%04x-%s", system_id, tpm_mode); - tpm_guid = as_utils_guid_from_string (tpm_guid_raw); + tpm_guid = fu_common_guid_from_string (tpm_guid_raw); tpm_id = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, tpm_guid); tpm_guid_raw_alt = g_strdup_printf ("%04x-%s", system_id, tpm_mode_alt); - tpm_guid_alt = as_utils_guid_from_string (tpm_guid_raw_alt); + tpm_guid_alt = fu_common_guid_from_string (tpm_guid_raw_alt); tpm_id_alt = g_strdup_printf ("DELL-%s" G_GUINT64_FORMAT, tpm_guid_alt); g_debug ("Creating primary TPM GUID %s and secondary TPM GUID %s", diff --git a/plugins/udev/fu-rom.c b/plugins/udev/fu-rom.c index 5f9917c45..0dc7c2dca 100644 --- a/plugins/udev/fu-rom.c +++ b/plugins/udev/fu-rom.c @@ -7,10 +7,10 @@ #include "config.h" #include -#include #include #include +#include "fu-common-guid.h" #include "fu-rom.h" static void fu_rom_finalize (GObject *object); @@ -689,7 +689,7 @@ fu_rom_load_data (FuRom *self, /* update guid */ id = g_strdup_printf ("PCI\\VEN_%04X&DEV_%04X", self->vendor_id, self->device_id); - self->guid = as_utils_guid_from_string (id); + self->guid = fu_common_guid_from_string (id); g_debug ("using %s for %s", self->guid, id); /* not known */ diff --git a/src/fu-common-guid.c b/src/fu-common-guid.c new file mode 100644 index 000000000..fe9006604 --- /dev/null +++ b/src/fu-common-guid.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#define G_LOG_DOMAIN "FuCommon" + +#include + +#include +#include + +#include "fwupd-error.h" + +#include "fu-common-guid.h" + +/** + * fu_common_guid_from_data: + * @namespace_id: A namespace ID, e.g. "6ba7b810-9dad-11d1-80b4-00c04fd430c8" + * @data: data to hash + * @data_len: length of @data + * @error: A #GError or %NULL + * + * Returns a GUID for some data. This uses a hash and so even small + * differences in the @data will produce radically different return values. + * + * The implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash. + * + * Returns: A new GUID, or %NULL if the namespace_id was invalid + * + * Since: 1.2.0 + **/ +gchar * +fu_common_guid_from_data (const gchar *namespace_id, + const guint8 *data, + gsize data_len, + GError **error) +{ + gchar guid_new[37]; /* 36 plus NUL */ + gsize digestlen = 20; + guint8 hash[20]; + gint rc; + uuid_t uu_namespace; + uuid_t uu_new; + g_autoptr(GChecksum) csum = NULL; + + g_return_val_if_fail (namespace_id != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (data_len != 0, FALSE); + + /* convert the namespace to binary */ + rc = uuid_parse (namespace_id, uu_namespace); + if (rc != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_SUPPORTED, + "namespace '%s' is invalid", + namespace_id); + return FALSE; + } + + /* hash the namespace and then the string */ + csum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (csum, (guchar *) uu_namespace, 16); + g_checksum_update (csum, (guchar *) data, (gssize) data_len); + g_checksum_get_digest (csum, hash, &digestlen); + + /* copy most parts of the hash 1:1 */ + memcpy (uu_new, hash, 16); + + /* set specific bits according to Section 4.1.3 */ + uu_new[6] = (guint8) ((uu_new[6] & 0x0f) | (5 << 4)); + uu_new[8] = (guint8) ((uu_new[8] & 0x3f) | 0x80); + + /* return as a string */ + uuid_unparse (uu_new, guid_new); + return g_strdup (guid_new); +} + +/** + * fu_common_guid_is_valid: + * @guid: string to check + * + * Checks the source string is a valid string GUID descriptor. + * + * Returns: %TRUE if @guid was a valid GUID, %FALSE otherwise + * + * Since: 1.2.0 + **/ +gboolean +fu_common_guid_is_valid (const gchar *guid) +{ + gint rc; + uuid_t uu; + if (guid == NULL) + return FALSE; + rc = uuid_parse (guid, uu); + return rc == 0; +} + +/** + * fu_common_guid_from_string: + * @str: A source string to use as a key + * + * Returns a GUID for a given string. This uses a hash and so even small + * differences in the @str will produce radically different return values. + * + * The implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash with a DNS namespace. + * The same result can be obtained with this simple python program: + * + * #!/usr/bin/python + * import uuid + * print uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') + * + * Returns: A new GUID, or %NULL if the string was invalid + * + * Since: 1.2.0 + **/ +gchar * +fu_common_guid_from_string (const gchar *str) +{ + if (str == NULL) + return NULL; + return fu_common_guid_from_data ("6ba7b810-9dad-11d1-80b4-00c04fd430c8", + (const guint8 *) str, strlen (str), NULL); +} diff --git a/src/fu-common-guid.h b/src/fu-common-guid.h new file mode 100644 index 000000000..db6e50fa9 --- /dev/null +++ b/src/fu-common-guid.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017-2018 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef __FU_COMMON_GUID_H__ +#define __FU_COMMON_GUID_H__ + +#include + +gboolean fu_common_guid_is_valid (const gchar *guid); +gchar *fu_common_guid_from_string (const gchar *str); +gchar *fu_common_guid_from_data (const gchar *namespace_id, + const guint8 *data, + gsize data_len, + GError **error); + +#endif /* __FU_COMMON_GUID_H__ */ diff --git a/src/fu-device.c b/src/fu-device.c index bb427fba8..582736ab2 100644 --- a/src/fu-device.c +++ b/src/fu-device.c @@ -13,6 +13,7 @@ #include #include "fu-common.h" +#include "fu-common-guid.h" #include "fu-device-private.h" #include "fu-mutex.h" @@ -534,8 +535,8 @@ fu_device_add_parent_guid (FuDevice *self, const gchar *guid) g_return_if_fail (guid != NULL); /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); + if (!fu_common_guid_is_valid (guid)) { + g_autofree gchar *tmp = fu_common_guid_from_string (guid); if (fu_device_has_parent_guid (self, tmp)) return; g_debug ("using %s for %s", tmp, guid); @@ -769,7 +770,7 @@ fu_device_add_guid_safe (FuDevice *self, const gchar *guid) * @guid: A GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad` * * Adds a GUID to the device. If the @guid argument is not a valid GUID then it - * is converted to a GUID using as_utils_guid_from_string(). + * is converted to a GUID using fu_common_guid_from_string(). * * Since: 0.7.2 **/ @@ -777,8 +778,8 @@ void fu_device_add_guid (FuDevice *self, const gchar *guid) { /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); + if (!fu_common_guid_is_valid (guid)) { + g_autofree gchar *tmp = fu_common_guid_from_string (guid); g_debug ("using %s for %s", tmp, guid); fu_device_add_guid_safe (self, tmp); return; @@ -794,7 +795,7 @@ fu_device_add_guid (FuDevice *self, const gchar *guid) * @guid: A GUID, e.g. `2082b5e0-7a64-478a-b1b2-e3404fab6dad` * * Adds a GUID to the device. If the @guid argument is not a valid GUID then it - * is converted to a GUID using as_utils_guid_from_string(). + * is converted to a GUID using fu_common_guid_from_string(). * * A counterpart GUID is typically the GUID of the same device in bootloader * or runtime mode, if they have a different device PCI or USB ID. Adding this @@ -806,8 +807,8 @@ void fu_device_add_counterpart_guid (FuDevice *self, const gchar *guid) { /* make valid */ - if (!as_utils_guid_is_valid (guid)) { - g_autofree gchar *tmp = as_utils_guid_from_string (guid); + if (!fu_common_guid_is_valid (guid)) { + g_autofree gchar *tmp = fu_common_guid_from_string (guid); g_debug ("using %s for counterpart %s", tmp, guid); fwupd_device_add_guid (FWUPD_DEVICE (self), tmp); return; diff --git a/src/fu-engine.c b/src/fu-engine.c index 5c4126640..0d9b524e2 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -25,6 +25,7 @@ #include "fwupd-resources.h" #include "fu-common-cab.h" +#include "fu-common-guid.h" #include "fu-common.h" #include "fu-config.h" #include "fu-debug.h" @@ -824,7 +825,7 @@ fu_engine_check_requirement_firmware (FuEngine *self, AsRequire *req, } /* another device */ - if (as_utils_guid_is_valid (as_require_get_value (req))) { + if (fu_common_guid_is_valid (as_require_get_value (req))) { const gchar *guid = as_require_get_value (req); const gchar *version; g_autoptr(FuDevice) device2 = NULL; @@ -996,9 +997,9 @@ fu_engine_vendor_fixup_provide_value (AsApp *app) g_autofree gchar *guid = NULL; if (as_provide_get_kind (prov) != AS_PROVIDE_KIND_FIRMWARE_FLASHED) continue; - if (as_utils_guid_is_valid (value)) + if (fu_common_guid_is_valid (value)) continue; - guid = as_utils_guid_from_string (value); + guid = fu_common_guid_from_string (value); as_provide_set_value (prov, guid); } } diff --git a/src/fu-hwids.c b/src/fu-hwids.c index c436e2bdb..b72af2c5e 100644 --- a/src/fu-hwids.c +++ b/src/fu-hwids.c @@ -11,9 +11,9 @@ #include #include #include -#include #include "fu-common.h" +#include "fu-common-guid.h" #include "fu-hwids.h" #include "fwupd-error.h" @@ -97,10 +97,10 @@ fu_hwids_get_guid_for_str (const gchar *str, GError **error) data[i] = GUINT16_TO_LE(data[i]); /* convert to a GUID */ - return as_utils_guid_from_data (namespace_id, - (guint8*) data, - items_written * 2, - error); + return fu_common_guid_from_data (namespace_id, + (guint8*) data, + items_written * 2, + error); } /** diff --git a/src/fu-quirks.c b/src/fu-quirks.c index 2f6ead814..c41845d30 100644 --- a/src/fu-quirks.c +++ b/src/fu-quirks.c @@ -11,9 +11,9 @@ #include #include #include -#include #include "fu-common.h" +#include "fu-common-guid.h" #include "fu-mutex.h" #include "fu-quirks.h" @@ -97,9 +97,9 @@ fu_quirks_build_group_key (const gchar *group) for (guint i = 0; guid_prefixes[i] != NULL; i++) { if (g_str_has_prefix (group, guid_prefixes[i])) { gsize len = strlen (guid_prefixes[i]); - if (as_utils_guid_is_valid (group + len)) + if (fu_common_guid_is_valid (group + len)) return g_strdup (group + len); - return as_utils_guid_from_string (group + len); + return fu_common_guid_from_string (group + len); } } diff --git a/src/fu-self-test.c b/src/fu-self-test.c index 4f359614e..b779f2350 100644 --- a/src/fu-self-test.c +++ b/src/fu-self-test.c @@ -16,6 +16,7 @@ #include #include "fu-common-cab.h" +#include "fu-common-guid.h" #include "fu-chunk.h" #include "fu-config.h" #include "fu-device-list.h" @@ -2838,6 +2839,29 @@ fu_common_strstrip_func (void) } } +static void +fu_common_guid_func (void) +{ + g_autofree gchar *guid1 = NULL; + g_autofree gchar *guid2 = NULL; + + /* invalid */ + g_assert (!fu_common_guid_is_valid (NULL)); + g_assert (!fu_common_guid_is_valid ("")); + g_assert (!fu_common_guid_is_valid ("1ff60ab2-3905-06a1-b476")); + g_assert (!fu_common_guid_is_valid ("1ff60ab2-XXXX-XXXX-XXXX-0371f00c9e9b")); + g_assert (!fu_common_guid_is_valid (" 1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + + /* valid */ + g_assert (fu_common_guid_is_valid ("1ff60ab2-3905-06a1-b476-0371f00c9e9b")); + + /* make valid */ + guid1 = fu_common_guid_from_string ("python.org"); + g_assert_cmpstr (guid1, ==, "886313e1-3b8a-5372-9b90-0c9aee199e5d"); + guid2 = fu_common_guid_from_string ("8086:0406"); + g_assert_cmpstr (guid2, ==, "1fbd1f2c-80f4-5d7c-a6ad-35c7b9bd5486"); +} + int main (int argc, char **argv) { @@ -2899,6 +2923,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func); g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func); g_test_add_func ("/fwupd/chunk", fu_chunk_func); + g_test_add_func ("/fwupd/common{guid}", fu_common_guid_func); g_test_add_func ("/fwupd/common{strstrip}", fu_common_strstrip_func); g_test_add_func ("/fwupd/common{endian}", fu_common_endian_func); g_test_add_func ("/fwupd/common{cab-success}", fu_common_store_cab_func); diff --git a/src/meson.build b/src/meson.build index 61a1db6c4..b5bedb0d4 100644 --- a/src/meson.build +++ b/src/meson.build @@ -26,6 +26,7 @@ libfwupdprivate = static_library( 'fwupdprivate', sources : [ 'fu-common.c', + 'fu-common-guid.c', 'fu-chunk.c', 'fu-device.c', 'fu-device-locker.c', @@ -53,6 +54,7 @@ libfwupdprivate = static_library( sqlite, libarchive, valgrind, + uuid, ], c_args : [ '-DFU_OFFLINE_DESTDIR=""', @@ -108,6 +110,7 @@ fwupdtool = executable( 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -145,6 +148,7 @@ fwupdtool = executable( sqlite, valgrind, libarchive, + uuid, ], link_with : [ fwupd, @@ -184,6 +188,7 @@ executable( 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', 'fu-config.c', 'fu-keyring.c', 'fu-keyring-result.c', @@ -223,6 +228,7 @@ executable( sqlite, valgrind, libarchive, + uuid, ], link_with : fwupd, c_args : [ @@ -251,6 +257,7 @@ if get_option('tests') 'fu-chunk.c', 'fu-common.c', 'fu-common-cab.c', + 'fu-common-guid.c', 'fu-config.c', 'fu-engine.c', 'fu-keyring.c', @@ -289,6 +296,7 @@ if get_option('tests') sqlite, valgrind, libarchive, + uuid, ], link_with : [ fwupd, @@ -312,6 +320,8 @@ if get_option('introspection') 'fu-chunk.c', 'fu-chunk.h', 'fu-common.c', + 'fu-common-guid.c', + 'fu-common-guid.h', 'fu-common.h', 'fu-device.c', 'fu-device.h',