File nm-probe-radius-server-cert.patch of Package NetworkManager
From 7f1ab67e7d78d94b28d0194e1fb70e71b70b6d21 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/3] 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 eb3f1f3..28cfd21 100644
--- a/libnm-util/libnm-util.ver
+++ b/libnm-util/libnm-util.ver
@@ -115,6 +115,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 28c0d3f..0920d73 100644
--- a/libnm-util/nm-setting-8021x.c
+++ b/libnm-util/nm-setting-8021x.c
@@ -64,6 +64,7 @@
**/
#define SCHEME_PATH "file://"
+#define SCHEME_HASH "hash://server/sha256/"
/**
* nm_setting_802_1x_error_quark:
@@ -388,6 +389,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;
}
@@ -398,7 +402,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)
**/
@@ -462,6 +467,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)
{
@@ -513,7 +544,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);
}
@@ -531,6 +563,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 */
@@ -2429,6 +2472,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 eaca344..33fff30 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 78812f9..0b7fd75 100644
--- a/src/settings/plugins/ifnet/connection_parser.c
+++ b/src/settings/plugins/ifnet/connection_parser.c
@@ -45,6 +45,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)
{
@@ -188,11 +190,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,
@@ -297,11 +306,18 @@ eap_peap_reader (const char *eap_method,
ca_cert = wpa_get_value (ssid, "ca_cert");
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"
@@ -399,11 +415,18 @@ eap_ttls_reader (const char *eap_method,
/* ca cert */
ca_cert = wpa_get_value (ssid, "ca_cert");
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"
@@ -1751,12 +1774,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;
@@ -1766,6 +1791,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"
@@ -1775,6 +1801,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"
@@ -1784,6 +1811,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"
@@ -1793,6 +1821,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"
@@ -1802,6 +1831,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"
@@ -1811,6 +1841,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"
@@ -1820,6 +1851,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"
@@ -1829,6 +1861,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"
@@ -1843,6 +1876,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);
@@ -1861,6 +1895,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;
}
@@ -1875,6 +1912,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 c7889cf..85090b8 100644
--- a/src/settings/plugins/keyfile/reader.c
+++ b/src/settings/plugins/keyfile/reader.c
@@ -871,6 +871,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" };
@@ -895,6 +896,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 bbd6a7c..bc90fbd 100644
--- a/src/settings/plugins/keyfile/writer.c
+++ b/src/settings/plugins/keyfile/writer.c
@@ -565,6 +565,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;
@@ -575,6 +576,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,
@@ -583,6 +585,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,
@@ -591,6 +594,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,
@@ -599,6 +603,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,
@@ -607,6 +612,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,
@@ -615,6 +621,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 },
@@ -693,7 +700,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;
@@ -755,6 +762,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.7.7
From 8de0c8b23577663cc622e04e3ff4c5fe01e11b9b Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <chingpang@gmail.com>
Date: Wed, 18 Jul 2012 12:17:17 +0800
Subject: [PATCH 2/3] 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(+), 0 deletions(-)
diff --git a/introspection/nm-device-wifi.xml b/introspection/nm-device-wifi.xml
index fb50762..fdff623 100644
--- a/introspection/nm-device-wifi.xml
+++ b/introspection/nm-device-wifi.xml
@@ -14,6 +14,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.
@@ -81,6 +93,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 ed964a5..3fd9fc7 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -59,10 +59,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);
#include "nm-device-wifi-glue.h"
@@ -99,6 +103,7 @@ enum {
HIDDEN_AP_FOUND,
PROPERTIES_CHANGED,
SCANNING_ALLOWED,
+ CERT_RECEIVED,
LAST_SIGNAL
};
@@ -113,6 +118,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;
@@ -1661,6 +1667,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
*
@@ -3526,6 +3615,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 1e665fc..b45b0df 100644
--- a/src/nm-device-wifi.h
+++ b/src/nm-device-wifi.h
@@ -46,6 +46,7 @@ typedef enum {
NM_WIFI_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/
NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/
NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, /*< nick=AccessPointNotFound >*/
+ NM_WIFI_ERROR_INVALID_CERT_PROBE, /*< nick=InvalidCertProbe >*/
} NMWifiError;
#define NM_DEVICE_WIFI_HW_ADDRESS "hw-address"
@@ -83,6 +84,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 a8e4ab9..0b87ddd 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,
@@ -912,6 +931,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 f8ad8f1..2c69d31 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -64,6 +64,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 };
@@ -503,6 +504,17 @@ wpas_iface_scan_done (DBusGProxy *proxy,
}
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)
@@ -717,6 +729,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,
@@ -1488,5 +1512,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 608ee05..b304546 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/nm-supplicant-interface.h
@@ -107,6 +107,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.7.7
From b8cc0eff9d479e96a7c64c51128c91fcf7d07f41 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <chingpang@gmail.com>
Date: Wed, 18 Jul 2012 12:26:19 +0800
Subject: [PATCH 3/3] 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 deletions(-)
diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver
index 427e248..e12c524 100644
--- a/libnm-glib/libnm-glib.ver
+++ b/libnm-glib/libnm-glib.ver
@@ -139,6 +139,7 @@ global:
nm_device_wifi_get_permanent_hw_address;
nm_device_wifi_get_type;
nm_device_wifi_new;
+ 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 6975898..566e6f0 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -79,6 +79,7 @@ enum {
enum {
ACCESS_POINT_ADDED,
ACCESS_POINT_REMOVED,
+ CERT_RECEIVED,
LAST_SIGNAL
};
@@ -342,6 +343,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)
{
@@ -593,6 +637,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),
@@ -760,4 +811,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 13f1cb8..45fa56c 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);
@@ -104,6 +104,9 @@ NMAccessPoint * nm_device_wifi_get_access_point_by_path (NMDeviceWifi *
const GPtrArray * nm_device_wifi_get_access_points (NMDeviceWifi *device);
+gboolean nm_device_wifi_probe_cert (NMDeviceWifi *device,
+ const GByteArray *ssid);
+
G_END_DECLS
#endif /* NM_DEVICE_WIFI_H */
--
1.7.7