From 47f8fc02bfe11133d30f88ad99e0c6ccf8857989 Mon Sep 17 00:00:00 2001
From: Jonathan Kang <jonathankang@gnome.org>
Date: Wed, 26 Aug 2020 09:28:25 +0800
Subject: [PATCH 1/2] add SAE support

---
 panels/network/cc-wifi-connection-row.c       | 11 ++++++++-
 .../connection-editor/ce-page-details.c       | 13 ++++++++--
 .../connection-editor/ce-page-security.c      | 24 +++++++++++++++++++
 3 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/panels/network/cc-wifi-connection-row.c b/panels/network/cc-wifi-connection-row.c
index 88ca9dfdc..f331e1597 100644
--- a/panels/network/cc-wifi-connection-row.c
+++ b/panels/network/cc-wifi-connection-row.c
@@ -59,7 +59,8 @@ typedef enum
   NM_AP_SEC_NONE,
   NM_AP_SEC_WEP,
   NM_AP_SEC_WPA,
-  NM_AP_SEC_WPA2
+  NM_AP_SEC_WPA2,
+  NM_AP_SEC_SAE
 } NMAccessPointSecurity;
 
 G_DEFINE_TYPE (CcWifiConnectionRow, cc_wifi_connection_row, GTK_TYPE_LIST_BOX_ROW)
@@ -96,6 +97,12 @@ get_access_point_security (NMAccessPoint *ap)
     {
       type = NM_AP_SEC_WPA;
     }
+#if NM_CHECK_VERSION(1,20,6)
+  else if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)
+    {
+      type = NM_AP_SEC_SAE;
+    }
+#endif
   else
     {
       type = NM_AP_SEC_WPA2;
@@ -128,6 +135,8 @@ get_connection_security (NMConnection *con)
     return NM_AP_SEC_WPA2;
   else if (strncmp (key_mgmt, "wpa-", 4) == 0)
     return NM_AP_SEC_WPA;
+  else if (g_str_equal (key_mgmt, "sae"))
+    return NM_AP_SEC_SAE;
   else
     return NM_AP_SEC_UNKNOWN;
 }
diff --git a/panels/network/connection-editor/ce-page-details.c b/panels/network/connection-editor/ce-page-details.c
index dbcc3d363..73a119b7e 100644
--- a/panels/network/connection-editor/ce-page-details.c
+++ b/panels/network/connection-editor/ce-page-details.c
@@ -60,8 +60,17 @@ get_ap_security_string (NMAccessPoint *ap)
                 g_string_append_printf (str, "%s, ", _("WPA"));
         }
         if (rsn_flags != NM_802_11_AP_SEC_NONE) {
-                /* TRANSLATORS: this WPA WiFi security */
-                g_string_append_printf (str, "%s, ", _("WPA2"));
+#if NM_CHECK_VERSION(1,20,6)
+                if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) {
+                        /* TRANSLATORS: this WPA3 WiFi security */
+                        g_string_append_printf (str, "%s, ", _("WPA3"));
+                }
+                else
+#endif
+                {
+                        /* TRANSLATORS: this WPA WiFi security */
+                        g_string_append_printf (str, "%s, ", _("WPA2"));
+                }
         }
         if ((wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) ||
             (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
diff --git a/panels/network/connection-editor/ce-page-security.c b/panels/network/connection-editor/ce-page-security.c
index f22954a33..d6da0e927 100644
--- a/panels/network/connection-editor/ce-page-security.c
+++ b/panels/network/connection-editor/ce-page-security.c
@@ -69,6 +69,12 @@ get_default_type_for_security (NMSettingWirelessSecurity *sec)
                 return NMU_SEC_DYNAMIC_WEP;
         }
 
+#if NM_CHECK_VERSION(1,20,6)
+        if (!strcmp (key_mgmt, "sae")) {
+                return NMU_SEC_SAE;
+        }
+#endif
+
         if (   !strcmp (key_mgmt, "wpa-none")
             || !strcmp (key_mgmt, "wpa-psk")) {
                 if (find_proto (sec, "rsn"))
@@ -337,6 +343,21 @@ finish_setup (CEPageSecurity *page)
                 }
         }
 
+#if NM_CHECK_VERSION(1,20,6)
+        if (nm_utils_security_valid (NMU_SEC_SAE, dev_caps, FALSE, is_adhoc, 0, 0, 0)) {
+                WirelessSecurityWPAPSK *ws_wpa_psk;
+
+                ws_wpa_psk = ws_wpa_psk_new (connection, FALSE);
+                if (ws_wpa_psk) {
+                        add_security_item (page, WIRELESS_SECURITY (ws_wpa_psk), sec_model,
+                                           &iter, _("WPA3 Personal"), FALSE);
+                        if ((active < 0) && ((default_type == NMU_SEC_SAE)))
+                                active = item;
+                        item++;
+                }
+        }
+#endif
+
         gtk_combo_box_set_model (combo, GTK_TREE_MODEL (sec_model));
         gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));
 
@@ -452,6 +473,9 @@ ce_page_security_new (NMConnection      *connection,
         if (default_type == NMU_SEC_STATIC_WEP ||
             default_type == NMU_SEC_LEAP ||
             default_type == NMU_SEC_WPA_PSK ||
+#if NM_CHECK_VERSION(1,20,6)
+            default_type == NMU_SEC_SAE ||
+#endif
             default_type == NMU_SEC_WPA2_PSK) {
                 CE_PAGE (page)->security_setting = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
         }
-- 
2.26.2


From 19a65a84070cbb2e041b88ecce885ef4e0162b0e Mon Sep 17 00:00:00 2001
From: Jonathan Kang <jonathankang@gnome.org>
Date: Sun, 27 Sep 2020 09:51:27 +0800
Subject: [PATCH 2/2] network: complet SAE Support

---
 .../connection-editor/ce-page-security.c      |   8 +-
 panels/network/wireless-security/meson.build  |   3 +
 .../wireless-security.gresource.xml           |   1 +
 .../wireless-security/wireless-security.h     |   1 +
 panels/network/wireless-security/ws-sae.c     | 202 ++++++++++++++++++
 panels/network/wireless-security/ws-sae.h     |  13 ++
 panels/network/wireless-security/ws-sae.ui    |  98 +++++++++
 7 files changed, 322 insertions(+), 4 deletions(-)
 create mode 100644 panels/network/wireless-security/ws-sae.c
 create mode 100644 panels/network/wireless-security/ws-sae.h
 create mode 100644 panels/network/wireless-security/ws-sae.ui

diff --git a/panels/network/connection-editor/ce-page-security.c b/panels/network/connection-editor/ce-page-security.c
index d6da0e927..12fc1ca76 100644
--- a/panels/network/connection-editor/ce-page-security.c
+++ b/panels/network/connection-editor/ce-page-security.c
@@ -345,11 +345,11 @@ finish_setup (CEPageSecurity *page)
 
 #if NM_CHECK_VERSION(1,20,6)
         if (nm_utils_security_valid (NMU_SEC_SAE, dev_caps, FALSE, is_adhoc, 0, 0, 0)) {
-                WirelessSecurityWPAPSK *ws_wpa_psk;
+                WirelessSecuritySAE *ws_sae;
 
-                ws_wpa_psk = ws_wpa_psk_new (connection, FALSE);
-                if (ws_wpa_psk) {
-                        add_security_item (page, WIRELESS_SECURITY (ws_wpa_psk), sec_model,
+                ws_sae = ws_sae_new (connection, FALSE);
+                if (ws_sae) {
+                        add_security_item (page, WIRELESS_SECURITY (ws_sae), sec_model,
                                            &iter, _("WPA3 Personal"), FALSE);
                         if ((active < 0) && ((default_type == NMU_SEC_SAE)))
                                 active = item;
diff --git a/panels/network/wireless-security/meson.build b/panels/network/wireless-security/meson.build
index 47def7a63..6036f56af 100644
--- a/panels/network/wireless-security/meson.build
+++ b/panels/network/wireless-security/meson.build
@@ -14,6 +14,7 @@ nm_applet_headers = [
   'wireless-security.h',
   'ws-leap.h',
   'ws-dynamic-wep.h',
+  'ws-sae.h',
   'ws-wep-key.h',
   'ws-wpa-eap.h',
   'ws-wpa-psk.h'
@@ -31,6 +32,7 @@ nm_applet_sources = [
   'wireless-security.c',
   'ws-leap.c',
   'ws-dynamic-wep.c',
+  'ws-sae.c',
   'ws-wep-key.c',
   'ws-wpa-eap.c',
   'ws-wpa-psk.c'
@@ -47,6 +49,7 @@ nm_resource_data = [
   'eap-method-ttls.ui',
   'ws-dynamic-wep.ui',
   'ws-leap.ui',
+  'ws-sae.ui',
   'ws-wep-key.ui',
   'ws-wpa-eap.ui',
   'ws-wpa-psk.ui'
diff --git a/panels/network/wireless-security/wireless-security.gresource.xml b/panels/network/wireless-security/wireless-security.gresource.xml
index a483d06a0..fa1a965ad 100644
--- a/panels/network/wireless-security/wireless-security.gresource.xml
+++ b/panels/network/wireless-security/wireless-security.gresource.xml
@@ -9,6 +9,7 @@
     <file preprocess="xml-stripblanks">eap-method-ttls.ui</file>
     <file preprocess="xml-stripblanks">ws-dynamic-wep.ui</file>
     <file preprocess="xml-stripblanks">ws-leap.ui</file>
+    <file preprocess="xml-stripblanks">ws-sae.ui</file>
     <file preprocess="xml-stripblanks">ws-wep-key.ui</file>
     <file preprocess="xml-stripblanks">ws-wpa-eap.ui</file>
     <file preprocess="xml-stripblanks">ws-wpa-psk.ui</file>
diff --git a/panels/network/wireless-security/wireless-security.h b/panels/network/wireless-security/wireless-security.h
index 975e750f6..e3b01c5c7 100644
--- a/panels/network/wireless-security/wireless-security.h
+++ b/panels/network/wireless-security/wireless-security.h
@@ -99,6 +99,7 @@ GType wireless_security_get_type (void);
 
 /* Below for internal use only */
 
+#include "ws-sae.h"
 #include "ws-wep-key.h"
 #include "ws-wpa-psk.h"
 #include "ws-leap.h"
diff --git a/panels/network/wireless-security/ws-sae.c b/panels/network/wireless-security/ws-sae.c
new file mode 100644
index 000000000..7fa95c687
--- /dev/null
+++ b/panels/network/wireless-security/ws-sae.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include <ctype.h>
+#include <string.h>
+
+#include "wireless-security.h"
+#include "helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+#define WPA_PMK_LEN 32
+
+struct _WirelessSecuritySAE {
+	WirelessSecurity parent;
+
+	gboolean editing_connection;
+	const char *password_flags_name;
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, WirelessSecurity *sec)
+{
+	GtkWidget *widget;
+	gboolean visible;
+
+	widget = GTK_WIDGET (gtk_builder_get_object (sec->builder, "psk_entry"));
+	g_assert (widget);
+
+	visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+	gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
+}
+
+static gboolean
+validate (WirelessSecurity *parent, GError **error)
+{
+	GtkWidget *entry;
+	NMSettingSecretFlags secret_flags;
+	const char *key;
+
+	entry = GTK_WIDGET (gtk_builder_get_object (parent->builder, "psk_entry"));
+	g_assert (entry);
+
+	secret_flags = nma_utils_menu_to_secret_flags (entry);
+	key = gtk_entry_get_text (GTK_ENTRY (entry));
+
+        if (   secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED
+            || secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) {
+		/* All good. */
+	} else if (key == NULL || key[0] == '\0') {
+		widget_set_error (entry);
+		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing password"));
+		return FALSE;
+	}
+	widget_unset_error (entry);
+
+	return TRUE;
+}
+
+static void
+add_to_size_group (WirelessSecurity *parent, GtkSizeGroup *group)
+{
+	GtkWidget *widget;
+
+	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "sae_type_label"));
+	gtk_size_group_add_widget (group, widget);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "sae_label"));
+	gtk_size_group_add_widget (group, widget);
+}
+
+static void
+fill_connection (WirelessSecurity *parent, NMConnection *connection)
+{
+	WirelessSecuritySAE *sae = (WirelessSecuritySAE *) parent;
+	GtkWidget *widget, *passwd_entry;
+	const char *key;
+	NMSettingWireless *s_wireless;
+	NMSettingWirelessSecurity *s_wireless_sec;
+	NMSettingSecretFlags secret_flags;
+	const char *mode;
+	gboolean is_adhoc = FALSE;
+
+	s_wireless = nm_connection_get_setting_wireless (connection);
+	g_assert (s_wireless);
+
+	mode = nm_setting_wireless_get_mode (s_wireless);
+	if (mode && !strcmp (mode, "adhoc"))
+		is_adhoc = TRUE;
+
+	/* Blow away the old security setting by adding a clear one */
+	s_wireless_sec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
+	nm_connection_add_setting (connection, (NMSetting *) s_wireless_sec);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "psk_entry"));
+	passwd_entry = widget;
+	key = gtk_entry_get_text (GTK_ENTRY (widget));
+	g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_PSK, key, NULL);
+
+	/* Save PSK_FLAGS to the connection */
+	secret_flags = nma_utils_menu_to_secret_flags (passwd_entry);
+	nm_setting_set_secret_flags (NM_SETTING (s_wireless_sec), NM_SETTING_WIRELESS_SECURITY_PSK,
+	                             secret_flags, NULL);
+
+	/* Update secret flags and popup when editing the connection */
+	if (sae->editing_connection)
+		nma_utils_update_password_storage (passwd_entry, secret_flags,
+		                                   NM_SETTING (s_wireless_sec), sae->password_flags_name);
+
+	wireless_security_clear_ciphers (connection);
+	if (is_adhoc) {
+		/* Ad-Hoc settings as specified by the supplicant */
+		g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NULL);
+		nm_setting_wireless_security_add_proto (s_wireless_sec, "rsn");
+		nm_setting_wireless_security_add_pairwise (s_wireless_sec, "ccmp");
+		nm_setting_wireless_security_add_group (s_wireless_sec, "ccmp");
+	} else {
+		g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NULL);
+
+		/* Just leave ciphers and protocol empty, the supplicant will
+		 * figure that out magically based on the AP IEs and card capabilities.
+		 */
+	}
+}
+
+static void
+update_secrets (WirelessSecurity *parent, NMConnection *connection)
+{
+	helper_fill_secret_entry (connection,
+	                          parent->builder,
+	                          "psk_entry",
+	                          NM_TYPE_SETTING_WIRELESS_SECURITY,
+	                          (HelperSecretFunc) nm_setting_wireless_security_get_psk);
+}
+
+WirelessSecuritySAE *
+ws_sae_new (NMConnection *connection, gboolean secrets_only)
+{
+	WirelessSecurity *parent;
+	WirelessSecuritySAE *sec;
+	NMSetting *setting = NULL;
+	GtkWidget *widget;
+
+	parent = wireless_security_init (sizeof (WirelessSecuritySAE),
+	                                 validate,
+	                                 add_to_size_group,
+	                                 fill_connection,
+	                                 update_secrets,
+	                                 NULL,
+	                                 "/org/freedesktop/network-manager-applet/ws-sae.ui",
+	                                 "sae_notebook",
+	                                 "psk_entry");
+	if (!parent)
+		return NULL;
+
+	parent->adhoc_compatible = TRUE;
+	sec = (WirelessSecuritySAE *) parent;
+	sec->editing_connection = secrets_only ? FALSE : TRUE;
+	sec->password_flags_name = NM_SETTING_WIRELESS_SECURITY_PSK;
+
+	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "psk_entry"));
+	g_assert (widget);
+	g_signal_connect (G_OBJECT (widget), "changed",
+	                  (GCallback) wireless_security_changed_cb,
+	                  sec);
+	gtk_entry_set_width_chars (GTK_ENTRY (widget), 28);
+
+	/* Create password-storage popup menu for password entry under entry's secondary icon */
+	if (connection)
+		setting = (NMSetting *) nm_connection_get_setting_wireless_security (connection);
+	nma_utils_setup_password_storage (widget, 0, setting, sec->password_flags_name,
+	                                  FALSE, secrets_only);
+
+	/* Fill secrets, if any */
+	if (connection)
+		update_secrets (WIRELESS_SECURITY (sec), connection);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "show_checkbutton_sae"));
+	g_assert (widget);
+	g_signal_connect (G_OBJECT (widget), "toggled",
+	                  (GCallback) show_toggled_cb,
+	                  sec);
+
+	/* Hide WPA/RSN for now since this can be autodetected by NM and the
+	 * supplicant when connecting to the AP.
+	 */
+
+	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "sae_type_combo"));
+	g_assert (widget);
+	gtk_widget_hide (widget);
+
+	widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "sae_type_label"));
+	g_assert (widget);
+	gtk_widget_hide (widget);
+
+	return sec;
+}
+
diff --git a/panels/network/wireless-security/ws-sae.h b/panels/network/wireless-security/ws-sae.h
new file mode 100644
index 000000000..1514e0b8c
--- /dev/null
+++ b/panels/network/wireless-security/ws-sae.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef WS_SAE_H
+#define WS_SAE_H
+
+typedef struct _WirelessSecuritySAE WirelessSecuritySAE;
+
+WirelessSecuritySAE * ws_sae_new (NMConnection *connection, gboolean secrets_only);
+
+#endif /* WS_SAE_H */
diff --git a/panels/network/wireless-security/ws-sae.ui b/panels/network/wireless-security/ws-sae.ui
new file mode 100644
index 000000000..8f0d04133
--- /dev/null
+++ b/panels/network/wireless-security/ws-sae.ui
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface domain="nm-applet">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkNotebook" id="sae_notebook">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="show_tabs">False</property>
+    <property name="show_border">False</property>
+    <child>
+      <object class="GtkGrid" id="sae_table">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <child>
+          <object class="GtkLabel" id="sae_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Password</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">psk_entry</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="psk_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="max_length">64</property>
+            <property name="visibility">False</property>
+            <property name="activates_default">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="sae_type_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">_Type</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">sae_type_combo</property>
+            <property name="xalign">1</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="show_checkbutton_sae">
+            <property name="label" translatable="yes">Sho_w password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="hexpand">True</property>
+            <property name="use_underline">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkComboBox" id="sae_type_combo">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+    <child type="tab">
+      <object class="GtkLabel" id="GtkLabel2">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+      <packing>
+        <property name="tab_fill">False</property>
+      </packing>
+    </child>
+  </object>
+</interface>
-- 
2.26.2

