summary refs log tree commit diff
path: root/libnm-core
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-02-26 19:01:41 +0100
committerMichael Biebl <biebl@debian.org>2019-02-26 19:01:41 +0100
commit964ae8cc391520440cf5aa13e2b9cc34850ea6c2 (patch)
tree50da9ecaee7fbb612ec18f9e24f7dec215bf7861 /libnm-core
parent3626b425d1bc017fdc6f1ea0cfd329d1e1681641 (diff)
New upstream version 1.14.6 upstream/1.14.6
Diffstat (limited to 'libnm-core')
-rw-r--r--libnm-core/nm-connection.c24
-rw-r--r--libnm-core/nm-connection.h2
-rw-r--r--libnm-core/nm-core-internal.h60
-rw-r--r--libnm-core/nm-crypto.c15
-rw-r--r--libnm-core/nm-keyfile.c2
-rw-r--r--libnm-core/nm-setting-bridge-port.c11
-rw-r--r--libnm-core/nm-setting-connection.c4
-rw-r--r--libnm-core/nm-setting-ip4-config.c11
-rw-r--r--libnm-core/nm-setting-ip6-config.c3
-rw-r--r--libnm-core/nm-setting-macsec.c30
-rw-r--r--libnm-core/nm-setting-sriov.c12
-rw-r--r--libnm-core/nm-setting.c14
-rw-r--r--libnm-core/nm-utils.c369
-rw-r--r--libnm-core/tests/test-general.c206
14 files changed, 597 insertions, 166 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 172f9c99..5f406cc6 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -1125,6 +1125,29 @@ _normalize_wireless_mac_address_randomization (NMConnection *self, GHashTable *p
 }
 
 static gboolean
+_normalize_macsec (NMConnection *self, GHashTable *parameters)
+{
+	NMSettingMacsec *s_macsec = nm_connection_get_setting_macsec (self);
+	gboolean changed = FALSE;
+
+	if (!s_macsec)
+		return FALSE;
+
+	if (nm_setting_macsec_get_mode (s_macsec) != NM_SETTING_MACSEC_MODE_PSK) {
+		if (nm_setting_macsec_get_mka_cak (s_macsec)) {
+			g_object_set (s_macsec, NM_SETTING_MACSEC_MKA_CAK, NULL, NULL);
+			changed = TRUE;
+		}
+		if (nm_setting_macsec_get_mka_ckn (s_macsec)) {
+			g_object_set (s_macsec, NM_SETTING_MACSEC_MKA_CKN, NULL, NULL);
+			changed = TRUE;
+		}
+	}
+
+	return changed;
+}
+
+static gboolean
 _normalize_team_config (NMConnection *self, GHashTable *parameters)
 {
 	NMSettingTeam *s_team = nm_connection_get_setting_team (self);
@@ -1564,6 +1587,7 @@ nm_connection_normalize (NMConnection *connection,
 	was_modified |= _normalize_bond_mode (connection, parameters);
 	was_modified |= _normalize_bond_options (connection, parameters);
 	was_modified |= _normalize_wireless_mac_address_randomization (connection, parameters);
+	was_modified |= _normalize_macsec (connection, parameters);
 	was_modified |= _normalize_team_config (connection, parameters);
 	was_modified |= _normalize_team_port_config (connection, parameters);
 	was_modified |= _normalize_bluetooth_type (connection, parameters);
diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h
index 802f68ba..b6e00977 100644
--- a/libnm-core/nm-connection.h
+++ b/libnm-core/nm-connection.h
@@ -121,6 +121,8 @@ typedef enum { /*< flags >*/
 	NM_CONNECTION_SERIALIZE_ALL = 0x00000000,
 	NM_CONNECTION_SERIALIZE_NO_SECRETS = 0x00000001,
 	NM_CONNECTION_SERIALIZE_ONLY_SECRETS = 0x00000002,
+
+	/* 0x80000000 is used for a private flag */
 } NMConnectionSerializationFlags;
 
 GVariant     *nm_connection_to_dbus       (NMConnection *connection,
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index f0d4e40f..9d2d0f2c 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -101,6 +101,11 @@
 #define NM_BR_MIN_AGEING_TIME   0
 #define NM_BR_MAX_AGEING_TIME   1000000
 
+#define NM_BR_PORT_MAX_PRIORITY 63
+#define NM_BR_PORT_DEF_PRIORITY 32
+
+#define NM_BR_PORT_MAX_PATH_COST 65535
+
 /* NM_SETTING_COMPARE_FLAG_INFERRABLE: check whether a device-generated
  * connection can be replaced by a already-defined connection. This flag only
  * takes into account properties marked with the %NM_SETTING_PARAM_INFERRABLE
@@ -174,6 +179,13 @@ NMSettingPriority _nm_setting_get_setting_priority (NMSetting *setting);
 
 gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value);
 
+/* NM_CONNECTION_SERIALIZE_NO_SYNTH: This flag is passed to _nm_setting_to_dbus()
+ * by nm_setting_to_string() to let it know that it shouldn't serialize the
+ * synthetic properties. It wouldn't be able to do so, since the full connection
+ * is not available, only the setting alone.
+ */
+#define NM_CONNECTION_SERIALIZE_NO_SYNTH ((NMConnectionSerializationFlags) 0x80000000)
+
 /*****************************************************************************/
 
 GHashTable *_nm_setting_gendata_hash (NMSetting *setting,
@@ -212,15 +224,26 @@ guint nm_setting_ethtool_init_features (NMSettingEthtool *setting,
 guint8 *_nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize buffer_length, gsize *out_length);
 const char *nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboolean upper_case, char *buf, gsize buf_len);
 
-char *_nm_utils_bin2str (gconstpointer addr, gsize length, gboolean upper_case);
-void _nm_utils_bin2str_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out);
+char *_nm_utils_bin2hexstr_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out);
+
+guint8 *_nm_utils_hexstr2bin_full (const char *hexstr,
+                                   gboolean allow_0x_prefix,
+                                   gboolean delimiter_required,
+                                   const char *delimiter_candidates,
+                                   gsize required_len,
+                                   guint8 *buffer,
+                                   gsize buffer_len,
+                                   gsize *out_len);
+
+#define _nm_utils_hexstr2bin_buf(hexstr, allow_0x_prefix, delimiter_required, delimiter_candidates, buffer) \
+    _nm_utils_hexstr2bin_full ((hexstr), (allow_0x_prefix), (delimiter_required), (delimiter_candidates), G_N_ELEMENTS (buffer), (buffer), G_N_ELEMENTS (buffer), NULL)
 
-guint8 *_nm_utils_str2bin_full (const char *asc,
-                                gboolean delimiter_required,
-                                const char *delimiter_candidates,
-                                guint8 *buffer,
-                                gsize buffer_length,
-                                gsize *out_len);
+guint8 *_nm_utils_hexstr2bin_alloc (const char *hexstr,
+                                    gboolean allow_0x_prefix,
+                                    gboolean delimiter_required,
+                                    const char *delimiter_candidates,
+                                    gsize required_len,
+                                    gsize *out_len);
 
 GSList *    _nm_utils_hash_values_to_slist (GHashTable *hash);
 
@@ -234,7 +257,7 @@ gboolean _nm_ip_route_attribute_validate_all (const NMIPRoute *route);
 const char **_nm_ip_route_get_attribute_names (const NMIPRoute *route, gboolean sorted, guint *out_length);
 GHashTable *_nm_ip_route_get_attributes_direct (NMIPRoute *route);
 
-NMSriovVF *_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError **error);
+NMSriovVF *_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, gboolean ignore_unknown, GError **error);
 gboolean _nm_sriov_vf_attribute_validate_all (const NMSriovVF *vf, GError **error);
 
 static inline void
@@ -272,8 +295,25 @@ gboolean _nm_utils_check_module_file (const char *name,
                                       gpointer user_data,
                                       GError **error);
 
+/*****************************************************************************/
+
+typedef struct _NMUuid {
+	guchar uuid[16];
+} NMUuid;
+
+NMUuid *_nm_utils_uuid_parse (const char *str,
+                              NMUuid *uuid);
+char *_nm_utils_uuid_unparse (const NMUuid *uuid,
+                              char *out_str /*[37]*/);
+NMUuid *_nm_utils_uuid_generate_random (NMUuid *out_uuid);
+
+gboolean nm_utils_uuid_is_null (const NMUuid *uuid);
+
 #define NM_UTILS_UUID_TYPE_LEGACY            0
-#define NM_UTILS_UUID_TYPE_VARIANT3          1
+#define NM_UTILS_UUID_TYPE_VERSION3          3
+#define NM_UTILS_UUID_TYPE_VERSION5          5
+
+NMUuid *nm_utils_uuid_generate_from_string_bin (NMUuid *uuid, const char *s, gssize slen, int uuid_type, gpointer type_args);
 
 char *nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args);
 
diff --git a/libnm-core/nm-crypto.c b/libnm-core/nm-crypto.c
index dc8f1c15..1af2ea28 100644
--- a/libnm-core/nm-crypto.c
+++ b/libnm-core/nm-crypto.c
@@ -879,13 +879,10 @@ nm_crypto_md5_hash (const guint8 *salt,
                     gsize buflen)
 {
 	nm_auto_free_checksum GChecksum *ctx = NULL;
-#define MD5_DIGEST_LEN 16
-	nm_auto_clear_static_secret_ptr const NMSecretPtr digest = NM_SECRET_PTR_STATIC (MD5_DIGEST_LEN);
+	nm_auto_clear_static_secret_ptr const NMSecretPtr digest = NM_SECRET_PTR_STATIC (NM_UTILS_CHECKSUM_LENGTH_MD5);
 	gsize bufidx = 0;
 	int i;
 
-	nm_assert (g_checksum_type_get_length (G_CHECKSUM_MD5) == MD5_DIGEST_LEN);
-
 	g_return_if_fail (password_len == 0 || password);
 	g_return_if_fail (buffer);
 	g_return_if_fail (buflen > 0);
@@ -894,25 +891,21 @@ nm_crypto_md5_hash (const guint8 *salt,
 	ctx = g_checksum_new (G_CHECKSUM_MD5);
 
 	for (;;) {
-		gsize digest_len;
-
 		if (password_len > 0)
 			g_checksum_update (ctx, (const guchar *) password, password_len);
 		if (salt_len > 0)
 			g_checksum_update (ctx, (const guchar *) salt, salt_len);
 
-		digest_len = MD5_DIGEST_LEN;
-		g_checksum_get_digest (ctx, digest.bin, &digest_len);
-		nm_assert (digest_len == MD5_DIGEST_LEN);
+		nm_utils_checksum_get_digest_len (ctx, digest.bin, NM_UTILS_CHECKSUM_LENGTH_MD5);
 
-		for (i = 0; i < MD5_DIGEST_LEN; i++) {
+		for (i = 0; i < NM_UTILS_CHECKSUM_LENGTH_MD5; i++) {
 			if (bufidx >= buflen)
 				return;
 			buffer[bufidx++] = digest.bin[i];
 		}
 
 		g_checksum_reset (ctx);
-		g_checksum_update (ctx, digest.ptr, MD5_DIGEST_LEN);
+		g_checksum_update (ctx, digest.ptr, NM_UTILS_CHECKSUM_LENGTH_MD5);
 	}
 }
 
diff --git a/libnm-core/nm-keyfile.c b/libnm-core/nm-keyfile.c
index e4ed1899..5aa8a4ac 100644
--- a/libnm-core/nm-keyfile.c
+++ b/libnm-core/nm-keyfile.c
@@ -152,7 +152,7 @@ sriov_vfs_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
 		                                         keys[i],
 		                                         NULL);
 
-		vf = _nm_utils_sriov_vf_from_strparts (rest, value, NULL);
+		vf = _nm_utils_sriov_vf_from_strparts (rest, value, TRUE, NULL);
 		if (vf)
 			g_ptr_array_add (vfs, vf);
 	}
diff --git a/libnm-core/nm-setting-bridge-port.c b/libnm-core/nm-setting-bridge-port.c
index 4104f8c5..bc9c3e6f 100644
--- a/libnm-core/nm-setting-bridge-port.c
+++ b/libnm-core/nm-setting-bridge-port.c
@@ -104,12 +104,6 @@ nm_setting_bridge_port_get_hairpin_mode (NMSettingBridgePort *setting)
 
 /*****************************************************************************/
 
-#define BR_MAX_PORT_PRIORITY 63
-#define BR_DEF_PRIORITY      32
-
-#define BR_MIN_PATH_COST     1
-#define BR_MAX_PATH_COST     65535
-
 static gboolean
 verify (NMSetting *setting, NMConnection *connection, GError **error)
 {
@@ -238,7 +232,7 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
 	g_object_class_install_property
 		(object_class, PROP_PRIORITY,
 		 g_param_spec_uint (NM_SETTING_BRIDGE_PORT_PRIORITY, "", "",
-		                    0, BR_MAX_PORT_PRIORITY, BR_DEF_PRIORITY,
+		                    0, NM_BR_PORT_MAX_PRIORITY, NM_BR_PORT_DEF_PRIORITY,
 		                    G_PARAM_READWRITE |
 		                    G_PARAM_CONSTRUCT |
 		                    NM_SETTING_PARAM_INFERRABLE |
@@ -261,10 +255,9 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
 	g_object_class_install_property
 		(object_class, PROP_PATH_COST,
 		 g_param_spec_uint (NM_SETTING_BRIDGE_PORT_PATH_COST, "", "",
-		                    0, BR_MAX_PATH_COST, 100,
+		                    0, NM_BR_PORT_MAX_PATH_COST, 100,
 		                    G_PARAM_READWRITE |
 		                    G_PARAM_CONSTRUCT |
-		                    NM_SETTING_PARAM_INFERRABLE |
 		                    G_PARAM_STATIC_STRINGS));
 
 	/**
diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c
index 50240bc9..44021b9c 100644
--- a/libnm-core/nm-setting-connection.c
+++ b/libnm-core/nm-setting-connection.c
@@ -1626,11 +1626,11 @@ nm_setting_connection_class_init (NMSettingConnectionClass *klass)
 	 * name is included, so that different interfaces yield different addresses.
 	 *
 	 * The '$' character is treated special to perform dynamic substitutions
-	 * at runtime. Currently supported are "${CONNECTION}", "${DEVICE}",
+	 * at runtime. Currently supported are "${CONNECTION}", "${DEVICE}", "${MAC}",
 	 * "${BOOT}", "${RANDOM}".
 	 * These effectively create unique IDs per-connection, per-device, per-boot,
 	 * or every time. Note that "${DEVICE}" corresponds the the interface name of the
-	 * device.
+	 * device and "${MAC}" is the permanent MAC address of the device.
 	 * Any unrecognized patterns following '$' are treated verbatim, however
 	 * are reserved for future use. You are thus advised to avoid '$' or
 	 * escape it as "$$".
diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c
index 19f1cc8d..36765484 100644
--- a/libnm-core/nm-setting-ip4-config.c
+++ b/libnm-core/nm-setting-ip4-config.c
@@ -721,11 +721,16 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *klass)
 	 * with type ethernet (01). Currently, these options only work for ethernet
 	 * type of links.
 	 *
+	 * The special value "duid" generates a RFC4361-compliant client identifier based
+	 * on a hash of the interface name as IAID and /etc/machine-id.
+	 *
 	 * The special value "stable" is supported to generate a type 0 client identifier based
-	 * on the stable-id (see connection.stable-id) and a per-host key.
+	 * on the stable-id (see connection.stable-id) and a per-host key. If you set the
+	 * stable-id, you may want to include the "${DEVICE}" or "${MAC}" specifier to get a
+	 * per-device key.
 	 *
-	 * If unset, a globally configured default is used. If still unset, the
-	 * client-id from the last lease is reused.
+	 * If unset, a globally configured default is used. If still unset, the default
+	 * depends on the DHCP plugin.
 	 **/
 	/* ---ifcfg-rh---
 	 * property: dhcp-client-id
diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c
index a55fd801..fa65be91 100644
--- a/libnm-core/nm-setting-ip6-config.c
+++ b/libnm-core/nm-setting-ip6-config.c
@@ -852,7 +852,8 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *klass)
 	 *
 	 * The special values "stable-llt", "stable-ll" and "stable-uuid" will generate
 	 * a DUID of the corresponding type, derived from the connection's stable-id and
-	 * a per-host unique key.
+	 * a per-host unique key. You may want to include the "${DEVICE}" or "${MAC}" specifier
+	 * in the stable-id, in case this profile gets activated on multiple devices.
 	 * So, the link-layer address of "stable-ll" and "stable-llt" will be a generated
 	 * address derived from the stable id. The DUID-LLT time value in the "stable-llt"
 	 * option will be picked among a static timespan of three years (the upper bound
diff --git a/libnm-core/nm-setting-macsec.c b/libnm-core/nm-setting-macsec.c
index 2c7cff23..5c468221 100644
--- a/libnm-core/nm-setting-macsec.c
+++ b/libnm-core/nm-setting-macsec.c
@@ -243,6 +243,12 @@ verify_macsec_key (const char *key, gboolean cak, GError **error)
 {
 	int req_len;
 
+	/* CAK is a connection secret and can be NULL for various
+	 * reasons (agent-owned, no permissions to get secrets, etc.)
+	 */
+	if (cak && !key)
+		return TRUE;
+
 	if (!key || !key[0]) {
 		g_set_error_literal (error,
 		                     NM_CONNECTION_ERROR,
@@ -254,7 +260,7 @@ verify_macsec_key (const char *key, gboolean cak, GError **error)
 	req_len = cak ?
 	    NM_SETTING_MACSEC_MKA_CAK_LENGTH :
 	    NM_SETTING_MACSEC_MKA_CKN_LENGTH;
-	if (strlen (key) != req_len) {
+	if (strlen (key) != (gsize) req_len) {
 		g_set_error (error,
 		             NM_CONNECTION_ERROR,
 		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
@@ -340,6 +346,10 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 			g_prefix_error (error, "%s.%s: ", NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MKA_CKN);
 			return FALSE;
 		}
+		if (!verify_macsec_key (priv->mka_cak, TRUE, error)) {
+			g_prefix_error (error, "%s.%s: ", NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MKA_CAK);
+			return FALSE;
+		}
 	} else if (priv->mode == NM_SETTING_MACSEC_MODE_EAP) {
 		if (!s_8021x) {
 			g_set_error (error,
@@ -350,6 +360,13 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 			g_prefix_error (error, "%s: ", NM_SETTING_MACSEC_SETTING_NAME);
 			return FALSE;
 		}
+	} else {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("must be either psk (0) or eap (1)"));
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_MACSEC_SETTING_NAME, NM_SETTING_MACSEC_MODE);
+		return FALSE;
 	}
 
 	if (priv->port <= 0 || priv->port > 65534) {
@@ -362,6 +379,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
 		return FALSE;
 	}
 
+	if (   priv->mode != NM_SETTING_MACSEC_MODE_PSK
+	    && (priv->mka_cak || priv->mka_ckn)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("only valid for psk mode"));
+		g_prefix_error (error, "%s.%s: ", NM_SETTING_MACSEC_SETTING_NAME,
+		                priv->mka_cak ? NM_SETTING_MACSEC_MKA_CAK : NM_SETTING_MACSEC_MKA_CKN);
+		return NM_SETTING_VERIFY_NORMALIZABLE;
+	}
+
 	return TRUE;
 }
 
diff --git a/libnm-core/nm-setting-sriov.c b/libnm-core/nm-setting-sriov.c
index 7228fb0c..0addd972 100644
--- a/libnm-core/nm-setting-sriov.c
+++ b/libnm-core/nm-setting-sriov.c
@@ -1248,6 +1248,11 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 *
 	 * The total number of virtual functions to create.
 	 *
+	 * Note that when the sriov setting is present NetworkManager
+	 * enforces the number of virtual functions on the interface
+	 * also when it is zero. To prevent any changes to SR-IOV
+	 * parameters don't add a sriov setting to the connection.
+	 *
 	 * Since: 1.14
 	 **/
 	/* ---ifcfg-rh---
@@ -1283,7 +1288,11 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 *
 	 *   "2 mac=00:11:22:33:44:55 spoof-check=true".
 	 *
-	 * The "vlans" attribute is represented as a semicolor-separated
+	 * Multiple VFs can be specified using a comma as separator.
+	 * Currently the following attributes are supported: mac,
+	 * spoof-check, trust, min-tx-rate, max-tx-rate, vlans.
+	 *
+	 * The "vlans" attribute is represented as a semicolon-separated
 	 * list of VLAN descriptors, where each descriptor has the form
 	 *
 	 *   "ID[.PRIORITY[.PROTO]]".
@@ -1291,6 +1300,7 @@ nm_setting_sriov_class_init (NMSettingSriovClass *klass)
 	 * PROTO can be either 'q' for 802.1Q (the default) or 'ad' for
 	 * 802.1ad.
 	 *
+
 	 * Since: 1.14
 	 **/
 	/* ---ifcfg-rh---
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c
index 6b9681b5..047391ce 100644
--- a/libnm-core/nm-setting.c
+++ b/libnm-core/nm-setting.c
@@ -685,10 +685,15 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
 				continue;
 		}
 
-		if (property->synth_func)
-			dbus_value = property->synth_func (setting, connection, property->name);
-		else
+		if (property->synth_func) {
+			if (!(flags & NM_CONNECTION_SERIALIZE_NO_SYNTH))
+				dbus_value = property->synth_func (setting, connection, property->name);
+			else
+				dbus_value = NULL;
+		} else {
 			dbus_value = get_property_for_dbus (setting, property, TRUE);
+		}
+
 		if (dbus_value) {
 			/* Allow dbus_value to be either floating or not. */
 			g_variant_take_ref (dbus_value);
@@ -2013,7 +2018,8 @@ nm_setting_to_string (NMSetting *setting)
 	string = g_string_new (nm_setting_get_name (setting));
 	g_string_append_c (string, '\n');
 
-	variant = _nm_setting_to_dbus (setting, NULL, NM_CONNECTION_SERIALIZE_ALL);
+	variant = _nm_setting_to_dbus (setting, NULL,   NM_CONNECTION_SERIALIZE_ALL
+	                                              | NM_CONNECTION_SERIALIZE_NO_SYNTH);
 
 	g_variant_iter_init (&iter, variant);
 	while ((child = g_variant_iter_next_value (&iter))) {
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 0f524e11..f75276c7 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -2737,11 +2737,14 @@ nm_utils_sriov_vf_from_str (const char *str, GError **error)
 		detail++;
 	}
 
-	return _nm_utils_sriov_vf_from_strparts (str, detail, error);
+	return _nm_utils_sriov_vf_from_strparts (str, detail, FALSE, error);
 }
 
 NMSriovVF *
-_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError **error)
+_nm_utils_sriov_vf_from_strparts (const char *index,
+                                  const char *detail,
+                                  gboolean ignore_unknown,
+                                  GError **error)
 {
 	NMSriovVF *vf;
 	guint32 n_index;
@@ -2761,7 +2764,12 @@ _nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError
 
 	vf = nm_sriov_vf_new (n_index);
 	if (detail) {
-		ht = nm_utils_parse_variant_attributes (detail, ' ', '=', TRUE, _nm_sriov_vf_attribute_spec, error);
+		ht = nm_utils_parse_variant_attributes (detail,
+		                                        ' ',
+		                                        '=',
+		                                        ignore_unknown,
+		                                        _nm_sriov_vf_attribute_spec,
+		                                        error);
 		if (!ht) {
 			nm_sriov_vf_unref (vf);
 			return NULL;
@@ -2785,6 +2793,57 @@ _nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError
 
 /*****************************************************************************/
 
+NMUuid *
+_nm_utils_uuid_parse (const char *str,
+                      NMUuid *out_uuid)
+{
+	nm_assert (str);
+	nm_assert (out_uuid);
+
+	if (uuid_parse (str, out_uuid->uuid) != 0)
+		return NULL;
+	return out_uuid;
+}
+
+char *
+_nm_utils_uuid_unparse (const NMUuid *uuid,
+                        char *out_str /*[37]*/)
+{
+	nm_assert (uuid);
+
+	if (!out_str) {
+		/* for convenience, allow %NULL to indicate that a new
+		 * string should be allocated. */
+		out_str = g_malloc (37);
+	}
+	uuid_unparse_lower (uuid->uuid, out_str);
+	return out_str;
+}
+
+NMUuid *
+_nm_utils_uuid_generate_random (NMUuid *out_uuid)
+{
+	nm_assert (out_uuid);
+
+	uuid_generate_random (out_uuid->uuid);
+	return out_uuid;
+}
+
+gboolean
+nm_utils_uuid_is_null (const NMUuid *uuid)
+{
+	int i;
+
+	if (!uuid)
+		return TRUE;
+
+	for (i = 0; i < G_N_ELEMENTS (uuid->uuid); i++) {
+		if (uuid->uuid[i])
+			return FALSE;
+	}
+	return TRUE;
+}
+
 /**
  * nm_utils_uuid_generate_buf_:
  * @buf: input buffer, must contain at least 37 bytes
@@ -2794,11 +2853,12 @@ _nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, GError
 char *
 nm_utils_uuid_generate_buf_ (char *buf)
 {
-	uuid_t uuid;
+	NMUuid uuid;
+
+	nm_assert (buf);
 
-	uuid_generate_random (uuid);
-	uuid_unparse_lower (uuid, buf);
-	return buf;
+	_nm_utils_uuid_generate_random (&uuid);
+	return _nm_utils_uuid_unparse (&uuid, buf);
 }
 
 /**
@@ -2814,7 +2874,9 @@ nm_utils_uuid_generate (void)
 }
 
 /**
- * nm_utils_uuid_generate_from_string:
+ * nm_utils_uuid_generate_from_string_bin:
+ * @uuid: the UUID to update inplace. This function cannot
+ *   fail to succeed.
  * @s: a string to use as the seed for the UUID
  * @slen: if negative, treat @s as zero terminated C string.
  *   Otherwise, assume the length as given (and allow @s to be
@@ -2824,60 +2886,92 @@ nm_utils_uuid_generate (void)
  *
  * For a given @s, this function will always return the same UUID.
  *
- * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
- * object's #NMSettingConnection:id: property
+ * Returns: the input @uuid. This function cannot fail.
  **/
-char *
-nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args)
+NMUuid *
+nm_utils_uuid_generate_from_string_bin (NMUuid *uuid, const char *s, gssize slen, int uuid_type, gpointer type_args)
 {
-	uuid_t uuid;
-	char *buf;
-
+	g_return_val_if_fail (uuid, FALSE);
 	g_return_val_if_fail (slen == 0 || s, FALSE);
 
-	g_return_val_if_fail (uuid_type == NM_UTILS_UUID_TYPE_LEGACY || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
-	g_return_val_if_fail (!type_args || uuid_type == NM_UTILS_UUID_TYPE_VARIANT3, NULL);
-
 	if (slen < 0)
 		slen = s ? strlen (s) : 0;
 
 	switch (uuid_type) {
 	case NM_UTILS_UUID_TYPE_LEGACY:
+		g_return_val_if_fail (!type_args, NULL);
 		nm_crypto_md5_hash (NULL,
 		                    0,
 		                    (guint8 *) s,
 		                    slen,
 		                    (guint8 *) uuid,
-		                    sizeof (uuid));
+		                    sizeof (*uuid));
 		break;
-	case NM_UTILS_UUID_TYPE_VARIANT3: {
-		uuid_t ns_uuid = { 0 };
+	case NM_UTILS_UUID_TYPE_VERSION3:
+	case NM_UTILS_UUID_TYPE_VERSION5: {
+		NMUuid ns_uuid = { 0 };
 
 		if (type_args) {
 			/* type_args can be a name space UUID. Interpret it as (char *) */
-			if (uuid_parse ((char *) type_args, ns_uuid) != 0)
+			if (!_nm_utils_uuid_parse (type_args, &ns_uuid))
 				g_return_val_if_reached (NULL);
 		}
 
-		nm_crypto_md5_hash ((guint8 *) s,
-		                    slen,
-		                    (guint8 *) ns_uuid,
-		                    sizeof (ns_uuid),
-		                    (guint8 *) uuid,
-		                    sizeof (uuid));
+		if (uuid_type == NM_UTILS_UUID_TYPE_VERSION3) {
+			nm_crypto_md5_hash ((guint8 *) s,
+			                    slen,
+			                    (guint8 *) &ns_uuid,
+			                    sizeof (ns_uuid),
+			                    (guint8 *) uuid,
+			                    sizeof (*uuid));
+		} else {
+			nm_auto_free_checksum GChecksum *sum = NULL;
+			union {
+				guint8 sha1[NM_UTILS_CHECKSUM_LENGTH_SHA1];
+				NMUuid uuid;
+			} digest;
+
+			sum = g_checksum_new (G_CHECKSUM_SHA1);
+			g_checksum_update (sum, (guchar *) &ns_uuid, sizeof (ns_uuid));
+			g_checksum_update (sum, (guchar *) s, slen);
+			nm_utils_checksum_get_digest (sum, digest.sha1);
+
+			G_STATIC_ASSERT_EXPR (sizeof (digest.sha1) > sizeof (digest.uuid));
+			*uuid = digest.uuid;
+		}
 
-		uuid[6] = (uuid[6] & 0x0F) | 0x30;
-		uuid[8] = (uuid[8] & 0x3F) | 0x80;
+		uuid->uuid[6] = (uuid->uuid[6] & 0x0F) | (uuid_type << 4);
+		uuid->uuid[8] = (uuid->uuid[8] & 0x3F) | 0x80;
 		break;
 	}
 	default:
 		g_return_val_if_reached (NULL);
 	}
 
-	buf = g_malloc (37);
-	uuid_unparse_lower (uuid, &buf[0]);
+	return uuid;
+}
 
-	return buf;
+/**
+ * nm_utils_uuid_generate_from_string:
+ * @s: a string to use as the seed for the UUID
+ * @slen: if negative, treat @s as zero terminated C string.
+ *   Otherwise, assume the length as given (and allow @s to be
+ *   non-null terminated or contain '\0').
+ * @uuid_type: a type identifier which UUID format to generate.
+ * @type_args: additional arguments, depending on the uuid_type
+ *
+ * For a given @s, this function will always return the same UUID.
+ *
+ * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
+ * object's #NMSettingConnection:id: property
+ **/
+char *
+nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, gpointer type_args)
+{
+	NMUuid uuid;
+
+	nm_utils_uuid_generate_from_string_bin (&uuid, s, slen, uuid_type, type_args);
+	return _nm_utils_uuid_unparse (&uuid, NULL);
 }
 
 /**
@@ -2902,7 +2996,7 @@ _nm_utils_uuid_generate_from_strings (const char *string1, ...)
 	char *uuid;
 
 	if (!string1)
-		return nm_utils_uuid_generate_from_string (NULL, 0, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
+		return nm_utils_uuid_generate_from_string (NULL, 0, NM_UTILS_UUID_TYPE_VERSION3, NM_UTILS_UUID_NS);
 
 	str = g_string_sized_new (120); /* effectively allocates power of 2 (128)*/
 
@@ -2916,7 +3010,7 @@ _nm_utils_uuid_generate_from_strings (const char *string1, ...)
 	}
 	va_end (args);
 
-	uuid = nm_utils_uuid_generate_from_string (str->str, str->len, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
+	uuid = nm_utils_uuid_generate_from_string (str->str, str->len, NM_UTILS_UUID_TYPE_VERSION3, NM_UTILS_UUID_NS);
 
 	g_string_free (str, TRUE);
 	return uuid;
@@ -3527,60 +3621,68 @@ nm_utils_hwaddr_len (int type)
 }
 
 guint8 *
-_nm_utils_str2bin_full (const char *asc,
-                        gboolean delimiter_required,
-                        const char *delimiter_candidates,
-                        guint8 *buffer,
-                        gsize buffer_length,
-                        gsize *out_len)
-{
-	const char *in = asc;
+_nm_utils_hexstr2bin_full (const char *hexstr,
+                           gboolean allow_0x_prefix,
+                           gboolean delimiter_required,
+                           const char *delimiter_candidates,
+                           gsize required_len,
+                           guint8 *buffer,
+                           gsize buffer_len,
+                           gsize *out_len)
+{
+	const char *in = hexstr;
 	guint8 *out = buffer;
 	gboolean delimiter_has = TRUE;
 	guint8 delimiter = '\0';
+	gsize len;
 
-	nm_assert (asc);
+	nm_assert (hexstr);
 	nm_assert (buffer);
-	nm_assert (buffer_length);
-	nm_assert (out_len);
+	nm_assert (required_len > 0 || out_len);
+
+	if (   allow_0x_prefix
+	    && in[0] == '0'
+	    && in[1] == 'x')
+		in += 2;
 
 	while (TRUE) {
 		const guint8 d1 = in[0];
 		guint8 d2;
+		int i1, i2;
 
-		if (!g_ascii_isxdigit (d1))
-			return NULL;
-
-#define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - ('A' - 10))
+		i1 = nm_utils_hexchar_to_int (d1);
+		if (i1 < 0)
+			goto fail;
 
 		/* If there's no leading zero (ie "aa:b:cc") then fake it */
 		d2 = in[1];
-		if (d2 && g_ascii_isxdigit (d2)) {
-			*out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
+		if (   d2
+		    && (i2 = nm_utils_hexchar_to_int (d2)) >= 0) {
+			*out++ = (i1 << 4) + i2;
 			d2 = in[2];
 			if (!d2)
 				break;
 			in += 2;
 		} else {
 			/* Fake leading zero */
-			*out++ = HEXVAL (d1);
+			*out++ = i1;
 			if (!d2) {
 				if (!delimiter_has) {
 					/* when using no delimiter, there must be pairs of hex chars */
-					return NULL;
+					goto fail;
 				}
 				break;
 			}
 			in += 1;
 		}
 
-		if (--buffer_length == 0)
-			return NULL;
+		if (--buffer_len == 0)
+			goto fail;
 
 		if (delimiter_has) {
 			if (d2 != delimiter) {
 				if (delimiter)
-					return NULL;
+					goto fail;
 				if (delimiter_candidates) {
 					while (delimiter_candidates[0]) {
 						if (delimiter_candidates++[0] == d2)
@@ -3589,7 +3691,7 @@ _nm_utils_str2bin_full (const char *asc,
 				}
 				if (!delimiter) {
 					if (delimiter_required)
-						return NULL;
+						goto fail;
 					delimiter_has = FALSE;
 					continue;
 				}
@@ -3598,11 +3700,66 @@ _nm_utils_str2bin_full (const char *asc,
 		}
 	}
 
-	*out_len = out - buffer;
-	return buffer;
+	len = out - buffer;
+	if (   required_len == 0
+	    || len == required_len) {
+		NM_SET_OUT (out_len, len);
+		return buffer;
+	}
+
+fail:
+	NM_SET_OUT (out_len, 0);
+	return NULL;
 }
 
-#define hwaddr_aton(asc, buffer, buffer_length, out_len) _nm_utils_str2bin_full ((asc), TRUE, ":-", (buffer), (buffer_length), (out_len))
+guint8 *
+_nm_utils_hexstr2bin_alloc (const char *hexstr,
+                            gboolean allow_0x_prefix,
+                            gboolean delimiter_required,
+                            const char *delimiter_candidates,
+                            gsize required_len,
+                            gsize *out_len)
+{
+	guint8 *buffer;
+	gsize buffer_len, len;
+
+	g_return_val_if_fail (hexstr, NULL);
+
+	nm_assert (required_len > 0 || out_len);
+
+	if (   allow_0x_prefix
+	    && hexstr[0] == '0'
+	    && hexstr[1] == 'x')
+		hexstr += 2;
+
+	if (!hexstr[0])
+		goto fail;
+
+	if (required_len > 0)
+		buffer_len = required_len;
+	else
+		buffer_len = strlen (hexstr) / 2 + 3;
+
+	buffer = g_malloc (buffer_len);
+
+	if (_nm_utils_hexstr2bin_full (hexstr,
+	                               FALSE,
+	                               delimiter_required,
+	                               delimiter_candidates,
+	                               required_len,
+	                               buffer,
+	                               buffer_len,
+	                               &len)) {
+		NM_SET_OUT (out_len, len);
+		return buffer;
+	}
+
+	g_free (buffer);
+
+fail:
+	NM_SET_OUT (out_len, 0);
+	return NULL;
+}
 
 /**
  * nm_utils_hexstr2bin:
@@ -3619,23 +3776,17 @@ GBytes *
 nm_utils_hexstr2bin (const char *hex)
 {
 	guint8 *buffer;
-	gsize buffer_length, len;
-
-	g_return_val_if_fail (hex != NULL, NULL);
-
-	if (hex[0] == '0' && hex[1] == 'x')
-		hex += 2;
+	gsize len;
 
-	buffer_length = strlen (hex) / 2 + 3;
-	buffer = g_malloc (buffer_length);
-	if (!_nm_utils_str2bin_full (hex, FALSE, ":", buffer, buffer_length, &len)) {
-		g_free (buffer);
+	buffer = _nm_utils_hexstr2bin_alloc (hex, TRUE, FALSE, ":", 0, &len);
+	if (!buffer)
 		return NULL;
-	}
 	buffer = g_realloc (buffer, len);
 	return g_bytes_new_take (buffer, len);
 }
 
+#define hwaddr_aton(asc, buffer, buffer_len, out_len) _nm_utils_hexstr2bin_full ((asc), FALSE, TRUE, ":-", 0, (buffer), (buffer_len), (out_len))
+
 /**
  * nm_utils_hwaddr_atoba:
  * @asc: the ASCII representation of a hardware address
@@ -3728,16 +3879,46 @@ nm_utils_hwaddr_aton (const char *asc, gpointer buffer, gsize length)
 	return buffer;
 }
 
-void
-_nm_utils_bin2str_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out)
+/**
+ * _nm_utils_bin2hexstr_full:
+ * @addr: pointer of @length bytes.
+ * @length: number of bytes in @addr
+ * @delimiter: either '\0', otherwise the output string will have the
+ *   given delimiter character between each two hex numbers.
+ * @upper_case: if TRUE, use upper case ASCII characters for hex.
+ * @out: if %NULL, the function will allocate a new buffer of
+ *   either (@length*2+1) or (@length*3) bytes, depending on whether
+ *   a @delimiter is specified. In that case, the allocated buffer will
+ *   be returned and must be freed by the caller.
+ *   If not %NULL, the buffer must already be preallocated and contain
+ *   at least (@length*2+1) or (@length*3) bytes, depending on the delimiter.
+ *
+ * Returns: the binary value converted to a hex string. If @out is given,
+ *   this always returns @out. If @out is %NULL, a newly allocated string
+ *   is returned.
+ */
+char *
+_nm_utils_bin2hexstr_full (gconstpointer addr,
+                           gsize length,
+                           char delimiter,
+                           gboolean upper_case,
+                           char *out)
 {
 	const guint8 *in = addr;
 	const char *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
+	char *out0;
 
 	nm_assert (addr);
-	nm_assert (out);
 	nm_assert (length > 0);
 
+	if (out)
+		out0 = out;
+	else {
+		out0 = out = g_new (char, delimiter == '\0'
+		                          ? length * 2 + 1
+		                          : length * 3);
+	}
+
 	/* @out must contain at least @length*3 bytes if @delimiter is set,
 	 * otherwise, @length*2+1. */
 
@@ -3754,6 +3935,7 @@ _nm_utils_bin2str_full (gconstpointer addr, gsize length, const char delimiter,
 	}
 
 	*out = 0;
+	return out0;
 }
 
 /**
@@ -3779,7 +3961,8 @@ nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len)
 	g_return_val_if_fail (final_len < 0 || (gsize) final_len < buflen, NULL);
 
 	result = g_malloc (buflen);
-	_nm_utils_bin2str_full (src, len, '\0', FALSE, result);
+
+	_nm_utils_bin2hexstr_full (src, len, '\0', FALSE, result);
 
 	/* Cut converted key off at the correct length for this cipher type */
 	if (final_len >= 0 && (gsize) final_len < buflen)
@@ -3800,14 +3983,10 @@ nm_utils_bin2hexstr (gconstpointer src, gsize len, int final_len)
 char *
 nm_utils_hwaddr_ntoa (gconstpointer addr, gsize length)
 {
-	char *result;
-
 	g_return_val_if_fail (addr, g_strdup (""));
 	g_return_val_if_fail (length > 0, g_strdup (""));
 
-	result = g_malloc (length * 3);
-	_nm_utils_bin2str_full (addr, length, ':', TRUE, result);
-	return result;
+	return _nm_utils_bin2hexstr_full (addr, length, ':', TRUE, NULL);
 }
 
 const char *
@@ -3819,31 +3998,7 @@ nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboolean upper_cas
 	if (buf_len < addr_len * 3)
 		g_return_val_if_reached (NULL);
 
-	_nm_utils_bin2str_full (addr, addr_len, ':', upper_case, buf);
-	return buf;
-}
-
-/**
- * _nm_utils_bin2str:
- * @addr: (type guint8) (array length=length): a binary hardware address
- * @length: the length of @addr
- * @upper_case: the case for the hexadecimal digits.
- *
- * Converts @addr to textual form.
- *
- * Return value: (transfer full): the textual form of @addr
- */
-char *
-_nm_utils_bin2str (gconstpointer addr, gsize length, gboolean upper_case)
-{
-	char *result;
-
-	g_return_val_if_fail (addr, g_strdup (""));
-	g_return_val_if_fail (length > 0, g_strdup (""));
-
-	result = g_malloc (length * 3);
-	_nm_utils_bin2str_full (addr, length, ':', upper_case, result);
-	return result;
+	return _nm_utils_bin2hexstr_full (addr, addr_len, ':', upper_case, buf);
 }
 
 /**
@@ -4510,7 +4665,7 @@ _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin)
 		return TRUE;
 	}
 
-	if (_nm_utils_str2bin_full (duid, FALSE, ":", duid_arr, sizeof (duid_arr), &duid_len)) {
+	if (_nm_utils_hexstr2bin_full (duid, FALSE, FALSE, ":", 0, duid_arr, sizeof (duid_arr), &duid_len)) {
 		/* MAX DUID length is 128 octects + the type code (2 octects). */
 		if (   duid_len > 2
 		    && duid_len <= (128 + 2)) {
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index 5a954270..67b80098 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -5439,8 +5439,21 @@ test_nm_strquote (void)
 
 /*****************************************************************************/
 
-#define UUID_NIL        "00000000-0000-0000-0000-000000000000"
+#define UUID_NS_ZERO    "00000000-0000-0000-0000-000000000000"
 #define UUID_NS_DNS     "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+#define UUID_NS_URL     "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
+#define UUID_NS_OID     "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
+#define UUID_NS_X500    "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
+
+static const NMUuid *
+_uuid (const char *str)
+{
+	static NMUuid u;
+
+	g_assert (str);
+	g_assert (_nm_utils_uuid_parse (str, &u));
+	return &u;
+}
 
 static void
 _test_uuid (int uuid_type, const char *expected_uuid, const char *str, gssize slen, gpointer type_args)
@@ -5452,9 +5465,17 @@ _test_uuid (int uuid_type, const char *expected_uuid, const char *str, gssize sl
 	g_assert (uuid_test);
 	g_assert (nm_utils_is_uuid (uuid_test));
 
-	if (strcmp (uuid_test, expected_uuid)) {
-		g_error ("UUID test failed: type=%d; text=%s, len=%lld, uuid=%s, expected=%s", uuid_type,
-		         str, (long long) slen, uuid_test, expected_uuid);
+	if (!nm_streq (uuid_test, expected_uuid)) {
+		g_error ("UUID test failed: type=%d; text=%s, len=%lld, ns=%s, uuid=%s, expected=%s",
+		         uuid_type,
+		         str,
+		         (long long) slen,
+		         NM_IN_SET (uuid_type, NM_UTILS_UUID_TYPE_VERSION3,
+		                               NM_UTILS_UUID_TYPE_VERSION5)
+		           ? (((const char *) type_args) ?: "(all-zero)")
+		           : (type_args ? "(unknown)" : "(null)"),
+		         uuid_test,
+		         expected_uuid);
 	}
 
 	if (slen < 0) {
@@ -5465,30 +5486,174 @@ _test_uuid (int uuid_type, const char *expected_uuid, const char *str, gssize sl
 		_test_uuid (uuid_type, expected_uuid, NULL, 0, type_args);
 	}
 
-	if (uuid_type == NM_UTILS_UUID_TYPE_VARIANT3 && !type_args) {
-		/* For NM_UTILS_UUID_TYPE_VARIANT3, a missing @type_args is equal to UUID_NIL */
-		_test_uuid (uuid_type, expected_uuid, str, slen, UUID_NIL);
+	if (   NM_IN_SET (uuid_type, NM_UTILS_UUID_TYPE_VERSION3,
+	                             NM_UTILS_UUID_TYPE_VERSION5)
+	    && !type_args) {
+		/* For version3 and version5, a missing @type_args is equal to UUID_NS_ZERO */
+		_test_uuid (uuid_type, expected_uuid, str, slen, UUID_NS_ZERO);
 	}
 }
 
+typedef struct {
+	const char *uuid3;
+	const char *uuid5;
+} ExpectedUuids;
+
 static void
 test_nm_utils_uuid_generate_from_string (void)
 {
+	const ExpectedUuids zero_uuids[] = {
+	    { .uuid3 = "19826852-5007-3022-a72a-212f66e9fac3", .uuid5 = "b6c54489-38a0-5f50-a60a-fd8d76219cae", },
+	    { .uuid3 = "9153af2e-fc8e-34f3-9e8b-81f73b33d0cb", .uuid5 = "11116e73-1c03-5de6-9130-5f9925ae8ab4", },
+	    { .uuid3 = "2f06a3ae-d78d-30d7-b898-088a0e0b76f6", .uuid5 = "1087ebe8-1ef8-5d97-8873-735b4949004d", },
+	    { .uuid3 = "aca948e0-1468-3a51-9f2e-c688a484efd7", .uuid5 = "7e57d004-2b97-5e7a-b45f-5387367791cd", },
+	    { .uuid3 = "b74e537a-53e8-3808-9abd-58546a6542bd", .uuid5 = "1dd80df1-492c-5dc5-aec2-6bf0e104f923", },
+	    { .uuid3 = "1b00958a-7d76-3d08-8aba-c66c5828658c", .uuid5 = "f797f61e-a392-5acf-af25-b46057f1c8e8", },
+	    { .uuid3 = "7ba18f7d-c9cf-3b48-a89e-ad79243135cc", .uuid5 = "e02c9780-2fc5-5d57-b92f-4cc3a64bff16", },
+	    { .uuid3 = "9baf0978-1a60-35c5-9e9b-bec8d259fd4e", .uuid5 = "94167980-f909-527e-a4af-bc3155f586d3", },
+	    { .uuid3 = "588668c0-7631-39c7-9976-c7d414adf7ba", .uuid5 = "9e3eefda-b56e-56bd-8a3a-0b8009d4a536", },
+	    { .uuid3 = "8edb3613-9612-3b32-9dd7-0a01aa8ed453", .uuid5 = "9b75648e-d38c-54e8-adee-1fb295a079c9", },
+	    { .uuid3 = "f3b34394-63a5-3773-9014-1f8a50d765b8", .uuid5 = "dd56b598-9e74-58c3-b3e8-2c623780b8ed", },
+	    { .uuid3 = "0572965f-05b8-342b-b225-d5c29d449eee", .uuid5 = "5666449a-fb7e-55b7-ae9f-0552e6513a10", },
+	    { .uuid3 = "6f7177c3-77b0-3f42-82a8-7031e25fcccf", .uuid5 = "10b38db9-82fc-528e-9ddb-1f09b7dbf907", },
+	    { .uuid3 = "d1e0f845-bc1b-368c-b8c8-49ab0b9e486b", .uuid5 = "85492596-9468-5845-9c7f-d4ae999cb751", },
+	    { .uuid3 = "46371ea3-c8a3-34d8-b2cf-2fa90bda4378", .uuid5 = "22b1c0dd-aa5d-54a4-8768-5adfd0d112bd", },
+	    { .uuid3 = "f1e6b499-9b68-343b-a5c5-ece7acc49a68", .uuid5 = "9cc429f8-200e-52a3-9e3b-ef134afa1e29", },
+	    { .uuid3 = "9ed06458-c712-31dd-aba5-6cf79879fabe", .uuid5 = "3949f95c-5d76-5ee2-af60-8e2d8fcf649d", },
+	    { .uuid3 = "4ddd5cd7-bc83-36aa-909c-4e660f57c830", .uuid5 = "0e994a02-069b-58fb-b3a4-d7dc94e90fca", },
+	    { .uuid3 = "335fa537-0909-395d-a696-6f41827dcbeb", .uuid5 = "17db3a41-de9b-5c6b-904d-833943209b3c", },
+	    { .uuid3 = "dbd58444-05ad-3edd-adc7-4393ecbcb43c", .uuid5 = "1bd906f2-05f9-5ab5-a39a-4c17a188f886", },
+	    { .uuid3 = "a1c62d82-d13c-361b-8f4e-ca91bc2f7fc5", .uuid5 = "ce6550fd-95b7-57e4-9aa7-461522666be4", },
+	    { .uuid3 = "e943d83e-3f82-307f-81ed-b7a7bcd0743e", .uuid5 = "04aa09ee-b420-57ac-8a23-5d99907fb0a1", },
+	    { .uuid3 = "cabf46dd-9f09-375c-8f6e-f2a8cf114709", .uuid5 = "8ece2c62-0c31-5c55-b7c6-155381e3780e", },
+	    { .uuid3 = "19beddf3-f2fb-340f-96ac-4f394960b7a7", .uuid5 = "5762a9f9-9a21-59ab-b0d2-2cb90027ef7f", },
+	    { .uuid3 = "08d835c2-f4ca-394c-ba7f-2494d8b60c6c", .uuid5 = "23c8409d-4b5f-5b6a-b946-41e49bad6c78", },
+	    { .uuid3 = "3b8c6847-5331-35bf-9cd9-ced50e53cd7c", .uuid5 = "e8e396be-95d5-5569-8edc-e0b64c2b7613", },
+	    { .uuid3 = "e601f160-484b-3254-8f3b-0a25c7203d8a", .uuid5 = "bc8b3cbc-ad5b-5808-a1b0-e0f7a1ad68a3", },
+	    { .uuid3 = "e5e492ed-5349-379d-b7de-a370a51e44a3", .uuid5 = "62c5ed3f-9afa-59ad-874f-a9dd8afc69d4", },
+	    { .uuid3 = "c40111f6-fe97-305e-bfce-7db730c3d2ec", .uuid5 = "66877a72-7243-59ed-b9e3-b5023b6da9c2", },
+	    { .uuid3 = "21e18ea8-95c2-362b-9ca9-25d6a0ff2dff", .uuid5 = "49a49eee-7e86-5d66-837a-8a8810cb5562", },
+	    { .uuid3 = "adab623b-1343-307f-80d8-58d005376ad9", .uuid5 = "e4a2a7ed-3bf3-53cf-a2bb-154dbb39a38c", },
+	    { .uuid3 = "67e9fc7c-dafe-356d-ac1a-a63ce3f44813", .uuid5 = "50cacfc9-f5d2-52dd-897c-a25a0927b816", },
+	    { .uuid3 = "36cc7f20-126c-3e40-94e7-737ac7486547", .uuid5 = "ca629991-3f2b-5e86-9bb7-37a335f7d809", },
+	    { .uuid3 = "fe282996-ac5e-3d13-b478-5def30007a8e", .uuid5 = "c1adf8a7-f72a-58ae-82d5-d18807f12e2e", },
+	    { .uuid3 = "3bfe339c-05ae-3233-a1a5-ebf1ead589db", .uuid5 = "6120c3cd-24e1-5ce4-987b-f8bfee2e4633", },
+	    { .uuid3 = "d1d90bc7-da4a-3cd7-a7c8-a1a89765d8ee", .uuid5 = "433d6a26-c319-5fcf-9a30-5ec6ad59d109", },
+	    { .uuid3 = "10b88a02-0102-359b-81e9-7e3b0ff7d25e", .uuid5 = "77d228d9-1b96-59e2-a07e-a8fdd4f62884", },
+	    { .uuid3 = "7da5e4f2-6df0-3aca-a1b0-b7f8b1340e1d", .uuid5 = "698259bf-a32b-5e00-9ec6-88b12278c4ad", },
+	    { .uuid3 = "cbe24d98-ca20-3058-86b6-24a6b36ceff0", .uuid5 = "60dbca63-704f-5666-9f64-f4e1a630c4aa", },
+	    { .uuid3 = "04d84e6a-b793-3993-afbf-bae7cfc42b49", .uuid5 = "79d63ec0-a39d-557d-8299-f4c97acfadc3", },
+	    { .uuid3 = "fdd157d8-a537-350a-9cc9-1930e8666c63", .uuid5 = "7df7f75e-a146-5a76-828b-bac052db312b", },
+	    { .uuid3 = "0bea36bb-24a7-3ee6-a98d-116433c14cd4", .uuid5 = "2bcca2e9-2879-53e3-b09d-cbbfd58771b2", },
+	    { .uuid3 = "52b040a4-1b84-32d2-b758-f82386f7e0f0", .uuid5 = "cb7bdca3-e9f7-50cd-b72e-73cb9ff24f62", },
+	    { .uuid3 = "0f0a4e26-e034-3021-acf2-4e886af43092", .uuid5 = "8e428e2b-5da3-5368-b760-5ca07ccbd819", },
+	    { .uuid3 = "819d3cd1-afe5-3e4a-9f0c-945e25d09879", .uuid5 = "f340ef4d-139c-567a-b0fc-7c495336674e", },
+	    { .uuid3 = "e7df1a3b-c9f8-3e5a-88d6-ba72b2a0f27b", .uuid5 = "7e3f5fd2-3c93-58d6-9f35-6e0192445b11", },
+	    { .uuid3 = "0854bedf-74ba-3f2b-b823-dc2c90d27c76", .uuid5 = "bc112b6b-c5de-5ee9-b816-808792743a20", },
+	    { .uuid3 = "a1b8c3ba-f821-32ef-a3fd-b97b3855efa8", .uuid5 = "47f8f82d-9fcd-553c-90c5-3f3cb3ad00ad", },
+	    { .uuid3 = "9458f819-079b-3033-9430-ba10f576c067", .uuid5 = "bee5c091-5f01-51fa-86bb-e9488fd3b4da", },
+	    { .uuid3 = "8e1f240a-e386-3e00-866a-6f9da1e3503f", .uuid5 = "8ea92cea-d741-566f-a44a-d51e65b4c5e4", },
+	};
+	const ExpectedUuids dns_uuids[] = {
+	    { .uuid3 = "4385125b-dd1e-3025-880f-3311517cc8d5", .uuid5 = "6af613b6-569c-5c22-9c37-2ed93f31d3af", },
+	    { .uuid3 = "afd0b036-625a-3aa8-b639-9dc8c8fff0ff", .uuid5 = "b04965e6-a9bb-591f-8f8a-1adcb2c8dc39", },
+	    { .uuid3 = "9c45c2f1-1761-3daa-ad31-1ff8703ae846", .uuid5 = "4b166dbe-d99d-5091-abdd-95b83330ed3a", },
+	    { .uuid3 = "15e0ba07-10e4-3d7f-aaff-c00fed873c88", .uuid5 = "98123fde-012f-5ff3-8b50-881449dac91a", },
+	    { .uuid3 = "bc27b4db-bc0f-34f9-ae8e-4b72f2d51b60", .uuid5 = "6ed955c6-506a-5343-9be4-2c0afae02eef", },
+	    { .uuid3 = "7586bfed-b8b8-3bb3-9c95-09a4a79dc0f7", .uuid5 = "c8691da2-158a-5ed6-8537-0e6f140801f2", },
+	    { .uuid3 = "881430b6-8d28-3175-b87d-e81f2f5978c6", .uuid5 = "a6c4fc8f-6950-51de-a9ae-2c519c465071", },
+	    { .uuid3 = "24075675-98ae-354e-89ca-0126a9ad36e3", .uuid5 = "a9f96b98-dd44-5216-ab0d-dbfc6b262edf", },
+	    { .uuid3 = "2c269ea4-dbfd-32dd-9bd7-a5c22677d18b", .uuid5 = "e99caacd-6c45-5906-bd9f-b79e62f25963", },
+	    { .uuid3 = "44eb0948-118f-3f28-87e4-f61c8f889aba", .uuid5 = "e4d80b30-151e-51b5-9f4f-18a3b82718e6", },
+	    { .uuid3 = "fc72beeb-f790-36ee-a73d-33888c9d8880", .uuid5 = "0159d6c7-973f-5e7a-a9a0-d195d0ea6fe2", },
+	    { .uuid3 = "1e46afa2-6176-3cd3-9750-3015846723df", .uuid5 = "7fef88f7-411d-5669-b42d-bf5fc7f9b58b", },
+	    { .uuid3 = "0042b01d-95bd-343f-bd9f-3186bfd63508", .uuid5 = "52524d6e-10dc-5261-aa36-8b2efcbaa5f0", },
+	    { .uuid3 = "115ff52f-d605-3b4b-98fe-c0ea57f4930c", .uuid5 = "91c274f2-9a0d-5ce6-ac3d-7529f452df21", },
+	    { .uuid3 = "ed0221e8-ac7d-393b-821d-25183567885b", .uuid5 = "0ff1e264-520d-543a-87dd-181a491e667e", },
+	    { .uuid3 = "508ef333-85a6-314c-bcf3-17ddc32b2216", .uuid5 = "23986425-d3a5-5e13-8bab-299745777a8d", },
+	    { .uuid3 = "a4715ee0-524a-37cc-beb2-a0b5030757b7", .uuid5 = "c15b38c9-9a3e-543c-a703-dd742f25b4d5", },
+	    { .uuid3 = "d1c72756-aaec-3470-a2f2-97415f44d72f", .uuid5 = "db680066-c83d-5ed7-89a4-1d79466ea62d", },
+	    { .uuid3 = "7aec2f01-586e-3d53-b8f3-6cf7e6b649a4", .uuid5 = "cadb7952-2bba-5609-88d4-8e47ec4e7920", },
+	    { .uuid3 = "3d234b88-8d6f-319a-91ea-edb6059fc825", .uuid5 = "35140057-a2a4-5adb-a500-46f8ed8b66a9", },
+	    { .uuid3 = "d2568554-93ec-30c7-9e15-f383be19e5bb", .uuid5 = "66e549b7-01e2-5d07-98d5-430f74d8d3b2", },
+	    { .uuid3 = "800e59a7-dd0f-3114-8e58-ab7e213895ca", .uuid5 = "292c8e99-2378-55aa-83d8-350e0ac3f1cc", },
+	    { .uuid3 = "3b7d03f0-e067-3d72-84f4-e410ac36ef57", .uuid5 = "0e3b230a-0509-55d8-96a0-9875f387a2be", },
+	    { .uuid3 = "8762be68-de95-391a-94a0-c5fd0446e037", .uuid5 = "4c507660-a83b-55c0-9b2b-83eccb07723d", },
+	    { .uuid3 = "2bd8b4c9-01af-3cd0-aced-94ee6e2004b8", .uuid5 = "a1b9b633-da11-58be-b1a9-5cfa2848f186", },
+	    { .uuid3 = "a627d6a4-394a-33f5-b68e-22bfb6488d01", .uuid5 = "c2708a8b-120a-56f5-a30d-990048af87cc", },
+	    { .uuid3 = "6a592510-17d9-3925-b321-4a8d4927f8d0", .uuid5 = "e7263999-68b6-5a23-b530-af25b7efd632", },
+	    { .uuid3 = "9ee72491-59c4-333c-bb93-fe733a842fdb", .uuid5 = "ce1ae2d5-3454-5952-97ff-36ff935bcfe9", },
+	    { .uuid3 = "2591c62c-0a9d-3c28-97bc-fa0401556a3c", .uuid5 = "33677b87-bc8d-5ff6-9a25-fe60225e4bf0", },
+	    { .uuid3 = "7912be1e-4562-373b-92e2-3d6d2123bc8e", .uuid5 = "ed2305ae-e8f9-5387-b860-3d80ae6c02f7", },
+	    { .uuid3 = "09370cda-89a4-3a48-b592-9c0486e0d5e4", .uuid5 = "604ed872-ae2d-5d91-8e3e-572f3a3aaaa5", },
+	    { .uuid3 = "de5980d3-a137-373c-850b-ca3e5f100779", .uuid5 = "8f8173d9-2f8d-5636-a693-24d9f79ba651", },
+	    { .uuid3 = "9441501d-f633-365a-8955-9df443edc762", .uuid5 = "36eb8d4d-b854-51f1-9fdf-3735964225d5", },
+	    { .uuid3 = "434ada18-13ce-3c08-8b40-a1a1ae030569", .uuid5 = "3493b6ca-f84b-56a9-97cc-c0bd1c46c4c0", },
+	    { .uuid3 = "a13b6160-bd23-3710-a150-41d800dd30b4", .uuid5 = "f413ea13-fcd9-5b44-9d22-1fa1f7b063a5", },
+	    { .uuid3 = "73a67c12-c5f0-3288-ad6a-c78aea0917b0", .uuid5 = "f468d924-d23b-56c2-b90f-3d1cf4b45337", },
+	    { .uuid3 = "a126ee4f-a222-357d-b71b-7d3f226c559f", .uuid5 = "8828c9d6-ed76-5c09-bf64-ba9e9cd90896", },
+	    { .uuid3 = "48f4f36b-b015-3137-9b6e-351bb175c7f7", .uuid5 = "facb7618-55ca-5c30-9cba-fd567b6c0611", },
+	    { .uuid3 = "3fe8f6a3-fe4a-3487-89d6-dd06c6ad02e3", .uuid5 = "96f3de0e-6412-5434-b406-67ef3352ab85", },
+	    { .uuid3 = "d68fa2d4-adc9-3b20-ac77-42585cd1d59f", .uuid5 = "9ebacb89-40ab-52b3-93a2-9054611d8f55", },
+	    { .uuid3 = "819f86a3-31d5-3e72-a83e-142c3a3e4832", .uuid5 = "681046ff-9129-5ade-b11c-769864e02184", },
+	    { .uuid3 = "9957b433-ddc8-3113-a3e6-5512cf13dab1", .uuid5 = "c13d0b5d-1ca3-57b6-a23f-8586bca44928", },
+	    { .uuid3 = "5aab6e0c-b7d3-379c-92e3-2bfbb5572511", .uuid5 = "7c411b5e-9d3f-50b5-9c28-62096e41c4ed", },
+	    { .uuid3 = "11c8ff30-3a7d-3547-80a7-d61b8abeeda8", .uuid5 = "f825aafe-6696-5121-b263-6b2c408b7f43", },
+	    { .uuid3 = "98799b9f-1c5e-30b3-930f-e412b862cbe4", .uuid5 = "f2b4caea-61c3-5bed-8ce7-d8b9d16e129e", },
+	    { .uuid3 = "9bdf2544-31d8-3555-94b0-6a749118a996", .uuid5 = "3593855a-6557-5736-8cab-172c6987f949", },
+	    { .uuid3 = "ddcfb9b3-e990-3985-9021-546a2711e7e5", .uuid5 = "36392431-d554-5385-b876-7bc6e1cb26b3", },
+	    { .uuid3 = "190d7a78-1484-3136-80a6-40f28852785c", .uuid5 = "7e645493-0898-5501-8155-e8578b4f5224", },
+	    { .uuid3 = "6ed693e4-7dc0-3210-856b-a6eb4cc73e13", .uuid5 = "14dc6a81-0491-5683-baaf-7582a61c5798", },
+	    { .uuid3 = "b6a14b21-e73a-3ce2-9076-a804c434f5c6", .uuid5 = "883e0a9c-e3b3-5f9c-8073-2913cbbb99ec", },
+	};
+	char i_str[30];
+	guint i;
+
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "d41d8cd9-8f00-b204-e980-0998ecf8427e", "", -1, NULL);
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "0cc175b9-c0f1-b6a8-31c3-99e269772661", "a", -1, NULL);
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "098f6bcd-4621-d373-cade-4e832627b4f6", "test", -1, NULL);
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "70350f60-27bc-e371-3f6b-76473084309b", "a\0b", 3, NULL);
 	_test_uuid (NM_UTILS_UUID_TYPE_LEGACY, "59c0547b-7fe2-1c15-2cce-e328e8bf6742", "/etc/NetworkManager/system-connections/em1", -1, NULL);
 
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "4ae71336-e44b-39bf-b9d2-752e234818a5", "", -1, NULL);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "0531103a-d8fc-3dd4-b972-d98e4750994e", "a", -1, NULL);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "96e17d7a-ac89-38cf-95e1-bf5098da34e1", "test", -1, NULL);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "8156568e-4ae6-3f34-a93e-18e2c6cbbf78", "a\0b", 3, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "4ae71336-e44b-39bf-b9d2-752e234818a5", "", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "0531103a-d8fc-3dd4-b972-d98e4750994e", "a", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "96e17d7a-ac89-38cf-95e1-bf5098da34e1", "test", -1, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "8156568e-4ae6-3f34-a93e-18e2c6cbbf78", "a\0b", 3, NULL);
+
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "c87ee674-4ddc-3efe-a74e-dfe25da5d7b3", "", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "4c104dd0-4821-30d5-9ce3-0e7a1f8b7c0d", "a", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "45a113ac-c7f2-30b0-90a5-a399ab912716", "test", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "002a0ada-f547-375a-bab5-896a11d1927e", "a\0b", 3, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "9a75f5f2-195e-31a9-9d07-8c18b5d3b285", "test123", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "ec794efe-a384-3b11-a0b6-ec8995bc6acc", "x", -1, UUID_NS_DNS);
+
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "a7650b9f-f19f-5300-8a13-91160ea8de2c", "a\0b", 3, NULL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "4f3f2898-69e3-5a0d-820a-c4e87987dbce", "a", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "05b16a01-46c6-56dd-bd6e-c6dfb4a1427a", "x", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "c9ed566a-6b79-5d3a-b2b7-96a936b48cf3", "test123", -1, UUID_NS_DNS);
+
+	for (i = 0; i < G_N_ELEMENTS (zero_uuids); i++) {
+		nm_sprintf_buf (i_str, "%u", i),
+		_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, zero_uuids[i].uuid3, i_str, -1, NULL);
+		_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, zero_uuids[i].uuid5, i_str, -1, NULL);
+	}
+	for (i = 0; i < G_N_ELEMENTS (dns_uuids); i++) {
+		nm_sprintf_buf (i_str, "%u", i),
+		_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, dns_uuids[i].uuid3, i_str, -1, UUID_NS_DNS);
+		_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, dns_uuids[i].uuid5, i_str, -1, UUID_NS_DNS);
+	}
+
+	/* examples from cpython unit tests: */
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "6fa459ea-ee8a-3ca4-894e-db77e160355e", "python.org", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "886313e1-3b8a-5372-9b90-0c9aee199e5d", "python.org", -1, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "9fe8e8c4-aaa8-32a9-a55c-4535a88b748d", "http://python.org/", -1, UUID_NS_URL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "4c565f0d-3f5a-5890-b41b-20cf47701c5e", "http://python.org/", -1, UUID_NS_URL);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "dd1a1cef-13d5-368a-ad82-eca71acd4cd1", "1.3.6.1", -1, UUID_NS_OID);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "1447fa61-5277-5fef-a9b3-fbc6e44f4af3", "1.3.6.1", -1, UUID_NS_OID);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION3, "658d3002-db6b-3040-a1d1-8ddd7d189a4d", "c=ca", -1, UUID_NS_X500);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "cc957dd1-a972-5349-98cd-874190002798", "c=ca", -1, UUID_NS_X500);
 
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "c87ee674-4ddc-3efe-a74e-dfe25da5d7b3", "", -1, UUID_NS_DNS);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "4c104dd0-4821-30d5-9ce3-0e7a1f8b7c0d", "a", -1, UUID_NS_DNS);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "45a113ac-c7f2-30b0-90a5-a399ab912716", "test", -1, UUID_NS_DNS);
-	_test_uuid (NM_UTILS_UUID_TYPE_VARIANT3, "002a0ada-f547-375a-bab5-896a11d1927e", "a\0b", 3, UUID_NS_DNS);
+	_test_uuid (NM_UTILS_UUID_TYPE_VERSION5, "74738ff5-5367-5958-9aee-98fffdcd1876", "www.example.org", -1, UUID_NS_DNS);
 }
 
 /*****************************************************************************/
@@ -5505,7 +5670,7 @@ __test_uuid (const char *expected_uuid, const char *str, gssize slen, char *uuid
 	}
 	g_free (uuid_test);
 
-	uuid_test = nm_utils_uuid_generate_from_string (str, slen, NM_UTILS_UUID_TYPE_VARIANT3, NM_UTILS_UUID_NS);
+	uuid_test = nm_utils_uuid_generate_from_string (str, slen, NM_UTILS_UUID_TYPE_VERSION3, NM_UTILS_UUID_NS);
 
 	g_assert (uuid_test);
 	g_assert (nm_utils_is_uuid (uuid_test));
@@ -5522,6 +5687,15 @@ __test_uuid (const char *expected_uuid, const char *str, gssize slen, char *uuid
 static void
 test_nm_utils_uuid_generate_from_strings (void)
 {
+	const NMUuid uuid0 = { 0 };
+
+	g_assert_cmpmem (&uuid0, sizeof (uuid0), _uuid ("00000000-0000-0000-0000-000000000000"), 16);
+
+	g_assert (nm_utils_uuid_is_null (NULL));
+	g_assert (nm_utils_uuid_is_null (&uuid0));
+	g_assert ( nm_utils_uuid_is_null (_uuid ("00000000-0000-0000-0000-000000000000")));
+	g_assert (!nm_utils_uuid_is_null (_uuid ("10000000-0000-0000-0000-000000000000")));
+
 	_test_uuid ("b07c334a-399b-32de-8d50-58e4e08f98e3", "",         0, NULL);
 	_test_uuid ("b8a426cb-bcb5-30a3-bd8f-6786fea72df9", "\0",       1, "");
 	_test_uuid ("12a4a982-7aae-39e1-951e-41aeb1250959", "a\0",      2, "a");