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
