[gnome-control-center/wip/feborges/new-remote-desktop-dialog: 8/12] sharing: Generate RDP TLS certificates when missing




commit 5c617faaec795c141206fbcf2d9b24e3d239b163
Author: Jonas Ådahl <jadahl gmail com>
Date:   Tue Feb 22 10:30:07 2022 +0100

    sharing: Generate RDP TLS certificates when missing
    
    This also hooks up the certificate verification dialog to the configured
    TLS certificate.

 meson.build                          |   1 +
 panels/sharing/cc-sharing-panel.c    | 214 ++++++++++++++++++++++++++++++++++-
 panels/sharing/cc-sharing-panel.ui   |  23 ++++
 panels/sharing/meson.build           |   1 +
 panels/sharing/sharing.css           |   4 +
 panels/sharing/sharing.gresource.xml |   1 +
 panels/wwan/meson.build              |   4 +-
 7 files changed, 244 insertions(+), 4 deletions(-)
---
diff --git a/meson.build b/meson.build
index d963651f9..73f2ba303 100644
--- a/meson.build
+++ b/meson.build
@@ -128,6 +128,7 @@ gudev_dep = dependency('gudev-1.0', version: '>= 232')
 x11_dep = dependency('x11')
 xi_dep = dependency('xi', version: '>= 1.2')
 epoxy_dep = dependency('epoxy')
+gcr_dep = dependency('gcr-base-3')
 
 m_dep = cc.find_library('m')
 
diff --git a/panels/sharing/cc-sharing-panel.c b/panels/sharing/cc-sharing-panel.c
index a4f84f411..8f3deca9e 100644
--- a/panels/sharing/cc-sharing-panel.c
+++ b/panels/sharing/cc-sharing-panel.c
@@ -29,12 +29,17 @@
 #include "cc-media-sharing.h"
 #include "cc-sharing-networks.h"
 #include "cc-gnome-remote-desktop.h"
+#include "cc-tls-certificate.h"
 #include "org.gnome.SettingsDaemon.Sharing.h"
 
 #ifdef GDK_WINDOWING_WAYLAND
 #include <gdk/wayland/gdkwayland.h>
 #endif
 #include <glib/gi18n.h>
+
+#define GCR_API_SUBJECT_TO_CHANGE
+#include <gcr/gcr-base.h>
+
 #include <config.h>
 
 static void cc_sharing_panel_setup_label_with_hostname (CcSharingPanel *self, GtkWidget *label);
@@ -82,7 +87,10 @@ struct _CcSharingPanel
   GtkWidget *remote_desktop_address_label;
   GtkWidget *remote_desktop_row;
   GtkWidget *remote_desktop_switch;
+  GtkWidget *remote_desktop_verify_encryption;
   GtkWidget *remote_desktop_fingerprint_dialog;
+  GtkWidget *remote_desktop_fingerprint_left;
+  GtkWidget *remote_desktop_fingerprint_right;
 
   GtkWidget *shared_folders_grid;
   GtkWidget *shared_folders_listbox;
@@ -91,6 +99,7 @@ struct _CcSharingPanel
 
   guint remote_desktop_name_watch;
   guint remote_desktop_store_credentials_id;
+  GTlsCertificate *remote_desktop_certificate;
 };
 
 CC_PANEL_REGISTER (CcSharingPanel, cc_sharing_panel)
@@ -173,6 +182,54 @@ cc_sharing_panel_get_help_uri (CcPanel *panel)
 static void
 remote_desktop_show_encryption_fingerprint (CcSharingPanel *self)
 {
+  g_autoptr(GByteArray) der = NULL;
+  g_autoptr(GcrCertificate) gcr_cert = NULL;
+  g_autofree char *fingerprint = NULL;
+  g_auto(GStrv) fingerprintv = NULL;
+  g_autofree char *left_string = NULL;
+  g_autofree char *right_string = NULL;
+
+  g_return_if_fail (self->remote_desktop_certificate);
+
+  g_object_get (self->remote_desktop_certificate,
+                "certificate", &der, NULL);
+  gcr_cert = gcr_simple_certificate_new (der->data, der->len);
+  if (!gcr_cert)
+    {
+      g_warning ("Failed to load GCR TLS certificate representation");
+      return;
+    }
+
+  fingerprint = gcr_certificate_get_fingerprint_hex (gcr_cert, G_CHECKSUM_SHA256);
+
+  fingerprintv = g_strsplit (fingerprint, " ", -1);
+  g_return_if_fail (g_strv_length (fingerprintv) == 32);
+
+  left_string = g_strdup_printf (
+    "%s:%s:%s:%s\n"
+    "%s:%s:%s:%s\n"
+    "%s:%s:%s:%s\n"
+    "%s:%s:%s:%s\n",
+    fingerprintv[0], fingerprintv[1], fingerprintv[2], fingerprintv[3],
+    fingerprintv[8], fingerprintv[9], fingerprintv[10], fingerprintv[11],
+    fingerprintv[16], fingerprintv[17], fingerprintv[18], fingerprintv[19],
+    fingerprintv[24], fingerprintv[25], fingerprintv[26], fingerprintv[27]);
+
+ right_string = g_strdup_printf (
+   "%s:%s:%s:%s\n"
+   "%s:%s:%s:%s\n"
+   "%s:%s:%s:%s\n"
+   "%s:%s:%s:%s\n",
+   fingerprintv[4], fingerprintv[5], fingerprintv[6], fingerprintv[7],
+   fingerprintv[12], fingerprintv[13], fingerprintv[14], fingerprintv[15],
+   fingerprintv[20], fingerprintv[21], fingerprintv[22], fingerprintv[23],
+   fingerprintv[28], fingerprintv[29], fingerprintv[30], fingerprintv[31]);
+
+  gtk_label_set_label (GTK_LABEL (self->remote_desktop_fingerprint_left),
+                       left_string);
+  gtk_label_set_label (GTK_LABEL (self->remote_desktop_fingerprint_right),
+                       right_string);
+
   gtk_window_set_transient_for (GTK_WINDOW (self->remote_desktop_fingerprint_dialog),
                                 GTK_WINDOW (self->remote_desktop_dialog));
   gtk_window_present (GTK_WINDOW (self->remote_desktop_fingerprint_dialog));
@@ -223,8 +280,11 @@ cc_sharing_panel_class_init (CcSharingPanelClass *klass)
   gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, remote_desktop_password_entry);
   gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, remote_desktop_device_name_label);
   gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, remote_desktop_address_label);
+  gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, remote_desktop_verify_encryption);
   gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, remote_desktop_fingerprint_dialog);
   gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, remote_desktop_row);
+  gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, remote_desktop_fingerprint_left);
+  gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, remote_desktop_fingerprint_right);
   gtk_widget_class_bind_template_child (widget_class, CcSharingPanel, shared_folders_listbox);
 
   gtk_widget_class_bind_template_callback (widget_class, remote_desktop_show_encryption_fingerprint);
@@ -1048,13 +1108,156 @@ disable_gnome_remote_desktop_service (CcSharingPanel *self)
     g_warning ("Failed to disable remote desktop service: %s", error->message);
 }
 
+static void
+calc_default_tls_paths (char **out_dir_path,
+                        char **out_cert_path,
+                        char **out_key_path)
+{
+  g_autofree char *dir_path = NULL;
+
+  dir_path = g_strdup_printf ("%s/gnome-remote-desktop",
+                              g_get_user_data_dir ());
+
+  if (out_cert_path)
+    *out_cert_path = g_strdup_printf ("%s/rdp-tls.crt", dir_path);
+  if (out_key_path)
+    *out_key_path = g_strdup_printf ("%s/rdp-tls.key", dir_path);
+
+  if (out_dir_path)
+    *out_dir_path = g_steal_pointer (&dir_path);
+}
+
+static void
+set_tls_certificate (CcSharingPanel  *self,
+                     GTlsCertificate *tls_certificate)
+{
+  g_set_object (&self->remote_desktop_certificate,
+                tls_certificate);
+  gtk_widget_set_sensitive (self->remote_desktop_verify_encryption, TRUE);
+}
+
+static void
+on_certificate_generated (GObject      *source_object,
+                          GAsyncResult *res,
+                          gpointer      user_data)
+{
+  CcSharingPanel *self;
+  g_autoptr(GTlsCertificate) tls_certificate = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autofree char *cert_path = NULL;
+  g_autofree char *key_path = NULL;
+  g_autoptr(GSettings) rdp_settings = NULL;
+
+  tls_certificate = bonsai_tls_certificate_new_generate_finish (res, &error);
+  if (!tls_certificate)
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
+
+      g_warning ("Failed to generate TLS certificate: %s", error->message);
+      return;
+    }
+
+  self = CC_SHARING_PANEL (user_data);
+
+  calc_default_tls_paths (NULL, &cert_path, &key_path);
+
+  rdp_settings = g_settings_new (GNOME_REMOTE_DESKTOP_RDP_SCHEMA_ID);
+
+  g_settings_set_string (rdp_settings, "tls-cert", cert_path);
+  g_settings_set_string (rdp_settings, "tls-key", key_path);
+
+  set_tls_certificate (self, tls_certificate);
+
+  enable_gnome_remote_desktop_service (self);
+}
+
+static void
+enable_gnome_remote_desktop (CcSharingPanel *self)
+{
+  g_autofree char *dir_path = NULL;
+  g_autofree char *cert_path = NULL;
+  g_autofree char *key_path = NULL;
+  g_autoptr(GFile) dir = NULL;
+  g_autoptr(GFile) cert_file = NULL;
+  g_autoptr(GFile) key_file = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GSettings) rdp_settings = NULL;
+
+  rdp_settings = g_settings_new (GNOME_REMOTE_DESKTOP_RDP_SCHEMA_ID);
+  cert_path = g_settings_get_string (rdp_settings, "tls-cert");
+  key_path = g_settings_get_string (rdp_settings, "tls-key");
+  if (strlen (cert_path) > 0 &&
+      strlen (key_path) > 0)
+    {
+      g_autoptr(GTlsCertificate) tls_certificate = NULL;
+
+      tls_certificate = g_tls_certificate_new_from_file (cert_path, &error);
+      if (tls_certificate)
+        {
+          set_tls_certificate (self, tls_certificate);
+
+          enable_gnome_remote_desktop_service (self);
+          return;
+        }
+
+      g_warning ("Configured TLS certificate invalid: %s", error->message);
+      return;
+    }
+
+  calc_default_tls_paths (&dir_path, &cert_path, &key_path);
+
+  dir = g_file_new_for_path (dir_path);
+  if (!g_file_query_exists (dir, NULL))
+    {
+      if (!g_file_make_directory_with_parents (dir, NULL, &error))
+        {
+          g_warning ("Failed to create remote desktop certificate directory: %s",
+                     error->message);
+          return;
+        }
+    }
+
+  cert_file = g_file_new_for_path (cert_path);
+  key_file = g_file_new_for_path (key_path);
+
+  if (g_file_query_exists (cert_file, NULL) &&
+      g_file_query_exists (key_file, NULL))
+    {
+      g_autoptr(GTlsCertificate) tls_certificate = NULL;
+
+      tls_certificate = g_tls_certificate_new_from_file (cert_path, &error);
+      if (tls_certificate)
+        {
+          g_settings_set_string (rdp_settings, "tls-cert", cert_path);
+          g_settings_set_string (rdp_settings, "tls-key", key_path);
+
+          set_tls_certificate (self, tls_certificate);
+
+          enable_gnome_remote_desktop_service (self);
+          return;
+        }
+
+      g_warning ("Existing TLS certificate invalid: %s", error->message);
+      return;
+    }
+
+  bonsai_tls_certificate_new_generate_async (cert_path,
+                                             key_path,
+                                             "US",
+                                             "GNOME",
+                                             cc_panel_get_cancellable (CC_PANEL (self)),
+                                             on_certificate_generated,
+                                             self);
+}
+
 static void
 on_remote_desktop_state_changed (GtkWidget      *widget,
                                  GParamSpec     *pspec,
                                  CcSharingPanel *self)
 {
   if (gtk_switch_get_active (GTK_SWITCH (widget)))
-    enable_gnome_remote_desktop_service (self);
+    enable_gnome_remote_desktop (self);
   else
     disable_gnome_remote_desktop_service (self);
 }
@@ -1224,6 +1427,8 @@ sharing_proxy_ready (GObject      *source,
 static void
 cc_sharing_panel_init (CcSharingPanel *self)
 {
+  g_autoptr(GtkCssProvider) provider = NULL;
+
   g_resources_register (cc_sharing_get_resource ());
 
   gtk_widget_init_template (GTK_WIDGET (self));
@@ -1260,6 +1465,13 @@ cc_sharing_panel_init (CcSharingPanel *self)
   /* make sure the hostname entry isn't focused by default */
   g_signal_connect_swapped (self, "map", G_CALLBACK (gtk_widget_grab_focus),
                             self->main_list_box);
+
+  provider = gtk_css_provider_new ();
+  gtk_css_provider_load_from_resource (provider,
+                                       "/org/gnome/control-center/sharing/sharing.css");
+  gtk_style_context_add_provider_for_display (gdk_display_get_default (),
+                                              GTK_STYLE_PROVIDER (provider),
+                                              GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 }
 
 CcSharingPanel *
diff --git a/panels/sharing/cc-sharing-panel.ui b/panels/sharing/cc-sharing-panel.ui
index 04fcc6b5d..093cf5635 100644
--- a/panels/sharing/cc-sharing-panel.ui
+++ b/panels/sharing/cc-sharing-panel.ui
@@ -379,6 +379,29 @@
           <object class="AdwStatusPage">
             <property name="title" translatable="yes">Encryption Fingerprint</property>
             <property name="description" translatable="yes">The encryption fingerprint can be seen in 
connecting clients and should be identical</property>
+            <child>
+              <object class="GtkBox">
+                <property name="orientation">horizontal</property>
+                <property name="halign">center</property>
+                <style>
+                  <class name="tls-cert-verification" />
+                </style>
+                <child>
+                  <object class="GtkLabel" id="remote_desktop_fingerprint_left">
+                    <style>
+                      <class name="tls-cert-fingerprint" />
+                    </style>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="remote_desktop_fingerprint_right">
+                    <style>
+                      <class name="tls-cert-fingerprint" />
+                    </style>
+                  </object>
+                </child>
+              </object>
+            </child>
           </object>
         </child>
       </object>
diff --git a/panels/sharing/meson.build b/panels/sharing/meson.build
index 5d2bcba6e..1e72f935e 100644
--- a/panels/sharing/meson.build
+++ b/panels/sharing/meson.build
@@ -84,6 +84,7 @@ panels_libs += static_library(
     common_deps,
     libsecret_dep,
     gnutls_dep,
+    gcr_dep,
   ],
   c_args: cflags
 )
diff --git a/panels/sharing/sharing.css b/panels/sharing/sharing.css
new file mode 100644
index 000000000..cf18ab392
--- /dev/null
+++ b/panels/sharing/sharing.css
@@ -0,0 +1,4 @@
+.tls-cert-fingerprint {
+  font-family: monospace;
+  margin: 10px;
+}
diff --git a/panels/sharing/sharing.gresource.xml b/panels/sharing/sharing.gresource.xml
index 75c7f7458..275f8846e 100644
--- a/panels/sharing/sharing.gresource.xml
+++ b/panels/sharing/sharing.gresource.xml
@@ -3,5 +3,6 @@
   <gresource prefix="/org/gnome/control-center/sharing">
     <file preprocess="xml-stripblanks">cc-sharing-panel.ui</file>
     <file preprocess="xml-stripblanks">cc-sharing-networks.ui</file>
+    <file>sharing.css</file>
   </gresource>
 </gresources>
diff --git a/panels/wwan/meson.build b/panels/wwan/meson.build
index 04a092050..9b73b5bb1 100644
--- a/panels/wwan/meson.build
+++ b/panels/wwan/meson.build
@@ -1,7 +1,5 @@
 
-gcr_dep = [dependency('gcr-base-3')]
-
-deps = common_deps + network_manager_deps + gcr_dep + [polkit_gobject_dep]
+deps = common_deps + network_manager_deps + [gcr_dep, polkit_gobject_dep]
 panels_list += cappletname
 desktop = 'gnome-@0@-panel.desktop'.format(cappletname)
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]