This commit utilizes the probe function in wpa_supplicant to
retreive the certificate of the RADIUS server. A D-Bus method and
signal are added to allow the client app to invoke and receive
the certificate.

https://bugzilla.gnome.org/show_bug.cgi?id=341323
---
 introspection/nm-device-wifi.xml                 |   23 +++++
 libnm-glib/libnm-glib.ver                        |    1 +
 libnm-glib/nm-device-wifi.c                      |   54 ++++++++++++
 libnm-glib/nm-device-wifi.h                      |    5 +-
 src/nm-device-wifi.c                             |  102 ++++++++++++++++++++++
 src/nm-device-wifi.h                             |    1 +
 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 +
 10 files changed, 247 insertions(+), 1 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/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver
index 1a4a68c..51b8c50 100644
--- a/libnm-glib/libnm-glib.ver
+++ b/libnm-glib/libnm-glib.ver
@@ -98,6 +98,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_get_active_nsp;
        nm_device_wimax_get_bsid;
        nm_device_wimax_get_center_frequency;
diff --git a/libnm-glib/nm-device-wifi.c b/libnm-glib/nm-device-wifi.c
index 7d0e1b9..2bf4e3b 100644
--- a/libnm-glib/nm-device-wifi.c
+++ b/libnm-glib/nm-device-wifi.c
@@ -84,6 +84,7 @@ enum {
 enum {
        ACCESS_POINT_ADDED,
        ACCESS_POINT_REMOVED,
+       CERT_RECEIVED,
 
        LAST_SIGNAL
 };
@@ -385,6 +386,26 @@ nm_device_wifi_get_access_point_by_path (NMDeviceWifi 
*device,
        return ap;
 }
 
+gboolean
+nm_device_wifi_probe_cert (NMDeviceWifi *device,
+                           const GByteArray *ssid)
+{
+       NMDeviceWifiPrivate *priv;
+       GError *error = NULL;
+
+       g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), FALSE);
+
+       priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
+
+       if (!org_freedesktop_NetworkManager_Device_Wireless_probe_cert 
(priv->proxy, ssid, &error)) {
+               g_warning ("%s: error probe certificate: %s", __func__, 
error->message);
+               g_error_free (error);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 static void
 access_point_added_proxy (DBusGProxy *proxy, char *path, gpointer user_data)
 {
@@ -440,6 +461,14 @@ access_point_removed_proxy (DBusGProxy *proxy, char *path, 
gpointer user_data)
 }
 
 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)
 {
        NMDeviceWifiPrivate *priv;
@@ -719,6 +748,13 @@ constructor (GType type,
                                                    G_CALLBACK 
(access_point_removed_proxy),
                                                    object, NULL);
 
+       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_for_property_changed (NM_DEVICE_WIFI (object));
 
        g_signal_connect (NM_DEVICE (object),
@@ -888,4 +924,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 fb2ab27..313a3f3 100644
--- a/libnm-glib/nm-device-wifi.h
+++ b/libnm-glib/nm-device-wifi.h
@@ -53,6 +53,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);
@@ -60,7 +61,6 @@ typedef struct {
        void (*_reserved3) (void);
        void (*_reserved4) (void);
        void (*_reserved5) (void);
-       void (*_reserved6) (void);
 } NMDeviceWifiClass;
 
 GType nm_device_wifi_get_type (void);
@@ -79,6 +79,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 */
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index 9695c07..69fbce3 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -57,10 +57,14 @@
 #include "nm-setting-ip6-config.h"
 #include "nm-system.h"
 #include "nm-settings-connection.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"
 
@@ -100,6 +104,7 @@ enum {
        HIDDEN_AP_FOUND,
        PROPERTIES_CHANGED,
        SCANNING_ALLOWED,
+       CERT_RECEIVED,
 
        LAST_SIGNAL
 };
@@ -114,6 +119,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;
@@ -200,6 +206,7 @@ typedef enum {
        NM_WIFI_ERROR_CONNECTION_INVALID,
        NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE,
        NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND,
+       NM_WIFI_ERROR_INVALID_CERT_PROBE,
 } NMWifiError;
 
 #define NM_WIFI_ERROR (nm_wifi_error_quark ())
@@ -232,6 +239,8 @@ nm_wifi_error_get_type (void)
                        ENUM_ENTRY (NM_WIFI_ERROR_CONNECTION_INCOMPATIBLE, 
"ConnectionIncompatible"),
                        /* Given access point was not in this device's scan 
list. */
                        ENUM_ENTRY (NM_WIFI_ERROR_ACCESS_POINT_NOT_FOUND, 
"AccessPointNotFound"),
+                       /* Certificate Probe was not valid. */
+                       ENUM_ENTRY (NM_WIFI_ERROR_INVALID_CERT_PROBE, 
"InvalidCertProbe"),
                        { 0, 0, 0 }
                };
                etype = g_enum_register_static ("NMWifiError", values);
@@ -1725,6 +1734,89 @@ impl_device_get_access_points (NMDeviceWifi *self,
        return TRUE;
 }
 
+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;
+}
+
 /*
  * nm_device_get_mode
  *
@@ -4021,6 +4113,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 31ac5ad..916c2b9 100644
--- a/src/nm-device-wifi.h
+++ b/src/nm-device-wifi.h
@@ -77,6 +77,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 4860314..4b6588e 100644
--- a/src/supplicant-manager/nm-supplicant-config.c
+++ b/src/supplicant-manager/nm-supplicant-config.c
@@ -173,6 +173,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,
@@ -845,6 +864,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 dad23e2..8886a91 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 857cde5..28ad780 100644
--- a/src/supplicant-manager/nm-supplicant-interface.c
+++ b/src/supplicant-manager/nm-supplicant-interface.c
@@ -60,6 +60,7 @@ enum {
        NEW_BSS,           /* interface saw a new access point from a scan */
        SCAN_DONE,         /* wifi scan is complete */
        CONNECTION_ERROR,  /* an error occurred during a connection request */
+       CERTIFICATION,     /* a RADIUS server certificate was received */
        LAST_SIGNAL
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -387,6 +388,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)
@@ -486,6 +498,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,
@@ -1207,5 +1231,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 e32411d..b65cd87 100644
--- a/src/supplicant-manager/nm-supplicant-interface.h
+++ b/src/supplicant-manager/nm-supplicant-interface.h
@@ -89,6 +89,10 @@ typedef struct {
        void (*connection_error) (NMSupplicantInterface * iface,
                                  const char * name,
                                  const char * message);
+
+       /* a RADIUS server certificate was received */
+       void (*certification) (NMSupplicantInterface * iface,
+                              const GHashTable * ca_cert);
 } NMSupplicantInterfaceClass;
 
 
-- 
1.7.3.4

_______________________________________________
networkmanager-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to