File nm-probe-radius-server-cert.patch of Package NetworkManager

From 17b0c482034e11f350c5470505cbb23f25582c96 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <chingpang@gmail.com>
Date: Wed, 18 Jul 2012 12:14:56 +0800
Subject: [PATCH 1/4] libnm-util: allow the server hash to be the CA
 certificate

---
 libnm-util/libnm-util.ver                      |  1 +
 libnm-util/nm-setting-8021x.c                  | 54 +++++++++++++++++-
 libnm-util/nm-setting-8021x.h                  |  6 +-
 src/settings/plugins/ifnet/connection_parser.c | 76 +++++++++++++++++++++-----
 src/settings/plugins/keyfile/reader.c          |  7 +++
 src/settings/plugins/keyfile/writer.c          | 14 ++++-
 6 files changed, 139 insertions(+), 19 deletions(-)

diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver
index 04f2a91..1ac871c 100644
--- a/libnm-util/libnm-util.ver
+++ b/libnm-util/libnm-util.ver
@@ -118,6 +118,7 @@ global:
 	nm_setting_802_1x_get_anonymous_identity;
 	nm_setting_802_1x_get_ca_cert_blob;
 	nm_setting_802_1x_get_ca_cert_path;
+	nm_setting_802_1x_get_ca_cert_hash;
 	nm_setting_802_1x_get_ca_cert_scheme;
 	nm_setting_802_1x_get_ca_path;
 	nm_setting_802_1x_get_client_cert_blob;
diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c
index 0a9a210..8e2dcdc 100644
--- a/libnm-util/nm-setting-8021x.c
+++ b/libnm-util/nm-setting-8021x.c
@@ -63,6 +63,7 @@
  **/
 
 #define SCHEME_PATH "file://"
+#define SCHEME_HASH "hash://server/sha256/"
 
 /**
  * nm_setting_802_1x_error_quark:
@@ -392,6 +393,9 @@ get_cert_scheme (GByteArray *array)
 	if (   (array->len > strlen (SCHEME_PATH))
 	    && !memcmp (array->data, SCHEME_PATH, strlen (SCHEME_PATH)))
 		return NM_SETTING_802_1X_CK_SCHEME_PATH;
+	else if (   (array->len > strlen (SCHEME_HASH))
+	         && !memcmp (array->data, SCHEME_HASH, strlen (SCHEME_HASH)))
+		return NM_SETTING_802_1X_CK_SCHEME_HASH;
 
 	return NM_SETTING_802_1X_CK_SCHEME_BLOB;
 }
@@ -402,7 +406,8 @@ get_cert_scheme (GByteArray *array)
  *
  * Returns the scheme used to store the CA certificate.  If the returned scheme
  * is %NM_SETTING_802_1X_CK_SCHEME_BLOB, use nm_setting_802_1x_get_ca_cert_blob();
- * if %NM_SETTING_802_1X_CK_SCHEME_PATH, use nm_setting_802_1x_get_ca_cert_path().
+ * if %NM_SETTING_802_1X_CK_SCHEME_PATH, use nm_setting_802_1x_get_ca_cert_path();
+ * if %NM_SETTING_802_1X_CK_SCHEME_HASH, use nm_setting_802_1x_get_ca_cert_hash().
  *
  * Returns: scheme used to store the CA certificate (blob or path)
  **/
@@ -466,6 +471,32 @@ nm_setting_802_1x_get_ca_cert_path (NMSetting8021x *setting)
 	return (const char *) (NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert->data + strlen (SCHEME_PATH));
 }
 
+/**
+ * nm_setting_802_1x_get_ca_cert_hash:
+ * @setting: the #NMSetting8021x
+ *
+ * Returns the CA certificate path if the CA certificate is stored using the
+ * %NM_SETTING_802_1X_CK_SCHEME_HASH scheme.  Not all EAP methods use a
+ * CA certificate (LEAP for example), and those that can take advantage of the
+ * CA certificate allow it to be unset.  Note that lack of a CA certificate
+ * reduces security by allowing man-in-the-middle attacks, because the identity
+ * of the network cannot be confirmed by the client.
+ *
+ * Returns: hash of the RADIUS server
+ **/
+const char *
+nm_setting_802_1x_get_ca_cert_hash (NMSetting8021x *setting)
+{
+	NMSetting8021xCKScheme scheme;
+
+	g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL);
+
+	scheme = nm_setting_802_1x_get_ca_cert_scheme (setting);
+	g_return_val_if_fail (scheme == NM_SETTING_802_1X_CK_SCHEME_HASH, NULL);
+
+	return (const char *) (NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert->data);
+}
+
 static GByteArray *
 path_to_scheme_value (const char *path)
 {
@@ -517,7 +548,8 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *self,
 	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,
+		                      || scheme == NM_SETTING_802_1X_CK_SCHEME_PATH
+		                      || scheme == NM_SETTING_802_1X_CK_SCHEME_HASH,
 		                      FALSE);
 	}
 
@@ -535,6 +567,17 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *self,
 	if (!cert_path)
 		return TRUE;
 
+	if (scheme == NM_SETTING_802_1X_CK_SCHEME_HASH) {
+		int length = strlen (cert_path);
+		if (   length == (strlen (SCHEME_HASH) + 64)
+		    && !g_str_has_prefix (cert_path, SCHEME_HASH))
+			return FALSE;
+		data = g_byte_array_sized_new (length + 1);
+		g_byte_array_append (data, (guint8 *) cert_path, length + 1);
+		priv->ca_cert = data;
+		return TRUE;
+	}
+
 	data = crypto_load_and_verify_certificate (cert_path, &format, error);
 	if (data) {
 		/* wpa_supplicant can only use raw x509 CA certs */
@@ -2426,6 +2469,13 @@ verify_cert (GByteArray *array, const char *prop_name, GError **error)
 				return TRUE;
 		}
 		break;
+	case NM_SETTING_802_1X_CK_SCHEME_HASH:
+		/* For hash-based schemes, verify that the has is zero-terminated */
+		if (array->data[array->len - 1] == '\0') {
+			if (g_str_has_prefix ((char *)array->data, SCHEME_HASH))
+				return TRUE;
+		}
+		break;
 	default:
 		break;
 	}
diff --git a/libnm-util/nm-setting-8021x.h b/libnm-util/nm-setting-8021x.h
index 8381fed..6f9ecf1 100644
--- a/libnm-util/nm-setting-8021x.h
+++ b/libnm-util/nm-setting-8021x.h
@@ -57,6 +57,8 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_ck_format >*/
  * item data
  * @NM_SETTING_802_1X_CK_SCHEME_PATH: certificate or key is stored as a path
  * to a file containing the certificate or key data
+ * @NM_SETTING_802_1X_CK_SCHEME_HASH: certificate or key is stored as a path
+ * of the CA server hash
  *
  * #NMSetting8021xCKScheme values indicate how a certificate or private key is
  * stored in the setting properties, either as a blob of the item's data, or as
@@ -65,7 +67,8 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_ck_format >*/
 typedef enum { /*< underscore_name=nm_setting_802_1x_ck_scheme >*/
 	NM_SETTING_802_1X_CK_SCHEME_UNKNOWN = 0,
 	NM_SETTING_802_1X_CK_SCHEME_BLOB,
-	NM_SETTING_802_1X_CK_SCHEME_PATH
+	NM_SETTING_802_1X_CK_SCHEME_PATH,
+	NM_SETTING_802_1X_CK_SCHEME_HASH
 } NMSetting8021xCKScheme;
 
 
@@ -185,6 +188,7 @@ const char *      nm_setting_802_1x_get_phase2_ca_path               (NMSetting8
 NMSetting8021xCKScheme nm_setting_802_1x_get_ca_cert_scheme          (NMSetting8021x *setting);
 const GByteArray *     nm_setting_802_1x_get_ca_cert_blob            (NMSetting8021x *setting);
 const char *           nm_setting_802_1x_get_ca_cert_path            (NMSetting8021x *setting);
+const char *           nm_setting_802_1x_get_ca_cert_hash            (NMSetting8021x *setting);
 gboolean               nm_setting_802_1x_set_ca_cert                 (NMSetting8021x *setting,
                                                                       const char *cert_path,
                                                                       NMSetting8021xCKScheme scheme,
diff --git a/src/settings/plugins/ifnet/connection_parser.c b/src/settings/plugins/ifnet/connection_parser.c
index c85b5c4..8372806 100644
--- a/src/settings/plugins/ifnet/connection_parser.c
+++ b/src/settings/plugins/ifnet/connection_parser.c
@@ -44,6 +44,8 @@
 #include "connection_parser.h"
 #include "nm-ifnet-connection.h"
 
+#define SCHEME_HASH "hash://server/sha256/"
+
 static void
 update_connection_id (NMConnection *connection, const char *conn_name)
 {
@@ -206,11 +208,18 @@ eap_tls_reader (const char *eap_method,
 								   NULL, error))
 				goto done;
 		} else {
-			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
-							    ca_cert,
-							    NM_SETTING_802_1X_CK_SCHEME_PATH,
-							    NULL, error))
-				goto done;
+			if (g_str_has_prefix (ca_cert, SCHEME_HASH))
+				if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+								    ca_cert,
+								    NM_SETTING_802_1X_CK_SCHEME_HASH,
+								    NULL, error))
+					goto done;
+			else
+				if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+								    ca_cert,
+								    NM_SETTING_802_1X_CK_SCHEME_PATH,
+								    NULL, error))
+					goto done;
 		}
 	} else {
 		PLUGIN_WARN (IFNET_PLUGIN_NAME,
@@ -317,11 +326,18 @@ eap_peap_reader (const char *eap_method,
 
 	ca_cert = get_cert (ssid, "ca_cert", basepath);
 	if (ca_cert) {
-		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
-						    ca_cert,
-						    NM_SETTING_802_1X_CK_SCHEME_PATH,
-						    NULL, error))
-			goto done;
+		if (g_str_has_prefix (ca_cert, SCHEME_HASH))
+			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+							    ca_cert,
+							    NM_SETTING_802_1X_CK_SCHEME_HASH,
+							    NULL, error))
+				goto done;
+		else
+			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+							    ca_cert,
+							    NM_SETTING_802_1X_CK_SCHEME_PATH,
+							    NULL, error))
+				goto done;
 	} else {
 		PLUGIN_WARN (IFNET_PLUGIN_NAME, "    warning: missing "
 			     "IEEE_8021X_CA_CERT for EAP method '%s'; this is"
@@ -420,11 +436,18 @@ eap_ttls_reader (const char *eap_method,
 	/* ca cert */
 	ca_cert = get_cert (ssid, "ca_cert", basepath);
 	if (ca_cert) {
-		if (!nm_setting_802_1x_set_ca_cert (s_8021x,
-						    ca_cert,
-						    NM_SETTING_802_1X_CK_SCHEME_PATH,
-						    NULL, error))
-			goto done;
+		if (g_str_has_prefix (ca_cert, SCHEME_HASH))
+			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+							    ca_cert,
+							    NM_SETTING_802_1X_CK_SCHEME_HASH,
+							    NULL, error))
+				goto done;
+		else
+			if (!nm_setting_802_1x_set_ca_cert (s_8021x,
+							    ca_cert,
+							    NM_SETTING_802_1X_CK_SCHEME_PATH,
+							    NULL, error))
+				goto done;
 	} else {
 		PLUGIN_WARN (IFNET_PLUGIN_NAME, "    warning: missing "
 			     "IEEE_8021X_CA_CERT for EAP method '%s'; this is"
@@ -1774,12 +1797,14 @@ error:
 
 typedef NMSetting8021xCKScheme (*SchemeFunc) (NMSetting8021x * setting);
 typedef const char *(*PathFunc) (NMSetting8021x * setting);
+typedef const char *(*HashFunc) (NMSetting8021x * setting);
 typedef const GByteArray *(*BlobFunc) (NMSetting8021x * setting);
 
 typedef struct ObjectType {
 	const char *setting_key;
 	SchemeFunc scheme_func;
 	PathFunc path_func;
+	HashFunc hash_func;
 	BlobFunc blob_func;
 	const char *conn_name_key;
 	const char *suffix;
@@ -1789,6 +1814,7 @@ static const ObjectType ca_type = {
 	NM_SETTING_802_1X_CA_CERT,
 	nm_setting_802_1x_get_ca_cert_scheme,
 	nm_setting_802_1x_get_ca_cert_path,
+	nm_setting_802_1x_get_ca_cert_hash,
 	nm_setting_802_1x_get_ca_cert_blob,
 	"ca_cert",
 	"ca-cert.der"
@@ -1798,6 +1824,7 @@ static const ObjectType phase2_ca_type = {
 	NM_SETTING_802_1X_PHASE2_CA_CERT,
 	nm_setting_802_1x_get_phase2_ca_cert_scheme,
 	nm_setting_802_1x_get_phase2_ca_cert_path,
+	NULL,
 	nm_setting_802_1x_get_phase2_ca_cert_blob,
 	"ca_cert2",
 	"inner-ca-cert.der"
@@ -1807,6 +1834,7 @@ static const ObjectType client_type = {
 	NM_SETTING_802_1X_CLIENT_CERT,
 	nm_setting_802_1x_get_client_cert_scheme,
 	nm_setting_802_1x_get_client_cert_path,
+	NULL,
 	nm_setting_802_1x_get_client_cert_blob,
 	"client_cert",
 	"client-cert.der"
@@ -1816,6 +1844,7 @@ static const ObjectType phase2_client_type = {
 	NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
 	nm_setting_802_1x_get_phase2_client_cert_scheme,
 	nm_setting_802_1x_get_phase2_client_cert_path,
+	NULL,
 	nm_setting_802_1x_get_phase2_client_cert_blob,
 	"client_cert2",
 	"inner-client-cert.der"
@@ -1825,6 +1854,7 @@ static const ObjectType pk_type = {
 	NM_SETTING_802_1X_PRIVATE_KEY,
 	nm_setting_802_1x_get_private_key_scheme,
 	nm_setting_802_1x_get_private_key_path,
+	NULL,
 	nm_setting_802_1x_get_private_key_blob,
 	"private_key",
 	"private-key.pem"
@@ -1834,6 +1864,7 @@ static const ObjectType phase2_pk_type = {
 	NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
 	nm_setting_802_1x_get_phase2_private_key_scheme,
 	nm_setting_802_1x_get_phase2_private_key_path,
+	NULL,
 	nm_setting_802_1x_get_phase2_private_key_blob,
 	"private_key2",
 	"inner-private-key.pem"
@@ -1843,6 +1874,7 @@ static const ObjectType p12_type = {
 	NM_SETTING_802_1X_PRIVATE_KEY,
 	nm_setting_802_1x_get_private_key_scheme,
 	nm_setting_802_1x_get_private_key_path,
+	NULL,
 	nm_setting_802_1x_get_private_key_blob,
 	"private_key",
 	"private-key.p12"
@@ -1852,6 +1884,7 @@ static const ObjectType phase2_p12_type = {
 	NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
 	nm_setting_802_1x_get_phase2_private_key_scheme,
 	nm_setting_802_1x_get_phase2_private_key_path,
+	NULL,
 	nm_setting_802_1x_get_phase2_private_key_blob,
 	"private_key2",
 	"inner-private-key.p12"
@@ -1866,6 +1899,7 @@ write_object (NMSetting8021x *s_8021x,
 {
 	NMSetting8021xCKScheme scheme;
 	const char *path = NULL;
+	const char *hash = NULL;
 	const GByteArray *blob = NULL;
 
 	g_return_val_if_fail (conn_name != NULL, FALSE);
@@ -1884,6 +1918,9 @@ write_object (NMSetting8021x *s_8021x,
 		case NM_SETTING_802_1X_CK_SCHEME_PATH:
 			path = (*(objtype->path_func)) (s_8021x);
 			break;
+		case NM_SETTING_802_1X_CK_SCHEME_HASH:
+			hash = (*(objtype->hash_func)) (s_8021x);
+			break;
 		default:
 			break;
 		}
@@ -1898,6 +1935,15 @@ write_object (NMSetting8021x *s_8021x,
 		return TRUE;
 	}
 
+	/* If the object hash was specified, prefer that over any raw cert data that
+	 * may have been sent.
+	 */
+	if (hash) {
+		wpa_set_data (conn_name, (gchar *) objtype->conn_name_key,
+			      (gchar *) hash);
+		return TRUE;
+	}
+
 	/* does not support writing encryption data now */
 	if (blob) {
 		PLUGIN_WARN (IFNET_PLUGIN_NAME,
diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c
index ec4661e..9df23eb 100644
--- a/src/settings/plugins/keyfile/reader.c
+++ b/src/settings/plugins/keyfile/reader.c
@@ -703,6 +703,7 @@ get_cert_path (const char *keyfile_path, GByteArray *cert_path)
 }
 
 #define SCHEME_PATH "file://"
+#define SCHEME_HASH "hash://server/sha256/"
 
 static const char *certext[] = { ".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key" };
 
@@ -727,6 +728,12 @@ handle_as_scheme (GByteArray *array, NMSetting *setting, const char *key)
 	    && (array->data[array->len - 1] == '\0')) {
 		g_object_set (setting, key, array, NULL);
 		return TRUE;
+	} else if (   (array->len > strlen (SCHEME_HASH))
+	           && g_str_has_prefix ((const char *) array->data, SCHEME_HASH)
+	           && (array->data[array->len - 1] == '\0')) {
+		/* It's the HASH scheme, can just set plain data */
+		g_object_set (setting, key, array, NULL);
+		return TRUE;
 	}
 	return FALSE;
 }
diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c
index 38061a5..7d3272c 100644
--- a/src/settings/plugins/keyfile/writer.c
+++ b/src/settings/plugins/keyfile/writer.c
@@ -548,6 +548,7 @@ typedef struct ObjectType {
 	NMSetting8021xCKScheme (*scheme_func) (NMSetting8021x *setting);
 	NMSetting8021xCKFormat (*format_func) (NMSetting8021x *setting);
 	const char *           (*path_func)   (NMSetting8021x *setting);
+	const char *           (*hash_func)   (NMSetting8021x *setting);
 	const GByteArray *     (*blob_func)   (NMSetting8021x *setting);
 } ObjectType;
 
@@ -558,6 +559,7 @@ static const ObjectType objtypes[10] = {
 	  nm_setting_802_1x_get_ca_cert_scheme,
 	  NULL,
 	  nm_setting_802_1x_get_ca_cert_path,
+	  nm_setting_802_1x_get_ca_cert_hash,
 	  nm_setting_802_1x_get_ca_cert_blob },
 
 	{ NM_SETTING_802_1X_PHASE2_CA_CERT,
@@ -566,6 +568,7 @@ static const ObjectType objtypes[10] = {
 	  nm_setting_802_1x_get_phase2_ca_cert_scheme,
 	  NULL,
 	  nm_setting_802_1x_get_phase2_ca_cert_path,
+	  NULL,
 	  nm_setting_802_1x_get_phase2_ca_cert_blob },
 
 	{ NM_SETTING_802_1X_CLIENT_CERT,
@@ -574,6 +577,7 @@ static const ObjectType objtypes[10] = {
 	  nm_setting_802_1x_get_client_cert_scheme,
 	  NULL,
 	  nm_setting_802_1x_get_client_cert_path,
+	  NULL,
 	  nm_setting_802_1x_get_client_cert_blob },
 
 	{ NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
@@ -582,6 +586,7 @@ static const ObjectType objtypes[10] = {
 	  nm_setting_802_1x_get_phase2_client_cert_scheme,
 	  NULL,
 	  nm_setting_802_1x_get_phase2_client_cert_path,
+	  NULL,
 	  nm_setting_802_1x_get_phase2_client_cert_blob },
 
 	{ NM_SETTING_802_1X_PRIVATE_KEY,
@@ -590,6 +595,7 @@ static const ObjectType objtypes[10] = {
 	  nm_setting_802_1x_get_private_key_scheme,
 	  nm_setting_802_1x_get_private_key_format,
 	  nm_setting_802_1x_get_private_key_path,
+	  NULL,
 	  nm_setting_802_1x_get_private_key_blob },
 
 	{ NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
@@ -598,6 +604,7 @@ static const ObjectType objtypes[10] = {
 	  nm_setting_802_1x_get_phase2_private_key_scheme,
 	  nm_setting_802_1x_get_phase2_private_key_format,
 	  nm_setting_802_1x_get_phase2_private_key_path,
+	  NULL,
 	  nm_setting_802_1x_get_phase2_private_key_blob },
 
 	{ NULL },
@@ -676,7 +683,7 @@ cert_writer (GKeyFile *file,
 	const char *setting_name = nm_setting_get_name (setting);
 	NMSetting8021xCKScheme scheme;
 	NMSetting8021xCKFormat format;
-	const char *path = NULL, *ext = "pem";
+	const char *path = NULL, *hash = NULL, *ext = "pem";
 	const ObjectType *objtype = NULL;
 	int i;
 
@@ -738,6 +745,11 @@ cert_writer (GKeyFile *file,
 			g_error_free (error);
 		}
 		g_free (new_path);
+	} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_HASH) {
+		hash = objtype->hash_func (NM_SETTING_802_1X (setting));
+		g_assert (hash);
+
+		g_key_file_set_string (file, setting_name, key, hash);
 	} else
 		g_assert_not_reached ();
 }
-- 
1.8.1.4


From dca713eb64d3e0914874a2f4b6e010bd8d6787c5 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <chingpang@gmail.com>
Date: Fri, 8 Feb 2013 11:23:15 +0800
Subject: [PATCH 2/4] wifi: add the dbus method to probe the certificate

---
 introspection/nm-device-wifi.xml                 | 23 ++++++
 src/nm-device-wifi.c                             | 99 ++++++++++++++++++++++++
 src/nm-device-wifi.h                             |  2 +
 src/supplicant-manager/nm-supplicant-config.c    | 24 ++++++
 src/supplicant-manager/nm-supplicant-config.h    |  2 +
 src/supplicant-manager/nm-supplicant-interface.c | 32 ++++++++
 src/supplicant-manager/nm-supplicant-interface.h |  4 +
 7 files changed, 186 insertions(+)

diff --git a/introspection/nm-device-wifi.xml b/introspection/nm-device-wifi.xml
index dcfa20c..25adcda 100644
--- a/introspection/nm-device-wifi.xml
+++ b/introspection/nm-device-wifi.xml
@@ -27,6 +27,18 @@
       </tp:docstring>
     </method>
 
+    <method name="ProbeCert">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_probe_cert"/>
+      <arg name="ssid" type="ay" direction="in">
+        <tp:docstring>
+          The SSID of the AP to be probed
+        </tp:docstring>
+      </arg>
+      <tp:docstring>
+        Probe the certificate of the RADIUS server.
+      </tp:docstring>
+    </method>
+
     <property name="HwAddress" type="s" access="read">
       <tp:docstring>
         The active hardware address of the device.
@@ -94,6 +106,17 @@
         </tp:docstring>
     </signal>
 
+    <signal name="CertReceived">
+      <arg name="cert" type="a{sv}" tp:type="String_Variant_Map">
+        <tp:docstring>
+          The certificate of the RADIUS server
+        </tp:docstring>
+      </arg>
+        <tp:docstring>
+            Emitted when wpa_supplicant replies the certificate of the RADIUS server.
+        </tp:docstring>
+    </signal>
+
     <tp:flags name="NM_802_11_DEVICE_CAP" type="u">
       <tp:docstring>
         Flags describing the capabilities of a wireless device.
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index 3ac34e7..7dd027f 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -60,10 +60,14 @@
 #include "nm-settings-connection.h"
 #include "nm-enum-types.h"
 #include "wifi-utils.h"
+#include "nm-dbus-glib-types.h"
 
 static gboolean impl_device_get_access_points (NMDeviceWifi *device,
                                                GPtrArray **aps,
                                                GError **err);
+static gboolean impl_device_probe_cert (NMDeviceWifi *device,
+                                        GByteArray *ssid,
+                                        GError **err);
 
 static void impl_device_request_scan (NMDeviceWifi *device,
                                       GHashTable *options,
@@ -104,6 +108,7 @@ enum {
 	HIDDEN_AP_FOUND,
 	PROPERTIES_CHANGED,
 	SCANNING_ALLOWED,
+	CERT_RECEIVED,
 
 	LAST_SIGNAL
 };
@@ -118,6 +123,7 @@ typedef struct Supplicant {
 
 	guint sig_ids[SUP_SIG_ID_LEN];
 	guint iface_error_id;
+	guint iface_cert_id;
 
 	/* Timeouts and idles */
 	guint iface_con_error_cb_id;
@@ -1876,6 +1882,89 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface,
 #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
 #define MAC_ARG(x) ((guint8*)(x))[0],((guint8*)(x))[1],((guint8*)(x))[2],((guint8*)(x))[3],((guint8*)(x))[4],((guint8*)(x))[5]
 
+static void
+supplicant_iface_certification_cb (NMSupplicantInterface * iface,
+                                   GHashTable *cert,
+                                   NMDeviceWifi * self)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	GValue *value;
+	const char *subject, *hash;
+	guint depth;
+
+	value = g_hash_table_lookup (cert, "depth");
+	if (!value || !G_VALUE_HOLDS_UINT(value)) {
+		nm_log_dbg (LOGD_WIFI_SCAN, "Depth was not set");
+		return;
+	}
+	depth = g_value_get_uint (value);
+
+	value = g_hash_table_lookup (cert, "subject");
+	if (!value || !G_VALUE_HOLDS_STRING(value))
+		return;
+	subject = g_value_get_string (value);
+
+	value = g_hash_table_lookup (cert, "cert_hash");
+	if (!value || !G_VALUE_HOLDS_STRING(value))
+		return;
+	hash = g_value_get_string (value);
+
+	nm_log_info (LOGD_WIFI_SCAN, "Got Server Certificate %u, subject %s, hash %s", depth, subject, hash);
+
+	if (depth != 0)
+		return;
+
+	g_signal_emit (self, signals[CERT_RECEIVED], 0, cert);
+
+	if (priv->supplicant.iface_cert_id > 0) {
+		g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_cert_id);
+		priv->supplicant.iface_cert_id = 0;
+	}
+
+	nm_supplicant_interface_disconnect (iface);
+}
+
+static gboolean
+impl_device_probe_cert (NMDeviceWifi *self,
+                        GByteArray *ssid,
+                        GError **err)
+{
+	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	NMSupplicantConfig *config = NULL;
+	guint id;
+	gboolean ret = FALSE;
+
+	config = nm_supplicant_config_new_probe (ssid);
+	if (!config)
+		goto error;
+
+	/* Hook up signal handler to capture certification signal */
+	id = g_signal_connect (priv->supplicant.iface,
+	                       "certification",
+	                       G_CALLBACK (supplicant_iface_certification_cb),
+	                       self);
+	priv->supplicant.iface_cert_id = id;
+
+	if (!nm_supplicant_interface_set_config (priv->supplicant.iface, config))
+		goto error;
+
+	ret = TRUE;
+
+error:
+	if (!ret) {
+		g_set_error_literal (err,
+		                     NM_WIFI_ERROR,
+		                     NM_WIFI_ERROR_INVALID_CERT_PROBE,
+		                     "Couldn't probe RADIUS server certificate");
+		if (priv->supplicant.iface_cert_id) {
+			g_signal_handler_disconnect (priv->supplicant.iface, priv->supplicant.iface_cert_id);
+			priv->supplicant.iface_cert_id = 0;
+		}
+	}
+
+	return ret;
+}
+
 /*
  * merge_scanned_ap
  *
@@ -3891,6 +3980,16 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
 		              _nm_marshal_BOOLEAN__VOID,
 		              G_TYPE_BOOLEAN, 0);
 
+	signals[CERT_RECEIVED] =
+		g_signal_new ("cert-received",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_FIRST,
+		              G_STRUCT_OFFSET (NMDeviceWifiClass, cert_received),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__BOXED,
+		              G_TYPE_NONE, 1,
+		              DBUS_TYPE_G_MAP_OF_VARIANT);
+
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), &dbus_glib_nm_device_wifi_object_info);
 
 	dbus_g_error_domain_register (NM_WIFI_ERROR, NULL, NM_TYPE_WIFI_ERROR);
diff --git a/src/nm-device-wifi.h b/src/nm-device-wifi.h
index 368d0b8..74484ae 100644
--- a/src/nm-device-wifi.h
+++ b/src/nm-device-wifi.h
@@ -49,6 +49,7 @@ typedef enum {
 	NM_WIFI_ERROR_SCAN_NOT_ALLOWED,            /*< nick=ScanNotAllowed >*/
 	NM_WIFI_ERROR_AP_MODE_UNSUPPORTED,         /*< nick=ApModeUnsupported >*/
 	NM_WIFI_ERROR_ADHOC_MODE_UNSUPPORTED,      /*< nick=AdhocModeUnsupported >*/
+	NM_WIFI_ERROR_INVALID_CERT_PROBE,          /*< nick=InvalidCertProbe >*/
 } NMWifiError;
 
 #define NM_DEVICE_WIFI_HW_ADDRESS          "hw-address"
@@ -86,6 +87,7 @@ struct _NMDeviceWifiClass
 	void (*hidden_ap_found)      (NMDeviceWifi *device, NMAccessPoint *ap);
 	void (*properties_changed)   (NMDeviceWifi *device, GHashTable *properties);
 	gboolean (*scanning_allowed) (NMDeviceWifi *device);
+	void (*cert_received)        (NMDeviceWifi *device, GHashTable *cert);
 };
 
 
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index f5fc154..8e7807c 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -174,6 +174,25 @@ nm_supplicant_config_add_option (NMSupplicantConfig *self,
 	return nm_supplicant_config_add_option_with_type (self, key, value, len, TYPE_INVALID, secret);
 }
 
+NMSupplicantConfig *
+nm_supplicant_config_new_probe (const GByteArray *ssid)
+{
+	NMSupplicantConfig *probe_config;
+
+	if (!ssid)
+		return NULL;
+
+	probe_config = (NMSupplicantConfig *)g_object_new (NM_TYPE_SUPPLICANT_CONFIG, NULL);
+
+	nm_supplicant_config_add_option (probe_config, "ssid", (char *)ssid->data, ssid->len, FALSE);
+	nm_supplicant_config_add_option (probe_config, "key_mgmt", "WPA-EAP", -1, FALSE);
+	nm_supplicant_config_add_option (probe_config, "eap", "TTLS PEAP TLS", -1, FALSE);
+	nm_supplicant_config_add_option (probe_config, "identity", " ", -1, FALSE);
+	nm_supplicant_config_add_option (probe_config, "ca_cert", "probe://", -1, FALSE);
+
+	return probe_config;
+}
+
 static gboolean
 nm_supplicant_config_add_blob (NMSupplicantConfig *self,
                                const char *key,
@@ -914,6 +933,11 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
 		if (!add_string_val (self, path, "ca_cert", FALSE, FALSE))
 			return FALSE;
 		break;
+	case NM_SETTING_802_1X_CK_SCHEME_HASH:
+		path = nm_setting_802_1x_get_ca_cert_hash (setting);
+		if (!add_string_val (self, path, "ca_cert", FALSE, FALSE))
+			return FALSE;
+		break;
 	default:
 		break;
 	}
diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h
index a8d3047..c0356c5 100644
--- a/src/supplicant-manager/nm-supplicant-config.h
+++ b/src/supplicant-manager/nm-supplicant-config.h
@@ -52,6 +52,8 @@ GType nm_supplicant_config_get_type (void);
 
 NMSupplicantConfig *nm_supplicant_config_new (void);
 
+NMSupplicantConfig *nm_supplicant_config_new_probe (const GByteArray *ssid);
+
 guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self);
 
 void nm_supplicant_config_set_ap_scan (NMSupplicantConfig *self,
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c
index 75450a0..99601b7 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -66,6 +66,7 @@ enum {
 	SCAN_DONE,           /* wifi scan is complete */
 	CONNECTION_ERROR,    /* an error occurred during a connection request */
 	CREDENTIALS_REQUEST, /* 802.1x identity or password requested */
+	CERTIFICATION,       /* a RADIUS server certificate was received */
 	LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -580,6 +581,17 @@ parse_capabilities (NMSupplicantInterface *self, GHashTable *props)
 }
 
 static void
+wpas_iface_got_certification (DBusGProxy *proxy,
+                              const GHashTable *cert_table,
+                              gpointer user_data)
+{
+	g_signal_emit (user_data,
+	               signals[CERTIFICATION],
+	               0,
+	               cert_table);
+}
+
+static void
 wpas_iface_properties_changed (DBusGProxy *proxy,
                                GHashTable *props,
                                gpointer user_data)
@@ -908,6 +920,18 @@ interface_add_done (NMSupplicantInterface *self, char *path)
 	                             self,
 	                             NULL);
 
+	dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED,
+                                           G_TYPE_NONE,
+	                                   DBUS_TYPE_G_MAP_OF_VARIANT,
+	                                   G_TYPE_INVALID);
+	dbus_g_proxy_add_signal (priv->iface_proxy, "Certification",
+	                         DBUS_TYPE_G_MAP_OF_VARIANT,
+                                 G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->iface_proxy, "Certification",
+	                             G_CALLBACK (wpas_iface_got_certification),
+	                             self,
+	                             NULL);
+
 	priv->props_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr),
 	                                               WPAS_DBUS_SERVICE,
 	                                               path,
@@ -1706,5 +1730,13 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass)
 		              NULL, NULL,
 		              _nm_marshal_VOID__STRING_STRING,
 		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
+	signals[CERTIFICATION] =
+		g_signal_new ("certification",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (NMSupplicantInterfaceClass, certification),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__BOXED,
+		              G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT);
 }
 
diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h
index 2f0233c..a6fe89b 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/nm-supplicant-interface.h
@@ -115,6 +115,10 @@ typedef struct {
 	void (*credentials_request) (NMSupplicantInterface *iface,
 	                             const char *field,
 	                             const char *message);
+
+	/* a RADIUS server certificate was received */
+	void (*certification) (NMSupplicantInterface * iface,
+	                       const GHashTable * ca_cert);
 } NMSupplicantInterfaceClass;
 
 
-- 
1.8.1.4


From 6ee4c2109cb5883a789bd002d7eb2918b155d7d9 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <chingpang@gmail.com>
Date: Fri, 8 Feb 2013 11:24:10 +0800
Subject: [PATCH 3/4] libnm-glib: add the function to probe the certificate

---
 libnm-glib/libnm-glib.ver   |  1 +
 libnm-glib/nm-device-wifi.c | 69 +++++++++++++++++++++++++++++++++++++++++++++
 libnm-glib/nm-device-wifi.h |  5 +++-
 3 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver
index b7d3321..762cab4 100644
--- a/libnm-glib/libnm-glib.ver
+++ b/libnm-glib/libnm-glib.ver
@@ -166,6 +166,7 @@ global:
 	nm_device_wifi_get_type;
 	nm_device_wifi_new;
 	nm_device_wifi_request_scan_simple;
+	nm_device_wifi_probe_cert;
 	nm_device_wimax_error_get_type;
 	nm_device_wimax_error_quark;
 	nm_device_wimax_get_active_nsp;
diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
index 47594a5..fbeef07 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -87,6 +87,7 @@ enum {
 enum {
 	ACCESS_POINT_ADDED,
 	ACCESS_POINT_REMOVED,
+	CERT_RECEIVED,
 
 	LAST_SIGNAL
 };
@@ -414,6 +415,49 @@ access_point_removed (NMObject *self_obj, NMObject *ap_obj)
 	g_signal_emit (self, signals[ACCESS_POINT_REMOVED], 0, ap);
 }
 
+/**
+ * nm_device_wifi_probe_cert:
+ * @device: a #NMDeviceWifi
+ * @ssid: the ssid of the AP to probe
+ *
+ * Probe the certificate of the RADIUS server
+ *
+ * Returns: if the probe is sent or not
+ **/
+gboolean
+nm_device_wifi_probe_cert (NMDeviceWifi *device,
+                           const GByteArray *ssid)
+{
+	NMDeviceWifiPrivate *priv;
+	GError *error = NULL;
+	gboolean ret;
+
+	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), FALSE);
+
+	priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
+
+	ret = dbus_g_proxy_call (priv->proxy, "ProbeCert", &error,
+				 DBUS_TYPE_G_UCHAR_ARRAY, ssid,
+				 G_TYPE_INVALID,
+				 G_TYPE_INVALID);
+
+	if (!ret) {
+		g_warning ("%s: error probe certificate: %s", __func__, error->message);
+		g_error_free (error);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+cert_received_proxy (DBusGProxy *proxy, GHashTable *cert, gpointer user_data)
+{
+	NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
+
+	g_signal_emit (self, signals[CERT_RECEIVED], 0, cert);
+}
+
 static void
 clean_up_aps (NMDeviceWifi *self, gboolean notify)
 {
@@ -667,6 +711,13 @@ constructed (GObject *object)
 											nm_object_get_path (NM_OBJECT (object)),
 											NM_DBUS_INTERFACE_DEVICE_WIRELESS);
 
+	dbus_g_proxy_add_signal (priv->proxy, "CertReceived",
+	                         DBUS_TYPE_G_MAP_OF_VARIANT,
+	                         G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (priv->proxy, "CertReceived",
+						    G_CALLBACK (cert_received_proxy),
+						    object, NULL);
+
 	register_properties (NM_DEVICE_WIFI (object));
 
 	g_signal_connect (NM_DEVICE (object),
@@ -843,4 +894,22 @@ nm_device_wifi_class_init (NMDeviceWifiClass *wifi_class)
 				    g_cclosure_marshal_VOID__OBJECT,
 				    G_TYPE_NONE, 1,
 				    G_TYPE_OBJECT);
+
+	/**
+	 * NMDeviceWifi::cert-received:
+	 * @device: the wifi device that received the signal
+	 * @subject: the subject of the RADIUS server
+	 * @hash: the hash of the RADIUS server
+	 *
+	 * Notifies that a certificate of a RADIUS server is received.
+	 **/
+	signals[CERT_RECEIVED] =
+		g_signal_new ("cert-received",
+				    G_OBJECT_CLASS_TYPE (object_class),
+				    G_SIGNAL_RUN_FIRST,
+				    G_STRUCT_OFFSET (NMDeviceWifiClass, cert_received),
+				    NULL, NULL,
+				    g_cclosure_marshal_VOID__BOXED,
+				    G_TYPE_NONE, 1,
+				    G_TYPE_HASH_TABLE);
 }
diff --git a/libnm-glib/nm-device-wifi.h b/libnm-glib/nm-device-wifi.h
index 76d76b4..1b2ede3 100644
--- a/libnm-glib/nm-device-wifi.h
+++ b/libnm-glib/nm-device-wifi.h
@@ -78,6 +78,7 @@ typedef struct {
 	/* Signals */
 	void (*access_point_added) (NMDeviceWifi *device, NMAccessPoint *ap);
 	void (*access_point_removed) (NMDeviceWifi *device, NMAccessPoint *ap);
+	void (*cert_received) (NMDeviceWifi *device, GHashTable *cert);
 
 	/* Padding for future expansion */
 	void (*_reserved1) (void);
@@ -85,7 +86,6 @@ typedef struct {
 	void (*_reserved3) (void);
 	void (*_reserved4) (void);
 	void (*_reserved5) (void);
-	void (*_reserved6) (void);
 } NMDeviceWifiClass;
 
 GType nm_device_wifi_get_type (void);
@@ -111,6 +111,9 @@ void                     nm_device_wifi_request_scan_simple      (NMDeviceWifi *
                                                                   NMDeviceWifiRequestScanFn callback,
                                                                   gpointer user_data);
 
+gboolean                 nm_device_wifi_probe_cert               (NMDeviceWifi *device,
+                                                                  const GByteArray *ssid);
+
 G_END_DECLS
 
 #endif /* NM_DEVICE_WIFI_H */
-- 
1.8.1.4


From a367e7fd56710e7d75fa39665442156b2aec2b12 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <chingpang@gmail.com>
Date: Thu, 25 Apr 2013 11:13:52 +0800
Subject: [PATCH 4/4] wifi: Probe the Radius server with the user credential

Some servers do not accept anonymous probe.
---
 introspection/nm-device-wifi.xml              |  4 ++--
 libnm-glib/nm-device-wifi.c                   | 14 +++++++++---
 libnm-glib/nm-device-wifi.h                   |  2 +-
 src/nm-device-wifi.c                          | 33 +++++++++++++++++++++++----
 src/supplicant-manager/nm-supplicant-config.c | 31 +++++++++++++++++++++----
 src/supplicant-manager/nm-supplicant-config.h |  3 ++-
 6 files changed, 72 insertions(+), 15 deletions(-)

diff --git a/introspection/nm-device-wifi.xml b/introspection/nm-device-wifi.xml
index 25adcda..a1776ed 100644
--- a/introspection/nm-device-wifi.xml
+++ b/introspection/nm-device-wifi.xml
@@ -29,9 +29,9 @@
 
     <method name="ProbeCert">
       <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_probe_cert"/>
-      <arg name="ssid" type="ay" direction="in">
+      <arg name="settings" type="a{sa{sv}}" direction="in">
         <tp:docstring>
-          The SSID of the AP to be probed
+          Connection settings and properties
         </tp:docstring>
       </arg>
       <tp:docstring>
diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
index fbeef07..95021ca 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -418,7 +418,7 @@ access_point_removed (NMObject *self_obj, NMObject *ap_obj)
 /**
  * nm_device_wifi_probe_cert:
  * @device: a #NMDeviceWifi
- * @ssid: the ssid of the AP to probe
+ * @partial: the connection settings and properties
  *
  * Probe the certificate of the RADIUS server
  *
@@ -426,21 +426,29 @@ access_point_removed (NMObject *self_obj, NMObject *ap_obj)
  **/
 gboolean
 nm_device_wifi_probe_cert (NMDeviceWifi *device,
-                           const GByteArray *ssid)
+                           NMConnection *partial)
 {
 	NMDeviceWifiPrivate *priv;
+	GHashTable *hash = NULL;
 	GError *error = NULL;
 	gboolean ret;
 
 	g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), FALSE);
+	g_return_val_if_fail (partial, FALSE);
 
 	priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
 
+	hash = nm_connection_to_hash (partial, NM_SETTING_HASH_FLAG_ALL);
+	if (hash == NULL)
+		return FALSE;
+
 	ret = dbus_g_proxy_call (priv->proxy, "ProbeCert", &error,
-				 DBUS_TYPE_G_UCHAR_ARRAY, ssid,
+				 DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash,
 				 G_TYPE_INVALID,
 				 G_TYPE_INVALID);
 
+	g_hash_table_unref (hash);
+
 	if (!ret) {
 		g_warning ("%s: error probe certificate: %s", __func__, error->message);
 		g_error_free (error);
diff --git a/libnm-glib/nm-device-wifi.h b/libnm-glib/nm-device-wifi.h
index 1b2ede3..df41ab3 100644
--- a/libnm-glib/nm-device-wifi.h
+++ b/libnm-glib/nm-device-wifi.h
@@ -112,7 +112,7 @@ void                     nm_device_wifi_request_scan_simple      (NMDeviceWifi *
                                                                   gpointer user_data);
 
 gboolean                 nm_device_wifi_probe_cert               (NMDeviceWifi *device,
-                                                                  const GByteArray *ssid);
+                                                                  NMConnection *partial);
 
 G_END_DECLS
 
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index 7dd027f..305966d 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -66,7 +66,7 @@ static gboolean impl_device_get_access_points (NMDeviceWifi *device,
                                                GPtrArray **aps,
                                                GError **err);
 static gboolean impl_device_probe_cert (NMDeviceWifi *device,
-                                        GByteArray *ssid,
+                                        GHashTable *settings,
                                         GError **err);
 
 static void impl_device_request_scan (NMDeviceWifi *device,
@@ -1926,16 +1926,38 @@ supplicant_iface_certification_cb (NMSupplicantInterface * iface,
 
 static gboolean
 impl_device_probe_cert (NMDeviceWifi *self,
-                        GByteArray *ssid,
+                        GHashTable *settings,
                         GError **err)
 {
 	NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+	NMConnection *connection;
+	NMSettingWireless *setting_wifi;
+	const GByteArray *ssid;
+	NMSetting8021x *setting_8021x;
 	NMSupplicantConfig *config = NULL;
 	guint id;
 	gboolean ret = FALSE;
 
-	config = nm_supplicant_config_new_probe (ssid);
-	if (!config)
+	if (!settings)
+		goto error;
+
+	connection = nm_connection_new ();
+	nm_connection_replace_settings (connection, settings, NULL);
+
+	setting_wifi = nm_connection_get_setting_wireless (connection);
+	if (setting_wifi == NULL)
+		goto error;
+
+	ssid = nm_setting_wireless_get_ssid (setting_wifi);
+	if (ssid == NULL)
+		goto error;
+
+	setting_8021x = nm_connection_get_setting_802_1x (connection);
+	if (setting_8021x == NULL)
+		goto error;
+
+	config = nm_supplicant_config_new_probe (ssid, setting_8021x);
+	if (config == NULL)
 		goto error;
 
 	/* Hook up signal handler to capture certification signal */
@@ -1951,6 +1973,9 @@ impl_device_probe_cert (NMDeviceWifi *self,
 	ret = TRUE;
 
 error:
+	if (connection)
+		g_object_unref (connection);
+
 	if (!ret) {
 		g_set_error_literal (err,
 		                     NM_WIFI_ERROR,
diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c
index 8e7807c..b9bf6f1 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -175,21 +175,44 @@ nm_supplicant_config_add_option (NMSupplicantConfig *self,
 }
 
 NMSupplicantConfig *
-nm_supplicant_config_new_probe (const GByteArray *ssid)
+nm_supplicant_config_new_probe (const GByteArray *ssid, NMSetting8021x *setting)
 {
 	NMSupplicantConfig *probe_config;
+	const char *identity, *password;
+	gboolean use_pw = FALSE;
+	guint32 i, num_eap;
 
-	if (!ssid)
-		return NULL;
+	g_return_val_if_fail (ssid != NULL, NULL);
+	g_return_val_if_fail (setting != NULL, NULL);
+
+	num_eap = nm_setting_802_1x_get_num_eap_methods (setting);
+	for (i = 0; i < num_eap; i++) {
+		const char *method = nm_setting_802_1x_get_eap_method (setting, i);
+
+		if (method && (strcasecmp (method, "ttls") == 0 ||
+			       strcasecmp (method, "peap") == 0))
+			use_pw = TRUE;
+	}
+
+	identity = nm_setting_802_1x_get_identity (setting);
+	if (!identity)
+		identity = " ";
 
 	probe_config = (NMSupplicantConfig *)g_object_new (NM_TYPE_SUPPLICANT_CONFIG, NULL);
 
 	nm_supplicant_config_add_option (probe_config, "ssid", (char *)ssid->data, ssid->len, FALSE);
 	nm_supplicant_config_add_option (probe_config, "key_mgmt", "WPA-EAP", -1, FALSE);
 	nm_supplicant_config_add_option (probe_config, "eap", "TTLS PEAP TLS", -1, FALSE);
-	nm_supplicant_config_add_option (probe_config, "identity", " ", -1, FALSE);
+	nm_supplicant_config_add_option (probe_config, "identity", identity, -1, FALSE);
 	nm_supplicant_config_add_option (probe_config, "ca_cert", "probe://", -1, FALSE);
 
+	if (use_pw) {
+		password = nm_setting_802_1x_get_password(setting);
+		if (!password)
+			return NULL;
+		nm_supplicant_config_add_option (probe_config, "password", password, -1, TRUE);
+	}
+
 	return probe_config;
 }
 
diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h
index c0356c5..9d09239 100644
--- a/src/supplicant-manager/nm-supplicant-config.h
+++ b/src/supplicant-manager/nm-supplicant-config.h
@@ -52,7 +52,8 @@ GType nm_supplicant_config_get_type (void);
 
 NMSupplicantConfig *nm_supplicant_config_new (void);
 
-NMSupplicantConfig *nm_supplicant_config_new_probe (const GByteArray *ssid);
+NMSupplicantConfig *nm_supplicant_config_new_probe (const GByteArray *ssid,
+						    NMSetting8021x *setting);
 
 guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self);
 
-- 
1.8.1.4