about summary refs log tree commit diff
path: root/libnm-util
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-util')
-rw-r--r--libnm-util/crypto.c94
-rw-r--r--libnm-util/crypto.h5
-rw-r--r--libnm-util/crypto_gnutls.c51
-rw-r--r--libnm-util/crypto_nss.c15
-rw-r--r--libnm-util/libnm-util.ver1
-rw-r--r--libnm-util/nm-connection.c9
-rw-r--r--libnm-util/nm-param-spec-specialized.c98
-rw-r--r--libnm-util/nm-setting-8021x.c108
-rw-r--r--libnm-util/nm-setting-8021x.h12
-rw-r--r--libnm-util/nm-setting-gsm.c22
-rw-r--r--libnm-util/nm-setting-vpn.c49
-rw-r--r--libnm-util/nm-setting.c25
-rw-r--r--libnm-util/nm-utils.c64
-rw-r--r--libnm-util/nm-utils.h1
-rw-r--r--libnm-util/tests/Makefile.am8
-rw-r--r--libnm-util/tests/Makefile.in8
-rw-r--r--libnm-util/tests/certs/Makefile.am5
-rw-r--r--libnm-util/tests/certs/Makefile.in5
-rw-r--r--libnm-util/tests/certs/pkcs8-decrypted.derbin0 -> 1194 bytes
-rw-r--r--libnm-util/tests/certs/pkcs8-enc-key.pem29
-rw-r--r--libnm-util/tests/certs/pkcs8-noenc-key.pem28
-rw-r--r--libnm-util/tests/test-crypto.c34
-rw-r--r--libnm-util/tests/test-general.c90
23 files changed, 588 insertions, 173 deletions
diff --git a/libnm-util/crypto.c b/libnm-util/crypto.c
index 991b3c3e..949ee812 100644
--- a/libnm-util/crypto.c
+++ b/libnm-util/crypto.c
@@ -52,6 +52,12 @@ _nm_crypto_error_quark (void)
 #define PEM_CERT_BEGIN    "-----BEGIN CERTIFICATE-----"
 #define PEM_CERT_END      "-----END CERTIFICATE-----"
 
+#define PEM_PKCS8_ENC_KEY_BEGIN "-----BEGIN ENCRYPTED PRIVATE KEY-----"
+#define PEM_PKCS8_ENC_KEY_END   "-----END ENCRYPTED PRIVATE KEY-----"
+
+#define PEM_PKCS8_DEC_KEY_BEGIN "-----BEGIN PRIVATE KEY-----"
+#define PEM_PKCS8_DEC_KEY_END   "-----END PRIVATE KEY-----"
+
 static gboolean
 find_tag (const char *tag,
           const GByteArray *array,
@@ -251,6 +257,71 @@ parse_error:
 }
 
 static GByteArray *
+parse_pkcs8_key_file (const GByteArray *contents,
+                      gboolean *out_encrypted,
+                      GError **error)
+{
+	GByteArray *key = NULL;
+	gsize start = 0, end = 0;
+	unsigned char *der = NULL;
+	guint8 save_end;
+	gsize length = 0;
+	const char *start_tag = NULL, *end_tag = NULL;
+	gboolean encrypted = FALSE;
+
+	/* Try encrypted first, decrypted next */
+	if (find_tag (PEM_PKCS8_ENC_KEY_BEGIN, contents, 0, &start)) {
+		start_tag = PEM_PKCS8_ENC_KEY_BEGIN;
+		end_tag = PEM_PKCS8_ENC_KEY_END;
+		encrypted = TRUE;
+	} else if (find_tag (PEM_PKCS8_DEC_KEY_BEGIN, contents, 0, &start)) {
+		start_tag = PEM_PKCS8_DEC_KEY_BEGIN;
+		end_tag = PEM_PKCS8_DEC_KEY_END;
+		encrypted = FALSE;
+	} else {
+		g_set_error_literal (error, NM_CRYPTO_ERROR,
+		                     NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
+		                     _("Failed to find expected PKCS#8 start tag."));
+		return NULL;
+	}
+
+	start += strlen (start_tag);
+	if (!find_tag (end_tag, contents, start, &end)) {
+		g_set_error (error, NM_CRYPTO_ERROR,
+		             NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
+		             _("Failed to find expected PKCS#8 end tag '%s'."),
+		             end_tag);
+		return NULL;
+	}
+
+	/* g_base64_decode() wants a NULL-terminated string */
+	save_end = contents->data[end];
+	contents->data[end] = '\0';
+	der = g_base64_decode ((const char *) (contents->data + start), &length);
+	contents->data[end] = save_end;
+
+	if (der && length) {
+		key = g_byte_array_sized_new (length);
+		if (key) {
+			g_byte_array_append (key, der, length);
+			g_assert (key->len == length);
+			*out_encrypted = encrypted;
+		} else {
+			g_set_error_literal (error, NM_CRYPTO_ERROR,
+			                     NM_CRYPTO_ERR_OUT_OF_MEMORY,
+			                     _("Not enough memory to store private key data."));
+		}
+	} else {
+		g_set_error_literal (error, NM_CRYPTO_ERROR,
+		                     NM_CRYPTO_ERR_DECODE_FAILED,
+		                     _("Failed to decode PKCS#8 private key."));
+	}
+
+	g_free (der);
+	return key;
+}
+
+static GByteArray *
 file_to_g_byte_array (const char *filename, GError **error)
 {
 	char *contents;
@@ -654,6 +725,7 @@ crypto_verify_private_key_data (const GByteArray *contents,
 	GByteArray *tmp;
 	NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
 	NMCryptoKeyType ktype = NM_CRYPTO_KEY_TYPE_UNKNOWN;
+	gboolean is_encrypted = FALSE;
 
 	g_return_val_if_fail (contents != NULL, FALSE);
 
@@ -662,15 +734,29 @@ crypto_verify_private_key_data (const GByteArray *contents,
 		if (!password || crypto_verify_pkcs12 (contents, password, error))
 			format = NM_CRYPTO_FILE_FORMAT_PKCS12;
 	} else {
-		tmp = crypto_decrypt_private_key_data (contents, password, &ktype, error);
+		/* Maybe it's PKCS#8 */
+		tmp = parse_pkcs8_key_file (contents, &is_encrypted, error);
+		if (tmp) {
+			if (crypto_verify_pkcs8 (tmp, is_encrypted, password, error))
+				format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
+		} else {
+			g_clear_error (error);
+
+			/* Or it's old-style OpenSSL */
+			tmp = crypto_decrypt_private_key_data (contents, password, &ktype, error);
+			if (tmp)
+				format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
+			else if (!password && (ktype != NM_CRYPTO_KEY_TYPE_UNKNOWN))
+				format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
+		}
+
 		if (tmp) {
 			/* Don't leave decrypted key data around */
 			memset (tmp->data, 0, tmp->len);
 			g_byte_array_free (tmp, TRUE);
-			format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
-		} else if (!password && (ktype != NM_CRYPTO_KEY_TYPE_UNKNOWN))
-			format = NM_CRYPTO_FILE_FORMAT_RAW_KEY;
+		}
 	}
+
 	return format;
 }
 
diff --git a/libnm-util/crypto.h b/libnm-util/crypto.h
index cdf053e7..482ed087 100644
--- a/libnm-util/crypto.h
+++ b/libnm-util/crypto.h
@@ -136,4 +136,9 @@ gboolean crypto_verify_pkcs12 (const GByteArray *data,
                                const char *password,
                                GError **error);
 
+gboolean crypto_verify_pkcs8 (const GByteArray *data,
+                              gboolean is_encrypted,
+                              const char *password,
+                              GError **error);
+
 #endif  /* __CRYPTO_H__ */
diff --git a/libnm-util/crypto_gnutls.c b/libnm-util/crypto_gnutls.c
index 583eb8be..d82230b0 100644
--- a/libnm-util/crypto_gnutls.c
+++ b/libnm-util/crypto_gnutls.c
@@ -439,6 +439,57 @@ out:
 }
 
 gboolean
+crypto_verify_pkcs8 (const GByteArray *data,
+                     gboolean is_encrypted,
+                     const char *password,
+                     GError **error)
+{
+	gnutls_x509_privkey_t p8;
+	gnutls_datum dt;
+	int err;
+
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	dt.data = (unsigned char *) data->data;
+	dt.size = data->len;
+
+	err = gnutls_x509_privkey_init (&p8);
+	if (err < 0) {
+		g_set_error (error, NM_CRYPTO_ERROR,
+		             NM_CRYPTO_ERR_DECODE_FAILED,
+		             _("Couldn't initialize PKCS#8 decoder: %s"),
+		             gnutls_strerror (err));
+		return FALSE;
+	}
+
+	err = gnutls_x509_privkey_import_pkcs8 (p8,
+	                                        &dt,
+	                                        GNUTLS_X509_FMT_DER,
+	                                        is_encrypted ? password : NULL,
+	                                        is_encrypted ? 0 : GNUTLS_PKCS_PLAIN);
+	gnutls_x509_privkey_deinit (p8);
+
+	if (err < 0) {
+		if (err == GNUTLS_E_UNKNOWN_CIPHER_TYPE) {
+			/* HACK: gnutls doesn't support all the cipher types that openssl
+			 * can use with PKCS#8, so if we encounter one, we have to assume
+			 * the given password works.  gnutls needs to unsuckify, apparently.
+			 * Specifically, by default openssl uses pbeWithMD5AndDES-CBC
+			 * which gnutls does not support.
+			 */
+		} else {
+			g_set_error (error, NM_CRYPTO_ERROR,
+				         NM_CRYPTO_ERR_FILE_FORMAT_INVALID,
+				         _("Couldn't decode PKCS#8 file: %s"),
+				         gnutls_strerror (err));
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+gboolean
 crypto_randomize (void *buffer, gsize buffer_len, GError **error)
 {
 	gcry_randomize (buffer, buffer_len, GCRY_STRONG_RANDOM);
diff --git a/libnm-util/crypto_nss.c b/libnm-util/crypto_nss.c
index ff12f9c5..5a7aa30b 100644
--- a/libnm-util/crypto_nss.c
+++ b/libnm-util/crypto_nss.c
@@ -542,6 +542,21 @@ error:
 }
 
 gboolean
+crypto_verify_pkcs8 (const GByteArray *data,
+                     gboolean is_encrypted,
+                     const char *password,
+                     GError **error)
+{
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	/* NSS apparently doesn't do PKCS#8 natively, but you have to put the
+	 * PKCS#8 key into a PKCS#12 file and import that??  So until we figure
+	 * all that out, we can only assume the password is valid.
+	 */
+	return TRUE;
+}
+
+gboolean
 crypto_randomize (void *buffer, gsize buffer_len, GError **error)
 {
 	SECStatus s;
diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver
index bb988bc4..4ff0838e 100644
--- a/libnm-util/libnm-util.ver
+++ b/libnm-util/libnm-util.ver
@@ -130,6 +130,7 @@ global:
 	nm_setting_802_1x_get_phase2_private_key_path;
 	nm_setting_802_1x_get_phase2_private_key_scheme;
 	nm_setting_802_1x_get_pin;
+	nm_setting_802_1x_get_pin_flags;
 	nm_setting_802_1x_get_private_key_blob;
 	nm_setting_802_1x_get_private_key_format;
 	nm_setting_802_1x_get_private_key_password;
diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c
index cd9d53ff..6e9f92b5 100644
--- a/libnm-util/nm-connection.c
+++ b/libnm-util/nm-connection.c
@@ -512,7 +512,7 @@ validate_permissions_type (GHashTable *hash, GError **error)
 /**
  * nm_connection_replace_settings:
  * @connection: a #NMConnection
- * @new_settings: (element-type utf8 GHashTable<utf8,GValue>): a #GHashTable of settings
+ * @new_settings: (element-type utf8 GLib.HashTable): a #GHashTable of settings
  * @error: location to store error, or %NULL
  *
  * Returns: %TRUE if the settings were valid and added to the connection, %FALSE
@@ -640,9 +640,10 @@ diff_one_connection (NMConnection *a,
  * @a: a #NMConnection
  * @b: a second #NMConnection to compare with the first
  * @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
- * @out_settings: (element-type utf8 GHashTable<utf8,guint32>): if the
+ * @out_settings: (element-type utf8 GLib.HashTable): if the
  * connections differ, on return a hash table mapping setting names to
- * second-level GHashTable, which contains key names that differ
+ * second-level GHashTable (utf8 to guint32), which contains the key names that
+ * differ mapped to one or more of %NMSettingDiffResult as a bitfield
  *
  * Compares two #NMConnection objects for similarity, with comparison behavior
  * modified by a set of flags.  See nm_setting_compare() for a description of
@@ -968,7 +969,7 @@ nm_connection_clear_secrets (NMConnection *connection)
  * are #GHashTables mapping string:GValue, each of which represents the
  * properties of the #NMSetting object.
  *
- * Returns: (transfer full) (element-type utf8 GHashTable<utf8,GValue>): a new
+ * Returns: (transfer full) (element-type utf8 GLib.HashTable): a new
  * #GHashTable describing the connection, its settings, and each setting's
  * properties.  The caller owns the hash table and must unref the hash table
  * with g_hash_table_unref() when it is no longer needed.
diff --git a/libnm-util/nm-param-spec-specialized.c b/libnm-util/nm-param-spec-specialized.c
index f5a362ce..93623a11 100644
--- a/libnm-util/nm-param-spec-specialized.c
+++ b/libnm-util/nm-param-spec-specialized.c
@@ -37,9 +37,9 @@ struct _NMParamSpecSpecialized {
 #include "nm-dbus-glib-types.h"
 
 /***********************************************************/
-/* nm_gvalues_compare */
+/* _gvalues_compare */
 
-static gint nm_gvalues_compare (const GValue *value1, const GValue *value2);
+static gint _gvalues_compare (const GValue *value1, const GValue *value2);
 
 static gboolean
 type_is_fixed_size (GType type, gsize *tsize)
@@ -86,7 +86,7 @@ type_is_fixed_size (GType type, gsize *tsize)
 #define FLOAT_FACTOR 0.00000001
 
 static gint
-nm_gvalues_compare_fixed (const GValue *value1, const GValue *value2)
+_gvalues_compare_fixed (const GValue *value1, const GValue *value2)
 {
 	int ret = 0;
 
@@ -177,7 +177,7 @@ nm_gvalues_compare_fixed (const GValue *value1, const GValue *value2)
 }
 
 static gint
-nm_gvalues_compare_string (const GValue *value1, const GValue *value2)
+_gvalues_compare_string (const GValue *value1, const GValue *value2)
 {
 	const char *str1 = g_value_get_string (value1);
 	const char *str2 = g_value_get_string (value2);
@@ -194,7 +194,7 @@ nm_gvalues_compare_string (const GValue *value1, const GValue *value2)
 }
 
 static gint
-nm_gvalues_compare_strv (const GValue *value1, const GValue *value2)
+_gvalues_compare_strv (const GValue *value1, const GValue *value2)
 {
 	char **strv1;
 	char **strv2;
@@ -221,7 +221,7 @@ nm_gvalues_compare_strv (const GValue *value1, const GValue *value2)
 }
 
 static void
-nm_gvalue_destroy (gpointer data)
+_gvalue_destroy (gpointer data)
 {
 	GValue *value = (GValue *) data;
 
@@ -250,7 +250,7 @@ iterate_collection (const GValue *value, gpointer user_data)
 }
 
 static gint
-nm_gvalues_compare_collection (const GValue *value1, const GValue *value2)
+_gvalues_compare_collection (const GValue *value1, const GValue *value2)
 {
 	gint ret;
 	guint len1;
@@ -287,12 +287,12 @@ nm_gvalues_compare_collection (const GValue *value1, const GValue *value2)
 			for (iter1 = list1, iter2 = list2, ret = 0;
 				ret == 0 && iter1 && iter2; 
 				iter1 = iter1->next, iter2 = iter2->next)
-				ret = nm_gvalues_compare ((GValue *) iter1->data, (GValue *) iter2->data);
+				ret = _gvalues_compare ((GValue *) iter1->data, (GValue *) iter2->data);
 		}
 
-		g_slist_foreach (list1, (GFunc) nm_gvalue_destroy, NULL);
+		g_slist_foreach (list1, (GFunc) _gvalue_destroy, NULL);
 		g_slist_free (list1);
-		g_slist_foreach (list2, (GFunc) nm_gvalue_destroy, NULL);
+		g_slist_foreach (list2, (GFunc) _gvalue_destroy, NULL);
 		g_slist_free (list2);
 	}
 
@@ -325,13 +325,13 @@ compare_one_map_item (gpointer key, gpointer val, gpointer user_data)
 
 	value2 = (GValue *) g_hash_table_lookup (info->hash2, key);
 	if (value2)
-		info->ret = nm_gvalues_compare ((GValue *) val, value2);
+		info->ret = _gvalues_compare ((GValue *) val, value2);
 	else
 		info->ret = 1;
 }
 
 static gint
-nm_gvalues_compare_map (const GValue *value1, const GValue *value2)
+_gvalues_compare_map (const GValue *value1, const GValue *value2)
 {
 	GHashTable *hash1 = NULL;
 	GHashTable *hash2 = NULL;
@@ -345,11 +345,11 @@ nm_gvalues_compare_map (const GValue *value1, const GValue *value2)
 		return 0;
 	}
 
-	hash1 = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, nm_gvalue_destroy);
+	hash1 = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, _gvalue_destroy);
 	dbus_g_type_map_value_iterate (value1, iterate_map, &hash1); 
 	len1 = g_hash_table_size (hash1);
 
-	hash2 = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, nm_gvalue_destroy);
+	hash2 = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, _gvalue_destroy);
 	dbus_g_type_map_value_iterate (value2, iterate_map, &hash2);
 	len2 = g_hash_table_size (hash2);
 
@@ -491,10 +491,10 @@ nm_gvalue_ip6_route_compare (const GValue *value1, const GValue *value2)
 }
 
 static gint
-nm_gvalues_compare_struct (const GValue *value1, const GValue *value2)
+_gvalues_compare_struct (const GValue *value1, const GValue *value2)
 {
 	/* value1 and value2 must contain the same type since
-	 * nm_gvalues_compare() enforced that already.
+	 * _gvalues_compare() enforced that already.
 	 */
 
 	if (G_VALUE_HOLDS (value1, DBUS_TYPE_G_IP6_ADDRESS)) {
@@ -508,7 +508,7 @@ nm_gvalues_compare_struct (const GValue *value1, const GValue *value2)
 }
 
 gint
-nm_gvalues_compare (const GValue *value1, const GValue *value2)
+_gvalues_compare (const GValue *value1, const GValue *value2)
 {
 	GType type1;
 	GType type2;
@@ -528,9 +528,9 @@ nm_gvalues_compare (const GValue *value1, const GValue *value2)
 		return type1 < type2 ? -1 : type1 > type2;
 
 	if (type_is_fixed_size (type1, NULL))
-		ret = nm_gvalues_compare_fixed (value1, value2);
+		ret = _gvalues_compare_fixed (value1, value2);
 	else if (type1 == G_TYPE_STRING) 
-		ret = nm_gvalues_compare_string (value1, value2);
+		ret = _gvalues_compare_string (value1, value2);
 	else if (G_VALUE_HOLDS_BOXED (value1)) {
 		gpointer p1 = g_value_get_boxed (value1);
 		gpointer p2 = g_value_get_boxed (value2);
@@ -542,15 +542,15 @@ nm_gvalues_compare (const GValue *value1, const GValue *value2)
 		else if (!p2)
 			ret = -1; /* The comparision functions below don't handle NULLs */
 		else if (type1 == G_TYPE_STRV)
-			ret = nm_gvalues_compare_strv (value1, value2);
+			ret = _gvalues_compare_strv (value1, value2);
 		else if (dbus_g_type_is_collection (type1))
-			ret = nm_gvalues_compare_collection (value1, value2);
+			ret = _gvalues_compare_collection (value1, value2);
 		else if (dbus_g_type_is_map (type1))
-			ret = nm_gvalues_compare_map (value1, value2);
+			ret = _gvalues_compare_map (value1, value2);
 		else if (dbus_g_type_is_struct (type1))
-			ret = nm_gvalues_compare_struct (value1, value2);
+			ret = _gvalues_compare_struct (value1, value2);
 		else if (type1 == G_TYPE_VALUE)
-			ret = nm_gvalues_compare ((GValue *) g_value_get_boxed (value1), (GValue *) g_value_get_boxed (value2));
+			ret = _gvalues_compare ((GValue *) g_value_get_boxed (value1), (GValue *) g_value_get_boxed (value2));
 		else {
 			g_warning ("Don't know how to compare boxed types '%s'", g_type_name (type1));
 			ret = value1 == value2;
@@ -596,7 +596,7 @@ param_specialized_values_cmp (GParamSpec *pspec,
 						const GValue *value1,
 						const GValue *value2)
 {
-	return nm_gvalues_compare (value1, value2);
+	return _gvalues_compare (value1, value2);
 }
 
 GType
@@ -656,13 +656,13 @@ compare_ints (void)
 
 	g_value_set_int (&value1, 5);
 	g_value_set_int (&value2, 5);
-	g_print ("Comparing ints 5 and 5: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing ints 5 and 5: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_value_set_int (&value2, 10);
-	g_print ("Comparing ints 5 and 10: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing ints 5 and 10: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_value_set_int (&value2, 1);
-	g_print ("Comparing ints 5 and 1: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing ints 5 and 1: %d\n", _gvalues_compare (&value1, &value2));
 }
 
 static void
@@ -678,10 +678,10 @@ compare_strings (void)
 
 	g_value_set_string (&value1, str1);
 	g_value_set_string (&value2, str1);
-	g_print ("Comparing identical strings: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing identical strings: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_value_set_string (&value2, str2);
-	g_print ("Comparing different strings: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different strings: %d\n", _gvalues_compare (&value1, &value2));
 }
 
 static void
@@ -699,16 +699,16 @@ compare_strv (void)
 
 	g_value_set_boxed (&value1, strv1);
 	g_value_set_boxed (&value2, strv1);
-	g_print ("Comparing identical strv's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing identical strv's: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_value_set_boxed (&value2, strv2);
-	g_print ("Comparing different strv's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different strv's: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_value_set_boxed (&value2, strv3);
-	g_print ("Comparing different len (smaller) strv's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different len (smaller) strv's: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_value_set_boxed (&value2, strv4);
-	g_print ("Comparing different len (longer) strv's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different len (longer) strv's: %d\n", _gvalues_compare (&value1, &value2));
 }
 
 static void
@@ -734,16 +734,16 @@ compare_garrays (void)
 	g_value_set_boxed (&value1, array1);
 	g_value_set_boxed (&value2, array2);
 
-	g_print ("Comparing identical arrays's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing identical arrays's: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_array_remove_index (array2, 0);
 	g_value_set_boxed (&value2, array2);
-	g_print ("Comparing different length arrays's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different length arrays's: %d\n", _gvalues_compare (&value1, &value2));
 
 	i = 7;
 	g_array_prepend_val (array2, i);
 	g_value_set_boxed (&value2, array2);
-	g_print ("Comparing different arrays's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different arrays's: %d\n", _gvalues_compare (&value1, &value2));
 }
 
 static void
@@ -768,15 +768,15 @@ compare_ptrarrays (void)
 	g_ptr_array_add (array2, "world");
 	g_value_set_boxed (&value2, array2);
 
-	g_print ("Comparing identical ptr arrays's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing identical ptr arrays's: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_ptr_array_add (array2, "boo");
 	g_value_set_boxed (&value2, array2);
-	g_print ("Comparing different len ptr arrays's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different len ptr arrays's: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_ptr_array_add (array1, "booz");
 	g_value_set_boxed (&value1, array1);
-	g_print ("Comparing different ptr arrays's: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different ptr arrays's: %d\n", _gvalues_compare (&value1, &value2));
 }
 
 static void
@@ -801,15 +801,15 @@ compare_str_hash (void)
 
 	g_value_set_boxed (&value1, hash1);
 	g_value_set_boxed (&value2, hash2);
-	g_print ("Comparing identical str hashes: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing identical str hashes: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_hash_table_remove (hash2, "key2");
 	g_value_set_boxed (&value2, hash2);
-	g_print ("Comparing different length str hashes: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different length str hashes: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_hash_table_insert (hash2, "key2", "moon");
 	g_value_set_boxed (&value2, hash2);
-	g_print ("Comparing different str hashes: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different str hashes: %d\n", _gvalues_compare (&value1, &value2));
 }
 
 static GValue *
@@ -858,15 +858,15 @@ compare_gvalue_hash (void)
 
 	g_value_set_boxed (&value1, hash1);
 	g_value_set_boxed (&value2, hash2);
-	g_print ("Comparing identical gvalue hashes: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing identical gvalue hashes: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_hash_table_remove (hash2, "key2");
 	g_value_set_boxed (&value2, hash2);
-	g_print ("Comparing different length str hashes: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different length str hashes: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_hash_table_insert (hash2, "key2", str_to_gvalue ("moon"));
 	g_value_set_boxed (&value2, hash2);
-	g_print ("Comparing different str hashes: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different str hashes: %d\n", _gvalues_compare (&value1, &value2));
 }
 
 static void
@@ -939,15 +939,15 @@ compare_ip6_addresses (void)
 
 	g_value_set_boxed (&value1, array1);
 	g_value_set_boxed (&value2, array1);
-	g_print ("Comparing identical IPv6 address structures: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing identical IPv6 address structures: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_value_set_boxed (&value1, array1);
 	g_value_set_boxed (&value2, array2);
-	g_print ("Comparing different IPv6 address structures: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different IPv6 address structures: %d\n", _gvalues_compare (&value1, &value2));
 
 	g_value_set_boxed (&value1, array1);
 	g_value_set_boxed (&value2, array3);
-	g_print ("Comparing different IPv6 address structures: %d\n", nm_gvalues_compare (&value1, &value2));
+	g_print ("Comparing different IPv6 address structures: %d\n", _gvalues_compare (&value1, &value2));
 }
 
 int
diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c
index 4cd22016..24750422 100644
--- a/libnm-util/nm-setting-8021x.c
+++ b/libnm-util/nm-setting-8021x.c
@@ -475,9 +475,9 @@ path_to_scheme_value (const char *path)
 /**
  * nm_setting_802_1x_set_ca_cert:
  * @setting: the #NMSetting8021x
- * @value: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or
- *   %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the CA certificate file
- *   (PEM or DER format).  The path must be UTF-8 encoded; use
+ * @cert_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH
+ *   or %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the CA certificate
+ *   file (PEM or DER format).  The path must be UTF-8 encoded; use
  *   g_filename_to_utf8() to convert if needed.  Passing NULL with any @scheme
  *   clears the CA certificate.
  * @scheme: desired storage scheme for the certificate
@@ -493,7 +493,7 @@ path_to_scheme_value (const char *path)
  **/
 gboolean
 nm_setting_802_1x_set_ca_cert (NMSetting8021x *self,
-                               const char *value,
+                               const char *cert_path,
                                NMSetting8021xCKScheme scheme,
                                NMSetting8021xCKFormat *out_format,
                                GError **error)
@@ -504,8 +504,8 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *self,
 
 	g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
 
-	if (value) {
-		g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+	if (cert_path) {
+		g_return_val_if_fail (g_utf8_validate (cert_path, -1, NULL), FALSE);
 		g_return_val_if_fail (   scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
 		                      || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH,
 		                      FALSE);
@@ -522,10 +522,10 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *self,
 		priv->ca_cert = NULL;
 	}
 
-	if (!value)
+	if (!cert_path)
 		return TRUE;
 
-	data = crypto_load_and_verify_certificate (value, &format, error);
+	data = crypto_load_and_verify_certificate (cert_path, &format, error);
 	if (data) {
 		/* wpa_supplicant can only use raw x509 CA certs */
 		switch (format) {
@@ -547,7 +547,7 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *self,
 			if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 				priv->ca_cert = data;
 			else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
-				priv->ca_cert = path_to_scheme_value (value);
+				priv->ca_cert = path_to_scheme_value (cert_path);
 			else
 				g_assert_not_reached ();
 		}
@@ -623,11 +623,11 @@ nm_setting_802_1x_get_client_cert_path (NMSetting8021x *setting)
 /**
  * nm_setting_802_1x_set_client_cert:
  * @setting: the #NMSetting8021x
- * @value: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or
- *   %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the client certificate
- *   file (PEM, DER, or PKCS#12 format).  The path must be UTF-8 encoded; use
- *   g_filename_to_utf8() to convert if needed.  Passing NULL with any @scheme
- *   clears the client certificate.
+ * @cert_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH
+ *   or %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the client
+ *   certificate file (PEM, DER, or PKCS#12 format).  The path must be UTF-8
+ *   encoded; use g_filename_to_utf8() to convert if needed.  Passing NULL with
+ *   any @scheme clears the client certificate.
  * @scheme: desired storage scheme for the certificate
  * @out_format: on successful return, the type of the certificate added
  * @error: on unsuccessful return, an error
@@ -645,7 +645,7 @@ nm_setting_802_1x_get_client_cert_path (NMSetting8021x *setting)
  **/
 gboolean
 nm_setting_802_1x_set_client_cert (NMSetting8021x *self,
-                                   const char *value,
+                                   const char *cert_path,
                                    NMSetting8021xCKScheme scheme,
                                    NMSetting8021xCKFormat *out_format,
                                    GError **error)
@@ -656,8 +656,8 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *self,
 
 	g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
 
-	if (value) {
-		g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+	if (cert_path) {
+		g_return_val_if_fail (g_utf8_validate (cert_path, -1, NULL), FALSE);
 		g_return_val_if_fail (   scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
 		                      || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH,
 		                      FALSE);
@@ -674,10 +674,10 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *self,
 		priv->client_cert = NULL;
 	}
 
-	if (!value)
+	if (!cert_path)
 		return TRUE;
 
-	data = crypto_load_and_verify_certificate (value, &format, error);
+	data = crypto_load_and_verify_certificate (cert_path, &format, error);
 	if (data) {
 		/* wpa_supplicant can only use raw x509 CA certs */
 		switch (format) {
@@ -703,7 +703,7 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *self,
 			if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 				priv->client_cert = data;
 			else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
-				priv->client_cert = path_to_scheme_value (value);
+				priv->client_cert = path_to_scheme_value (cert_path);
 			else
 				g_assert_not_reached ();
 		}
@@ -886,8 +886,8 @@ nm_setting_802_1x_get_phase2_ca_cert_path (NMSetting8021x *setting)
 /**
  * nm_setting_802_1x_set_phase2_ca_cert:
  * @setting: the #NMSetting8021x
- * @value: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or
- *   %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" CA
+ * @cert_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH
+ *   or %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" CA
  *   certificate file (PEM or DER format).  The path must be UTF-8 encoded; use
  *   g_filename_to_utf8() to convert if needed.  Passing NULL with any @scheme
  *   clears the "phase2" CA certificate.
@@ -904,7 +904,7 @@ nm_setting_802_1x_get_phase2_ca_cert_path (NMSetting8021x *setting)
  **/
 gboolean
 nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self,
-                                      const char *value,
+                                      const char *cert_path,
                                       NMSetting8021xCKScheme scheme,
                                       NMSetting8021xCKFormat *out_format,
                                       GError **error)
@@ -915,8 +915,8 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self,
 
 	g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
 
-	if (value) {
-		g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+	if (cert_path) {
+		g_return_val_if_fail (g_utf8_validate (cert_path, -1, NULL), FALSE);
 		g_return_val_if_fail (   scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
 		                      || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH,
 		                      FALSE);
@@ -933,10 +933,10 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self,
 		priv->phase2_ca_cert = NULL;
 	}
 
-	if (!value)
+	if (!cert_path)
 		return TRUE;
 
-	data = crypto_load_and_verify_certificate (value, &format, error);
+	data = crypto_load_and_verify_certificate (cert_path, &format, error);
 	if (data) {
 		/* wpa_supplicant can only use raw x509 CA certs */
 		switch (format) {
@@ -958,7 +958,7 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *self,
 			if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 				priv->phase2_ca_cert = data;
 			else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
-				priv->phase2_ca_cert = path_to_scheme_value (value);
+				priv->phase2_ca_cert = path_to_scheme_value (cert_path);
 			else
 				g_assert_not_reached ();
 		}
@@ -1036,8 +1036,8 @@ nm_setting_802_1x_get_phase2_client_cert_path (NMSetting8021x *setting)
 /**
  * nm_setting_802_1x_set_phase2_client_cert:
  * @setting: the #NMSetting8021x
- * @value: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or
- *   %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" client
+ * @cert_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH
+ *   or %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" client
  *   certificate file (PEM, DER, or PKCS#12 format).  The path must be UTF-8
  *   encoded; use g_filename_to_utf8() to convert if needed.  Passing NULL with
  *   any @scheme clears the "phase2" client certificate.
@@ -1058,7 +1058,7 @@ nm_setting_802_1x_get_phase2_client_cert_path (NMSetting8021x *setting)
  **/
 gboolean
 nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self,
-                                          const char *value,
+                                          const char *cert_path,
                                           NMSetting8021xCKScheme scheme,
                                           NMSetting8021xCKFormat *out_format,
                                           GError **error)
@@ -1069,8 +1069,8 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self,
 
 	g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
 
-	if (value) {
-		g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+	if (cert_path) {
+		g_return_val_if_fail (g_utf8_validate (cert_path, -1, NULL), FALSE);
 		g_return_val_if_fail (   scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
 		                      || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH,
 		                      FALSE);
@@ -1087,10 +1087,10 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self,
 		priv->phase2_client_cert = NULL;
 	}
 
-	if (!value)
+	if (!cert_path)
 		return TRUE;
 
-	data = crypto_load_and_verify_certificate (value, &format, error);
+	data = crypto_load_and_verify_certificate (cert_path, &format, error);
 	if (data) {
 		/* wpa_supplicant can only use raw x509 CA certs */
 		switch (format) {
@@ -1116,7 +1116,7 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *self,
 			if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB)
 				priv->phase2_client_cert = data;
 			else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
-				priv->phase2_client_cert = path_to_scheme_value (value);
+				priv->phase2_client_cert = path_to_scheme_value (cert_path);
 			else
 				g_assert_not_reached ();
 		}
@@ -1275,7 +1275,7 @@ file_to_byte_array (const char *filename)
 /**
  * nm_setting_802_1x_set_private_key:
  * @setting: the #NMSetting8021x
- * @value: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or
+ * @key_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or
  *   %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the private key file
  *   (PEM, DER, or PKCS#12 format).  The path must be UTF-8 encoded; use
  *   g_filename_to_utf8() to convert if needed.  Passing NULL with any @scheme
@@ -1313,7 +1313,7 @@ file_to_byte_array (const char *filename)
  **/
 gboolean
 nm_setting_802_1x_set_private_key (NMSetting8021x *self,
-                                   const char *value,
+                                   const char *key_path,
                                    const char *password,
                                    NMSetting8021xCKScheme scheme,
                                    NMSetting8021xCKFormat *out_format,
@@ -1324,8 +1324,8 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *self,
 
 	g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
 
-	if (value) {
-		g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+	if (key_path) {
+		g_return_val_if_fail (g_utf8_validate (key_path, -1, NULL), FALSE);
 		g_return_val_if_fail (   scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
 		                      || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH,
 		                      FALSE);
@@ -1337,8 +1337,8 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *self,
 	/* Ensure the private key is a recognized format and if the password was
 	 * given, that it decrypts the private key.
 	 */
-	if (value) {
-		format = crypto_verify_private_key (value, password, NULL);
+	if (key_path) {
+		format = crypto_verify_private_key (key_path, password, NULL);
 		if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN) {
 			g_set_error (error,
 				         NM_SETTING_802_1X_ERROR,
@@ -1361,16 +1361,16 @@ nm_setting_802_1x_set_private_key (NMSetting8021x *self,
 	g_free (priv->private_key_password);
 	priv->private_key_password = NULL;
 
-	if (value == NULL)
+	if (key_path == NULL)
 		return TRUE;
 
 	priv->private_key_password = g_strdup (password);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
 		/* Shouldn't fail this since we just verified the private key above */
-		priv->private_key = file_to_byte_array (value);
+		priv->private_key = file_to_byte_array (key_path);
 		g_assert (priv->private_key);
 	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
-		priv->private_key = path_to_scheme_value (value);
+		priv->private_key = path_to_scheme_value (key_path);
 	else
 		g_assert_not_reached ();
 
@@ -1570,7 +1570,7 @@ nm_setting_802_1x_get_phase2_private_key_path (NMSetting8021x *setting)
 /**
  * nm_setting_802_1x_set_phase2_private_key:
  * @setting: the #NMSetting8021x
- * @value: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or
+ * @key_path: when @scheme is set to either %NM_SETTING_802_1X_CK_SCHEME_PATH or
  *   %NM_SETTING_802_1X_CK_SCHEME_BLOB, pass the path of the "phase2" private
  *   key file (PEM, DER, or PKCS#12 format).  The path must be UTF-8 encoded;
  *   use g_filename_to_utf8() to convert if needed.  Passing NULL with any
@@ -1608,7 +1608,7 @@ nm_setting_802_1x_get_phase2_private_key_path (NMSetting8021x *setting)
  **/
 gboolean
 nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self,
-                                          const char *value,
+                                          const char *key_path,
                                           const char *password,
                                           NMSetting8021xCKScheme scheme,
                                           NMSetting8021xCKFormat *out_format,
@@ -1619,8 +1619,8 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self,
 
 	g_return_val_if_fail (NM_IS_SETTING_802_1X (self), FALSE);
 
-	if (value) {
-		g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
+	if (key_path) {
+		g_return_val_if_fail (g_utf8_validate (key_path, -1, NULL), FALSE);
 		g_return_val_if_fail (   scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB
 		                      || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH,
 		                      FALSE);
@@ -1632,8 +1632,8 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self,
 	/* Ensure the private key is a recognized format and if the password was
 	 * given, that it decrypts the private key.
 	 */
-	if (value) {
-		format = crypto_verify_private_key (value, password, NULL);
+	if (key_path) {
+		format = crypto_verify_private_key (key_path, password, NULL);
 		if (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN) {
 			g_set_error (error,
 				         NM_SETTING_802_1X_ERROR,
@@ -1656,16 +1656,16 @@ nm_setting_802_1x_set_phase2_private_key (NMSetting8021x *self,
 	g_free (priv->phase2_private_key_password);
 	priv->phase2_private_key_password = NULL;
 
-	if (value == NULL)
+	if (key_path == NULL)
 		return TRUE;
 
 	priv->phase2_private_key_password = g_strdup (password);
 	if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
 		/* Shouldn't fail this since we just verified the private key above */
-		priv->phase2_private_key = file_to_byte_array (value);
+		priv->phase2_private_key = file_to_byte_array (key_path);
 		g_assert (priv->phase2_private_key);
 	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH)
-		priv->phase2_private_key = path_to_scheme_value (value);
+		priv->phase2_private_key = path_to_scheme_value (key_path);
 	else
 		g_assert_not_reached ();
 
diff --git a/libnm-util/nm-setting-8021x.h b/libnm-util/nm-setting-8021x.h
index bf587a90..f3e61e55 100644
--- a/libnm-util/nm-setting-8021x.h
+++ b/libnm-util/nm-setting-8021x.h
@@ -174,7 +174,7 @@ NMSetting8021xCKScheme nm_setting_802_1x_get_ca_cert_scheme          (NMSetting8
 const GByteArray *     nm_setting_802_1x_get_ca_cert_blob            (NMSetting8021x *setting);
 const char *           nm_setting_802_1x_get_ca_cert_path            (NMSetting8021x *setting);
 gboolean               nm_setting_802_1x_set_ca_cert                 (NMSetting8021x *setting,
-                                                                      const char *value,
+                                                                      const char *cert_path,
                                                                       NMSetting8021xCKScheme scheme,
                                                                       NMSetting8021xCKFormat *out_format,
                                                                       GError **error);
@@ -183,7 +183,7 @@ NMSetting8021xCKScheme nm_setting_802_1x_get_client_cert_scheme      (NMSetting8
 const GByteArray *     nm_setting_802_1x_get_client_cert_blob        (NMSetting8021x *setting);
 const char *           nm_setting_802_1x_get_client_cert_path        (NMSetting8021x *setting);
 gboolean               nm_setting_802_1x_set_client_cert             (NMSetting8021x *setting,
-                                                                      const char *value,
+                                                                      const char *cert_path,
                                                                       NMSetting8021xCKScheme scheme,
                                                                       NMSetting8021xCKFormat *out_format,
                                                                       GError **error);
@@ -202,7 +202,7 @@ NMSetting8021xCKScheme nm_setting_802_1x_get_phase2_ca_cert_scheme   (NMSetting8
 const GByteArray *     nm_setting_802_1x_get_phase2_ca_cert_blob     (NMSetting8021x *setting);
 const char *           nm_setting_802_1x_get_phase2_ca_cert_path     (NMSetting8021x *setting);
 gboolean               nm_setting_802_1x_set_phase2_ca_cert          (NMSetting8021x *setting,
-                                                                      const char *value,
+                                                                      const char *cert_path,
                                                                       NMSetting8021xCKScheme scheme,
                                                                       NMSetting8021xCKFormat *out_format,
                                                                       GError **error);
@@ -211,7 +211,7 @@ NMSetting8021xCKScheme nm_setting_802_1x_get_phase2_client_cert_scheme   (NMSett
 const GByteArray *     nm_setting_802_1x_get_phase2_client_cert_blob     (NMSetting8021x *setting);
 const char *           nm_setting_802_1x_get_phase2_client_cert_path     (NMSetting8021x *setting);
 gboolean               nm_setting_802_1x_set_phase2_client_cert          (NMSetting8021x *setting,
-                                                                          const char *value,
+                                                                          const char *cert_path,
                                                                           NMSetting8021xCKScheme scheme,
                                                                           NMSetting8021xCKFormat *out_format,
                                                                           GError **error);
@@ -226,7 +226,7 @@ NMSetting8021xCKScheme nm_setting_802_1x_get_private_key_scheme          (NMSett
 const GByteArray *     nm_setting_802_1x_get_private_key_blob            (NMSetting8021x *setting);
 const char *           nm_setting_802_1x_get_private_key_path            (NMSetting8021x *setting);
 gboolean               nm_setting_802_1x_set_private_key                 (NMSetting8021x *setting,
-                                                                          const char *value,
+                                                                          const char *key_path,
                                                                           const char *password,
                                                                           NMSetting8021xCKScheme scheme,
                                                                           NMSetting8021xCKFormat *out_format,
@@ -240,7 +240,7 @@ NMSetting8021xCKScheme nm_setting_802_1x_get_phase2_private_key_scheme   (NMSett
 const GByteArray *     nm_setting_802_1x_get_phase2_private_key_blob     (NMSetting8021x *setting);
 const char *           nm_setting_802_1x_get_phase2_private_key_path     (NMSetting8021x *setting);
 gboolean               nm_setting_802_1x_set_phase2_private_key          (NMSetting8021x *setting,
-                                                                          const char *value,
+                                                                          const char *key_path,
                                                                           const char *password,
                                                                           NMSetting8021xCKScheme scheme,
                                                                           NMSetting8021xCKFormat *out_format,
diff --git a/libnm-util/nm-setting-gsm.c b/libnm-util/nm-setting-gsm.c
index a1b7a6d3..0ece448b 100644
--- a/libnm-util/nm-setting-gsm.c
+++ b/libnm-util/nm-setting-gsm.c
@@ -241,10 +241,28 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
 		}
 
 		/* APNs roughly follow the same rules as DNS domain names.  Allowed
-		 * characters are a-z, 0-9, . and -.  GSM 03.60 Section 14.9.
+		 * characters are a-z, 0-9, . and -.  GSM 03.03 Section 9.1 states:
+		 *
+		 *   The syntax of the APN shall follow the Name Syntax defined in
+		 *   RFC 2181 [14] and RFC 1035 [15]. The APN consists of one or
+		 *   more labels. Each label is coded as one octet length field
+		 *   followed by that number of octets coded as 8 bit ASCII characters.
+		 *   Following RFC 1035 [15] the labels should consist only of the
+		 *   alphabetic characters (A-Z and a-z), digits (0-9) and the
+		 *   dash (-). The case of alphabetic characters is not significant.
+		 *
+		 * A dot (.) is commonly used to separate parts of the APN, and
+		 * apparently the underscore (_) is used as well.  RFC 2181 indicates
+		 * that no restrictions of any kind are placed on DNS labels, and thus
+		 * it would appear that none are placed on APNs either, but many modems
+		 * and networks will fail to accept APNs that include odd characters
+		 * like space ( ) and such.
 		 */
 		for (i = 0; i < apn_len; i++) {
-			if (!isalnum (priv->apn[i]) && (priv->apn[i] != '.') && (priv->apn[i] != '-')) {
+			if (   !isalnum (priv->apn[i])
+			    && (priv->apn[i] != '.')
+			    && (priv->apn[i] != '_')
+			    && (priv->apn[i] != '-')) {
 				g_set_error (error,
 				             NM_SETTING_GSM_ERROR,
 				             NM_SETTING_GSM_ERROR_INVALID_PROPERTY,
diff --git a/libnm-util/nm-setting-vpn.c b/libnm-util/nm-setting-vpn.c
index d3aac030..23f07383 100644
--- a/libnm-util/nm-setting-vpn.c
+++ b/libnm-util/nm-setting-vpn.c
@@ -161,23 +161,55 @@ nm_setting_vpn_remove_data_item (NMSettingVPN *setting, const char *key)
 	g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->data, key);
 }
 
+static void
+foreach_item_helper (GHashTable *hash,
+                     NMVPNIterFunc func,
+                     gpointer user_data)
+{
+	GList *keys, *liter;
+	GSList *copied = NULL, *siter;
+
+	g_return_if_fail (hash != NULL);
+
+	/* Grab keys and copy them so that the callback func can modify
+	 * the hash table items if it wants to.
+	 */
+	keys = g_hash_table_get_keys (hash);
+	for (liter = keys; liter; liter = g_list_next (liter))
+		copied = g_slist_prepend (copied, g_strdup (liter->data));
+	copied = g_slist_reverse (copied);
+	g_list_free (keys);
+
+	for (siter = copied; siter; siter = g_slist_next (siter)) {
+		gpointer value;
+
+		value = g_hash_table_lookup (hash, siter->data);
+		func (siter->data, value, user_data);
+	}
+
+	g_slist_foreach (copied, (GFunc) g_free, NULL);
+	g_slist_free (copied);
+}
+
 /**
  * nm_setting_vpn_foreach_data_item:
  * @setting: a #NMSettingVPN
  * @func: (scope call): an user provided function
  * @user_data: data to be passed to @func
  *
- * Iterates all data items stored in this setting
+ * Iterates all data items stored in this setting.  It is safe to add, remove,
+ * and modify data items inside @func, though any additions or removals made
+ * during iteration will not be part of the iteration.
  */
 void
 nm_setting_vpn_foreach_data_item (NMSettingVPN *setting,
                                   NMVPNIterFunc func,
                                   gpointer user_data)
 {
+	g_return_if_fail (setting != NULL);
 	g_return_if_fail (NM_IS_SETTING_VPN (setting));
 
-	g_hash_table_foreach (NM_SETTING_VPN_GET_PRIVATE (setting)->data,
-	                      (GHFunc) func, user_data);
+	foreach_item_helper (NM_SETTING_VPN_GET_PRIVATE (setting)->data, func, user_data);
 }
 
 void
@@ -217,17 +249,19 @@ nm_setting_vpn_remove_secret (NMSettingVPN *setting, const char *key)
  * @func: (scope call): an user provided function
  * @user_data: data to be passed to @func
  *
- * Iterates all secrets stored in this setting.
+ * Iterates all secrets stored in this setting.  It is safe to add, remove,
+ * and modify secrets inside @func, though any additions or removals made during
+ * iteration will not be part of the iteration.
  */
 void
 nm_setting_vpn_foreach_secret (NMSettingVPN *setting,
                                NMVPNIterFunc func,
                                gpointer user_data)
 {
+	g_return_if_fail (setting != NULL);
 	g_return_if_fail (NM_IS_SETTING_VPN (setting));
 
-	g_hash_table_foreach (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets,
-	                      (GHFunc) func, user_data);
+	foreach_item_helper (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, func, user_data);
 }
 
 static gboolean
@@ -377,7 +411,8 @@ get_secret_flags (NMSetting *setting,
 		errno = 0;
 		tmp = strtoul ((const char *) val, NULL, 10);
 		if ((errno == 0) && (tmp <= NM_SETTING_SECRET_FLAGS_ALL)) {
-			*out_flags = (guint32) tmp;
+			if (out_flags)
+				*out_flags = (guint32) tmp;
 			success = TRUE;
 		} else {
 			g_set_error (error,
diff --git a/libnm-util/nm-setting.c b/libnm-util/nm-setting.c
index 0f8b7d4f..3fe90db2 100644
--- a/libnm-util/nm-setting.c
+++ b/libnm-util/nm-setting.c
@@ -112,9 +112,10 @@ destroy_gvalue (gpointer data)
  *
  * Converts the #NMSetting into a #GHashTable mapping each setting property
  * name to a GValue describing that property, suitable for marshalling over
- * D-Bus or serializing.  The mapping is string:GValue.
+ * D-Bus or serializing.  The mapping is string to GValue.
  * 
- * Returns: (transfer full) (element-type utf8 GObject.Value): a new #GHashTable describing the setting's properties
+ * Returns: (transfer full) (element-type utf8 GObject.Value): a new #GHashTable
+ * describing the setting's properties
  **/
 GHashTable *
 nm_setting_to_hash (NMSetting *setting, NMSettingHashFlags flags)
@@ -209,8 +210,8 @@ one_property_cb (gpointer key, gpointer val, gpointer user_data)
 /**
  * nm_setting_new_from_hash:
  * @setting_type: the #NMSetting type which the hash contains properties for
- * @hash: the #GHashTable containing a string:GValue mapping of properties
- * that apply to the setting
+ * @hash: (element-type utf8 GObject.Value): the #GHashTable containing a
+ * string to GValue mapping of properties that apply to the setting
  *
  * Creates a new #NMSetting object and populates that object with the properties
  * contained in the hash table, using each hash key as the property to set,
@@ -223,8 +224,7 @@ one_property_cb (gpointer key, gpointer val, gpointer user_data)
  * hash table, or NULL on failure
  **/
 NMSetting *
-nm_setting_new_from_hash (GType setting_type,
-                          GHashTable *hash)
+nm_setting_new_from_hash (GType setting_type, GHashTable *hash)
 {
 	NMSetting *setting;
 	NMSettingFromHashInfo info;
@@ -421,10 +421,11 @@ nm_setting_compare (NMSetting *a,
  * @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
  * @invert_results: this parameter is used internally by libnm-util and should
  * be set to %FALSE.  If %TRUE inverts the meaning of the #NMSettingDiffResult.
- * @results: (element-type utf8 guint32): if the settings differ, on return a
- * hash table mapping the differing keys to one or more #NMSettingDiffResult
- * values OR-ed together.  If the settings do not differ, any hash table passed
- * in is unmodified.  If no hash table is passed in, a new one is created.
+ * @results: (inout) (transfer full) (element-type utf8 guint32): if the
+ * settings differ, on return a hash table mapping the differing keys to one or
+ * more %NMSettingDiffResult values OR-ed together.  If the settings do not
+ * differ, any hash table passed in is unmodified.  If no hash table is passed
+ * in and the settings differ, a new one is created and returned.
  *
  * Compares two #NMSetting objects for similarity, with comparison behavior
  * modified by a set of flags.  See the documentation for #NMSettingCompareFlags
@@ -661,8 +662,8 @@ update_one_secret (NMSetting *setting, const char *key, GValue *value, GError **
 /**
  * nm_setting_update_secrets:
  * @setting: the #NMSetting
- * @secrets: a #GHashTable mapping string:#GValue of setting property names and
- * secrets
+ * @secrets: (element-type utf8 GObject.Value): a #GHashTable mapping
+ * string to #GValue of setting property names and secrets
  * @error: location to store error, or %NULL
  *
  * Update the setting's secrets, given a hash table of secrets intended for that
diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c
index bac7fda3..449deb1c 100644
--- a/libnm-util/nm-utils.c
+++ b/libnm-util/nm-utils.c
@@ -534,7 +534,7 @@ _nm_utils_string_slist_validate (GSList *list, const char **valid_values)
 }
 
 static void
-nm_utils_convert_strv_to_slist (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_strv_to_slist (const GValue *src_value, GValue *dest_value)
 {
 	char **str;
 	GSList *list = NULL;
@@ -551,7 +551,7 @@ nm_utils_convert_strv_to_slist (const GValue *src_value, GValue *dest_value)
 }
 
 static void
-nm_utils_convert_strv_to_ptrarray (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_strv_to_ptrarray (const GValue *src_value, GValue *dest_value)
 {
 	char **str;
 	GPtrArray *array = NULL;
@@ -569,7 +569,7 @@ nm_utils_convert_strv_to_ptrarray (const GValue *src_value, GValue *dest_value)
 }
 
 static void
-nm_utils_convert_strv_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_strv_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GSList *strings;
 	GString *printable;
@@ -595,7 +595,7 @@ nm_utils_convert_strv_to_string (const GValue *src_value, GValue *dest_value)
 }
 
 static void
-nm_utils_convert_string_array_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_string_array_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GPtrArray *strings;
 	GString *printable;
@@ -621,7 +621,7 @@ nm_utils_convert_string_array_to_string (const GValue *src_value, GValue *dest_v
 }
 
 static void
-nm_utils_convert_uint_array_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_uint_array_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GArray *array;
 	GString *printable;
@@ -653,7 +653,7 @@ nm_utils_convert_uint_array_to_string (const GValue *src_value, GValue *dest_val
 }
 
 static void
-nm_utils_convert_ip4_addr_route_struct_array_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_ip4_addr_route_struct_array_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GPtrArray *ptr_array;
 	GString *printable;
@@ -738,7 +738,7 @@ convert_one_gvalue_hash_entry (gpointer key, gpointer value, gpointer user_data)
 }
 
 static void
-nm_utils_convert_gvalue_hash_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_gvalue_hash_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GHashTable *hash;
 	GString *printable;
@@ -764,7 +764,7 @@ convert_one_string_hash_entry (gpointer key, gpointer value, gpointer user_data)
 }
 
 static void
-nm_utils_convert_string_hash_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_string_hash_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GHashTable *hash;
 	GString *printable;
@@ -783,7 +783,7 @@ nm_utils_convert_string_hash_to_string (const GValue *src_value, GValue *dest_va
 }
 
 static void
-nm_utils_convert_byte_array_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_byte_array_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GArray *array;
 	GString *printable;
@@ -811,7 +811,7 @@ nm_utils_convert_byte_array_to_string (const GValue *src_value, GValue *dest_val
 }
 
 static gboolean
-nm_utils_inet6_ntop (struct in6_addr *addr, char *buf)
+_nm_utils_inet6_ntop (struct in6_addr *addr, char *buf)
 {
 	if (!inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN)) {
 		int i;
@@ -828,7 +828,7 @@ nm_utils_inet6_ntop (struct in6_addr *addr, char *buf)
 }
 
 static void
-nm_utils_convert_ip6_dns_array_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_ip6_dns_array_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GPtrArray *ptr_array;
 	GString *printable;
@@ -854,7 +854,7 @@ nm_utils_convert_ip6_dns_array_to_string (const GValue *src_value, GValue *dest_
 		}
 		addr = (struct in6_addr *) bytearray->data;
 		memset (buf, 0, sizeof (buf));
-		nm_utils_inet6_ntop (addr, buf);
+		_nm_utils_inet6_ntop (addr, buf);
 		g_string_append_printf (printable, "%s", buf);
 	}
 	g_string_append_c (printable, ']');
@@ -864,7 +864,7 @@ nm_utils_convert_ip6_dns_array_to_string (const GValue *src_value, GValue *dest_
 }
 
 static void
-nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GPtrArray *ptr_array;
 	GString *printable;
@@ -905,7 +905,7 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu
 		}
 		addr = (struct in6_addr *) ba_addr->data;
 		memset (buf, 0, sizeof (buf));
-		nm_utils_inet6_ntop (addr, buf);
+		_nm_utils_inet6_ntop (addr, buf);
 		g_string_append_printf (printable, "ip = %s", buf);
 		g_string_append (printable, ", ");
 
@@ -928,7 +928,7 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu
 		}
 		addr = (struct in6_addr *) ba_addr->data;
 		memset (buf, 0, sizeof (buf));
-		nm_utils_inet6_ntop (addr, buf);
+		_nm_utils_inet6_ntop (addr, buf);
 		g_string_append_printf (printable, "gw = %s", buf);
 		g_string_append (printable, " }");
 	}
@@ -939,7 +939,7 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu
 }
 
 static void
-nm_utils_convert_ip6_route_struct_array_to_string (const GValue *src_value, GValue *dest_value)
+_nm_utils_convert_ip6_route_struct_array_to_string (const GValue *src_value, GValue *dest_value)
 {
 	GPtrArray *ptr_array;
 	GString *printable;
@@ -981,7 +981,7 @@ nm_utils_convert_ip6_route_struct_array_to_string (const GValue *src_value, GVal
 		}
 		addr = (struct in6_addr *) ba_addr->data;
 		memset (buf, 0, sizeof (buf));
-		nm_utils_inet6_ntop (addr, buf);
+		_nm_utils_inet6_ntop (addr, buf);
 		g_string_append_printf (printable, "dst = %s", buf);
 		g_string_append (printable, ", ");
 
@@ -1004,7 +1004,7 @@ nm_utils_convert_ip6_route_struct_array_to_string (const GValue *src_value, GVal
 		}
 		addr = (struct in6_addr *) ba_addr->data;
 		memset (buf, 0, sizeof (buf));
-		nm_utils_inet6_ntop (addr, buf);
+		_nm_utils_inet6_ntop (addr, buf);
 		g_string_append_printf (printable, "nh = %s", buf);
 		g_string_append (printable, ", ");
 
@@ -1025,7 +1025,7 @@ nm_utils_convert_ip6_route_struct_array_to_string (const GValue *src_value, GVal
 #define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS))
 
 static void
-nm_utils_convert_old_ip6_addr_array (const GValue *src_value, GValue *dst_value)
+_nm_utils_convert_old_ip6_addr_array (const GValue *src_value, GValue *dst_value)
 {
 	GPtrArray *src_outer_array;
 	GPtrArray *dst_outer_array;
@@ -1081,43 +1081,43 @@ _nm_utils_register_value_transformations (void)
 	if (G_UNLIKELY (!registered)) {
 		g_value_register_transform_func (G_TYPE_STRV, 
 		                                 DBUS_TYPE_G_LIST_OF_STRING,
-		                                 nm_utils_convert_strv_to_slist);
+		                                 _nm_utils_convert_strv_to_slist);
 		g_value_register_transform_func (G_TYPE_STRV,
 		                                 DBUS_TYPE_G_ARRAY_OF_STRING,
-		                                 nm_utils_convert_strv_to_ptrarray);
+		                                 _nm_utils_convert_strv_to_ptrarray);
 		g_value_register_transform_func (DBUS_TYPE_G_LIST_OF_STRING,
 		                                 G_TYPE_STRING, 
-		                                 nm_utils_convert_strv_to_string);
+		                                 _nm_utils_convert_strv_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_ARRAY_OF_STRING,
 		                                 G_TYPE_STRING,
-		                                 nm_utils_convert_string_array_to_string);
+		                                 _nm_utils_convert_string_array_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_UINT_ARRAY,
 		                                 G_TYPE_STRING, 
-		                                 nm_utils_convert_uint_array_to_string);
+		                                 _nm_utils_convert_uint_array_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT,
 		                                 G_TYPE_STRING, 
-		                                 nm_utils_convert_ip4_addr_route_struct_array_to_string);
+		                                 _nm_utils_convert_ip4_addr_route_struct_array_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_MAP_OF_VARIANT,
 		                                 G_TYPE_STRING, 
-		                                 nm_utils_convert_gvalue_hash_to_string);
+		                                 _nm_utils_convert_gvalue_hash_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_MAP_OF_STRING,
 		                                 G_TYPE_STRING, 
-		                                 nm_utils_convert_string_hash_to_string);
+		                                 _nm_utils_convert_string_hash_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_UCHAR_ARRAY,
 		                                 G_TYPE_STRING,
-		                                 nm_utils_convert_byte_array_to_string);
+		                                 _nm_utils_convert_byte_array_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR,
 		                                 G_TYPE_STRING, 
-		                                 nm_utils_convert_ip6_dns_array_to_string);
+		                                 _nm_utils_convert_ip6_dns_array_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
 		                                 G_TYPE_STRING, 
-		                                 nm_utils_convert_ip6_addr_struct_array_to_string);
+		                                 _nm_utils_convert_ip6_addr_struct_array_to_string);
 		g_value_register_transform_func (DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE,
 		                                 G_TYPE_STRING, 
-		                                 nm_utils_convert_ip6_route_struct_array_to_string);
+		                                 _nm_utils_convert_ip6_route_struct_array_to_string);
 		g_value_register_transform_func (OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
 		                                 DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
-		                                 nm_utils_convert_old_ip6_addr_array);
+		                                 _nm_utils_convert_old_ip6_addr_array);
 		registered = TRUE;
 	}
 }
diff --git a/libnm-util/nm-utils.h b/libnm-util/nm-utils.h
index c3eb29bc..e4714a96 100644
--- a/libnm-util/nm-utils.h
+++ b/libnm-util/nm-utils.h
@@ -27,7 +27,6 @@
 #define NM_UTILS_H
 
 #include <glib.h>
-#include <execinfo.h>
 
 #include "nm-connection.h"
 
diff --git a/libnm-util/tests/Makefile.am b/libnm-util/tests/Makefile.am
index daf4d688..1d737d1a 100644
--- a/libnm-util/tests/Makefile.am
+++ b/libnm-util/tests/Makefile.am
@@ -84,6 +84,9 @@ check-local: test-settings-defaults test-crypto test-secrets
 # Private key by itself (PEM)
 	$(abs_builddir)/test-setting-8021x $(srcdir)/certs/test-key-only.pem "test"
 
+# PKCS#8 private key by itself (PEM)
+	$(abs_builddir)/test-setting-8021x $(srcdir)/certs/pkcs8-enc-key.pem "1234567890"
+
 # Private key and CA certificate in the same file (pkcs12)
 	$(abs_builddir)/test-setting-8021x $(srcdir)/certs/test-cert.p12 "test"
 
@@ -126,5 +129,10 @@ check-local: test-settings-defaults test-crypto test-secrets
 # Another PKCS#12 file
 	$(abs_builddir)/test-crypto --p12 $(srcdir)/certs/test2-cert.p12 "12345testing"
 
+# PKCS#8 encrypted private key
+	$(abs_builddir)/test-crypto --pkcs8 \
+		$(srcdir)/certs/pkcs8-enc-key.pem \
+		"1234567890"
+
 endif
 
diff --git a/libnm-util/tests/Makefile.in b/libnm-util/tests/Makefile.in
index 9e65094c..c4919ffc 100644
--- a/libnm-util/tests/Makefile.in
+++ b/libnm-util/tests/Makefile.in
@@ -941,6 +941,9 @@ uninstall-am:
 # Private key by itself (PEM)
 @WITH_TESTS_TRUE@	$(abs_builddir)/test-setting-8021x $(srcdir)/certs/test-key-only.pem "test"
 
+# PKCS#8 private key by itself (PEM)
+@WITH_TESTS_TRUE@	$(abs_builddir)/test-setting-8021x $(srcdir)/certs/pkcs8-enc-key.pem "1234567890"
+
 # Private key and CA certificate in the same file (pkcs12)
 @WITH_TESTS_TRUE@	$(abs_builddir)/test-setting-8021x $(srcdir)/certs/test-cert.p12 "test"
 
@@ -983,6 +986,11 @@ uninstall-am:
 # Another PKCS#12 file
 @WITH_TESTS_TRUE@	$(abs_builddir)/test-crypto --p12 $(srcdir)/certs/test2-cert.p12 "12345testing"
 
+# PKCS#8 encrypted private key
+@WITH_TESTS_TRUE@	$(abs_builddir)/test-crypto --pkcs8 \
+@WITH_TESTS_TRUE@		$(srcdir)/certs/pkcs8-enc-key.pem \
+@WITH_TESTS_TRUE@		"1234567890"
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
diff --git a/libnm-util/tests/certs/Makefile.am b/libnm-util/tests/certs/Makefile.am
index 02d5a5f5..e0f00a47 100644
--- a/libnm-util/tests/certs/Makefile.am
+++ b/libnm-util/tests/certs/Makefile.am
@@ -17,5 +17,8 @@ EXTRA_DIST = \
 	test2-cert.p12 \
 	ca-no-ending-newline.pem \
 	test-key-only.pem \
-	test-key-only-decrypted.der
+	test-key-only-decrypted.der \
+	pkcs8-enc-key.pem \
+	pkcs8-noenc-key.pem \
+	pkcs8-decrypted.der
 
diff --git a/libnm-util/tests/certs/Makefile.in b/libnm-util/tests/certs/Makefile.in
index 873218e8..5149078b 100644
--- a/libnm-util/tests/certs/Makefile.in
+++ b/libnm-util/tests/certs/Makefile.in
@@ -287,7 +287,10 @@ EXTRA_DIST = \
 	test2-cert.p12 \
 	ca-no-ending-newline.pem \
 	test-key-only.pem \
-	test-key-only-decrypted.der
+	test-key-only-decrypted.der \
+	pkcs8-enc-key.pem \
+	pkcs8-noenc-key.pem \
+	pkcs8-decrypted.der
 
 all: all-am
 
diff --git a/libnm-util/tests/certs/pkcs8-decrypted.der b/libnm-util/tests/certs/pkcs8-decrypted.der
new file mode 100644
index 00000000..2cbdeb5e
--- /dev/null
+++ b/libnm-util/tests/certs/pkcs8-decrypted.der
Binary files differdiff --git a/libnm-util/tests/certs/pkcs8-enc-key.pem b/libnm-util/tests/certs/pkcs8-enc-key.pem
new file mode 100644
index 00000000..0d08f2d2
--- /dev/null
+++ b/libnm-util/tests/certs/pkcs8-enc-key.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQMwDgQIwiGFT4Jz6RsCAggABIIEyJNMddDYofbhydUp
+J3VyrYIjv3LziJ7dkTXE3+mEYRCQrGLgljWBbib2JOLVCFt8melL6Yv1RcoVR7X7
+vrRqyycu0DumI4f5+Bf4wc234JNVhSaLYsw244fFtcnK2Gyn4IaVmWmrNvrwfX/w
+SKcVmO30D5C5PCKzv2bou5FmnJLKdDQV1t816cr9T8pTx7MHvBzSZXbh86334BhF
+T3zNwo8j2/+Gq2NBWUn+2GTTV8/r26aIwPcFi4QH6I2ghBwFmFHqU3/PoRm6nkmg
+CqJj2Dggy+8zE5qg0iId7lrio0OjCH+Qed6NGwIa2lgv/bhuJVP3FOk4gqamJWHi
+WMaq9McmS+03q2iokYeSQGbx85x+I90RTFZKhFx4dkerf6oTC/YoL4F++ff0e91v
+sOrQsBkgRhrRtFwa9OFCzbsknlixONdd+ITkyX490xz1wcZTDkKtMDRLIPWa2O0b
+MEq75jPYThZ5pF1vc5r+rqPafN7SfI+DDmhzJYEQNRoCWA4pH9Gwv0ayKnOgoj4K
+TuFhXvcyWzTnVXmcqEFyf3CRrB0Ti+Z61enupC+FCuYV5lGsx9kJaTumTk2UPD02
+9Ap3asDLozdEPSXBG3+oCM2s01/IJlxtR84C97r9rpmWTc9K6DCBScETe9KnIghW
+PU7XFogueG5Gwpe+x+IlTDq+qiyUNVX1uMGDcIaCC3VsoWqZrpnGGBhsovwBaXKt
+T9fT2nE27Fd6DRWso4fgos6PPx7RVveu17BTMVQeUq9L8GrV4JNrE3a9aoXdbUhc
+6gMiyAqxh/HEyciYoXsR9oVNi+VM0y8q3hL5nIcgDrCZr/c9aQ8+fuQBDXRrmrQd
+bR2iwNLCBnbmQmM/vM333VhJ4MSOKd3SGw/j41K+Nr3uP5KRZUwV+5yy3ef/hGxU
+i9JjCmSUt2bfWRUFlNaf1hCTYaKD0xnVr1SLFU4snIgh2qKawyqVc9EE2f+FcOM5
+0RtwQ3ku6FOk3cy6/xeKpResCHbWDS6nQaIKYyLukV+gm5MJIhOMkj2z4T1eXGUr
+Nu/L7Gz+ps7ct0lM8W82n5lzSEa5/l1eNGM0wtQoAwutFEZp7Nx/IBKK87jVttr6
+82UVJeRk7rO2Mpobfw2LbKwga4rsuLrx3UwVDBWdLx7dNIc1rGoAxhsc72+skFgF
+Uztwy4Yv1Uiji4T6v+mObPZD/HiIDL0vF02Pz08rNlgB0DgaTKrpql2FutIuQAdf
+AciffQIoh9VGERlJoWuunG/UTxg2XRl2m1vCDrgBMInax+PXCv7/5Vh21AQc3fWP
+uf4k6JSy46hYni7VTVKn6C/Di9z7oIrGl/jDkDsaenAbToyX9VWr3s7EBwnhTQ/I
+OQ9bkWCagHIQlwJbu4M4/VAbiR26NrcR0C3JXBlPlT0qvFFB8gKbJAQEXtwIFS2h
+m2fe0k6mQASMwdbJYXZ/wfsg5PPAWsKtny1aMvi0mTPSD5uRhIfEGEuR+AT4UbEW
+BkEIE0lgGly4P1SpunKDQQE6m/e7h8Nl4pi8SMSme3YoX5MJwCP/CNkLBDVenAZI
+oBrdoVox86SjwnUozVG192lcEAULlk+3ZGt6T9JXLBQl9hpNtyTC6SFh84R+5RoN
+AevNl1bDfO+Vci0uJw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/libnm-util/tests/certs/pkcs8-noenc-key.pem b/libnm-util/tests/certs/pkcs8-noenc-key.pem
new file mode 100644
index 00000000..f73fb55a
--- /dev/null
+++ b/libnm-util/tests/certs/pkcs8-noenc-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC80HGgFdlFIL2F
+W5rHQ99xOkMrWcZ7an9YurDebAE3M0UwqxM24+5mWbxc8FJ8yYugdMzuI5Nq77IA
+DwJpv9ZjMfnKC1VDMj3bmmMdPurfx8pLdLw/jhk3wBaYk6vMvh4z66Yvmb7valGq
+Pxh6CRTnekNGI9XA7me4JNBlisl0Qasn9g4pl9PiGJAruEamS4Pk6dSWbfw58bs7
+/Yo5ejyt/Mn1n0Q/r3Gv/lAS0qRvmrW6GE1rMtANMfuGRNlAln21TzNcJzykm+sp
+RWptxXEI0NY7u9+RP4M3C1mJxWir7AZDbtinpOZH6vF+92yMzgEYOLK/WZVdSPdW
+tROv9xtPAgMBAAECggEBAJAfp+vjYZJjuGaYEuAxjdhW+biYcWn5U7V9484TsSXa
+i+DnZOZMO8iCjMaAZuZ7zYmwPlE0dK12w29KBbSEy3eySRIRboa5TgBXq3pCcXRZ
+g6/vLlZw+AzXIiha6BODt3g4UwUYnWcQx79lJCDa18sNR1a9ucbn8+Har/wiYT3M
+JjTbUT6wR6rKEXchB58ZugYGhOTfugSDQg4U/dwEHPIaJ/wme++JUV5B/tjeGCG3
+F43o2Oos5vjfrDSpUKIYZn+2BdhP434jkwj22wQ2sy0ruU/kQx8nogMTRfP1v4GU
+9QmNXj/DB24K388ZxcDmcxBJxrGAJ0MohYFo28DqRBECgYEA6hyKEqe2UbJx/+B6
+8mYgHb+pS2j0M4jPl11q9MMLVxLnDY9xZ85IEyWHQEC0GavPSAois0oiDeGAm32c
+j6TFyV3/oPTmZSyV93/agWgnH9Xtc481pbNAb0GMfyotvRRE/+6ti9+Cl7oH9Qmm
+ldMk7Hn6sK9t2mUOW8idPjKqlqcCgYEAzne25BryLJoIinbRMZg9KTfxfgUE6EKc
+Tk5+9CFQn0/AItQJuKbIUyggYH4psWW5hWq6hFlmMYMR48FKv9ry7pZTB0djaoYD
+lN+wSuhzUYWXedkAjvPmekITmf6rbnPfwOZvsr8CGMEUekqJPnPLzsQy+Ea2y/fb
+QY4SHe7gExkCgYEAr+1scOJpZvFjK7ckjT3jipd6ADpJsORxo7zG4FImFnQU/6K4
+xRpGHWVJQyaccOIkrW04cGUYPDgmrjJx0ZwwKceijvEaphMgS1JgAHklVY4sl3ea
+CAAxPqoSi4lFv94Yj/9rmT4IZD6fNivfbJ20FKUBl37tXX4tkRmr2I64lOcCgYEA
+x3eqzrclrmdlxvfBZOuScwbkHP6WXhk0TwbQ6eRhsnfmxP8bITSoJoaGuRJKD2Oa
+l0WkSobgDwd0uhecsrvBpTS/pDGY32n3fdWZyNTHzEOHMyWtv23tBcJek5ERaBU0
+X3WBBiw4x1eKBBeMfjR6+xhbsbcHlQiw36V05UxJWMkCgYEAhtcYvrfU4K48IJTU
+qp03nvd+dMY3IUTdZNOCh8bswLKyn3aq3MfWF9Vp7kDAI3cfyMpSrAQnmg4nVcn6
+Gf3wakG8bpiSRbJnGN+iLm8JsD+3Vw9KzvKOOQVmpT7xt5Kupx1hWvLHQWvfYgOG
+qEtTM8/+LD7W3I7midJNt50CD8A=
+-----END PRIVATE KEY-----
diff --git a/libnm-util/tests/test-crypto.c b/libnm-util/tests/test-crypto.c
index 6cfb6ac2..57e39fca 100644
--- a/libnm-util/tests/test-crypto.c
+++ b/libnm-util/tests/test-crypto.c
@@ -239,6 +239,29 @@ test_is_pkcs12 (const char *path, gboolean expect_fail, const char *desc)
 }
 
 static void
+test_load_pkcs8 (const char *path,
+                 const char *password,
+                 gboolean expect_fail,
+                 const char *desc)
+{
+	NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN;
+	GError *error = NULL;
+
+	format = crypto_verify_private_key (path, password, &error);
+	if (expect_fail) {
+		ASSERT (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN, desc,
+		        "unexpected success reading PKCS#8 private key file "
+		        "'%s' with invalid password",
+		        path);
+	} else {
+		ASSERT (format == NM_CRYPTO_FILE_FORMAT_RAW_KEY, desc,
+			    "%s: unexpected PKCS#8 private key file format (expected %d, got "
+			    "%d): %d %s",
+			    path, NM_CRYPTO_FILE_FORMAT_RAW_KEY, format, error->code, error->message);
+	}
+}
+
+static void
 test_encrypt_private_key (const char *path,
                           const char *password,
                           const char *desc)
@@ -316,6 +339,17 @@ int main (int argc, char **argv)
 		test_load_pkcs12 (argv[2], argv[3], FALSE, "pkcs12-private-key");
 		test_load_pkcs12 (argv[2], "blahblahblah", TRUE, "pkcs12-private-key-bad-password");
 		test_load_pkcs12_no_password (argv[2], "pkcs12-private-key-no-password");
+	} else if (!strcmp (argv[1], "--pkcs8")) {
+		ASSERT (argc == 4, "test-crypto",
+		        "wrong number of arguments (--pkcs8 <key file> <password>)");
+
+		test_is_pkcs12 (argv[2], TRUE, "not-pkcs12");
+		test_load_pkcs8 (argv[2], argv[3], FALSE, "pkcs8-private-key");
+		/* Until gnutls and NSS grow support for all the ciphers that openssl
+		 * can use with PKCS#8, we can't actually verify the password.  So we
+		 * expect a bad password to work for the time being.
+		 */
+		test_load_pkcs8 (argv[2], "blahblahblah", FALSE, "pkcs8-private-key-bad-password");
 	} else {
 		ASSERT (argc > 2, "test-crypto", "unknown test type (not --cert, --key, or --p12)");
 	}
diff --git a/libnm-util/tests/test-general.c b/libnm-util/tests/test-general.c
index 1ce80622..87a50d67 100644
--- a/libnm-util/tests/test-general.c
+++ b/libnm-util/tests/test-general.c
@@ -195,6 +195,75 @@ test_setting_vpn_update_secrets (void)
 	g_object_unref (connection);
 }
 
+#define TO_DEL_NUM 50
+typedef struct {
+	NMSettingVPN *s_vpn;
+	char *to_del[TO_DEL_NUM];
+	guint called;
+} IterInfo;
+
+static void
+del_iter_func (const char *key, const char *value, gpointer user_data)
+{
+	IterInfo *info = user_data;
+	int i;
+
+	/* Record how many times this function gets called; it should get called
+	 * exactly as many times as there are keys in the hash table, regardless
+	 * of what keys we delete from the table.
+	 */
+	info->called++;
+
+	/* During the iteration, remove a bunch of stuff from the table */
+	if (info->called == 1) {
+		for (i = 0; i < TO_DEL_NUM; i++)
+			nm_setting_vpn_remove_data_item (info->s_vpn, info->to_del[i]);
+	}
+}
+
+static void
+test_setting_vpn_modify_during_foreach (void)
+{
+	NMSettingVPN *s_vpn;
+	IterInfo info;
+	char *key, *val;
+	int i, u = 0;
+
+	s_vpn = (NMSettingVPN *) nm_setting_vpn_new ();
+	g_assert (s_vpn);
+
+	for (i = 0; i < TO_DEL_NUM * 2; i++) {
+		key = g_strdup_printf ("adsfasdfadf%d", i);
+		val = g_strdup_printf ("42263236236awt%d", i);
+		nm_setting_vpn_add_data_item (s_vpn, key, val);
+
+		/* Cache some keys to delete */
+		if (i % 2)
+			info.to_del[u++] = g_strdup (key);
+
+		g_free (key);
+		g_free (val);
+	}
+
+	/* Iterate over current table keys */
+	info.s_vpn = s_vpn;
+	info.called = 0;
+	nm_setting_vpn_foreach_data_item (s_vpn, del_iter_func, &info);
+
+	/* Make sure all the things we removed during iteration are really gone */
+	for (i = 0; i < TO_DEL_NUM; i++) {
+		g_assert_cmpstr (nm_setting_vpn_get_data_item (s_vpn, info.to_del[i]), ==, NULL);
+		g_free (info.to_del[i]);
+	}
+
+	/* And make sure the foreach callback was called the same number of times
+	 * as there were keys in the table at the beginning of the foreach.
+	 */
+	g_assert_cmpint (info.called, ==, TO_DEL_NUM * 2);
+
+	g_object_unref (s_vpn);
+}
+
 #define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
 #define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS))
 
@@ -354,6 +423,25 @@ test_setting_gsm_apn_bad_chars (void)
 	        "gsm-apn-bad-chars", "unexpectedly valid GSM setting");
 }
 
+static void
+test_setting_gsm_apn_underscore (void)
+{
+	NMSettingGsm *s_gsm;
+	GError *error = NULL;
+	gboolean success;
+
+	s_gsm = (NMSettingGsm *) nm_setting_gsm_new ();
+	g_assert (s_gsm);
+
+	g_object_set (s_gsm, NM_SETTING_GSM_NUMBER, "*99#", NULL);
+
+	/* 65-character long */
+	g_object_set (s_gsm, NM_SETTING_GSM_APN, "foobar_baz", NULL);
+	success = nm_setting_verify (NM_SETTING (s_gsm), NULL, &error);
+	g_assert_no_error (error);
+	g_assert (success == TRUE);
+}
+
 static NMSettingWirelessSecurity *
 make_test_wsec_setting (const char *detail)
 {
@@ -1132,9 +1220,11 @@ int main (int argc, char **argv)
 	/* The tests */
 	test_setting_vpn_items ();
 	test_setting_vpn_update_secrets ();
+	test_setting_vpn_modify_during_foreach ();
 	test_setting_ip6_config_old_address_array ();
 	test_setting_gsm_apn_spaces ();
 	test_setting_gsm_apn_bad_chars ();
+	test_setting_gsm_apn_underscore ();
 	test_setting_to_hash_all ();
 	test_setting_to_hash_no_secrets ();
 	test_setting_to_hash_only_secrets ();