[glib-networking] Use the GnuTLS system trust by default



commit f1c8feee014007cc913b71357acb609f8d1200df
Author: Michael Catanzaro <mcatanzaro igalia com>
Date:   Thu Feb 8 22:02:06 2018 -0600

    Use the GnuTLS system trust by default
    
    Get rid of the ca_certificates_path build flag. The default GTlsDatabase
    will now use the GnuTLS system trust. GTlsFileDatabase now builds its
    internal hash tables by iterating its gnutls_x509_trust_list_t, rather
    than by parsing its certificate file manually.
    
    The find-ca-certificates script is removed, since it's no longer needed.
    
    There are some potential compatibility risks here:
    
     * The minimum required GnuTLS version is increased from 3.3.5 to 3.4.
    
     * If GnuTLS is not configured with a system trust, all certificate
       verification using the default GTlsDatabase will fail. I noticed that
       GNOME's flatpak runtime does not configure a system trust, so this
       breaks HTTPS there. This is sad for Epiphany Technology Preview, but
       we should do this anyway, and separately fix the GNOME runtime.
    
     * It was previously possible to configure glib-networking using
       --without-ca-certificates to ensure the default GTlsDatabase is
       empty (GNOME #727282). Apparently this was desirable on some embedded
       systems, though I'm not sure why. Such configuration is still
       possible by configuring GnuTLS with no system trust. Presumably,
       anybody relying on this behavior will notice that the
       --without-ca-certificates flag has disappeared during the build
       system change and investigate, so this seems unproblematic.
    
     * The default GTlsDatabase is a GTlsFileDatabase, but it might not
       actually correspond to a file anymore. This will be fixed in the next
       commit.
    
     * If the anchors property of a GTlsFileDatabase is NULL, that
       previously indicated an empty GTlsFileDatabase, but now indicates
       that the system trust is used. This will also be fixed in the next
       commit.
    
     * Certificate handles created using the default GTlsDatabase will be
       different before and after this commit. This seems unlikely to cause
       problems in practice, since a quick Debian codesearch reveals zero
       applications using our certificate handles. But, if an application
       were to rely on handles generated by previous versions of
       glib-networking being valid in the new version, it would break.
    
    None of the above seem likely to cause practical issues, once
    distributors ensure that GnuTLS is built properly, so I think we can
    proceed.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=753260

 find-ca-certificates                 |   20 ------
 meson.build                          |   10 +---
 meson_options.txt                    |    1 -
 tls/gnutls/gtlsbackend-gnutls.c      |    6 +--
 tls/gnutls/gtlsfiledatabase-gnutls.c |  117 ++++++++++++++++++---------------
 5 files changed, 66 insertions(+), 88 deletions(-)
---
diff --git a/meson.build b/meson.build
index cf6782c..ee2bd9d 100644
--- a/meson.build
+++ b/meson.build
@@ -62,14 +62,7 @@ if enable_gnome_proxy_support
 endif
 
 # *** Checks for GnuTLS     ***
-gnutls_dep = dependency('gnutls', version: '>= 3.3.5', required: true)
-
-msg = 'location of system Certificate Authority list: '
-res = run_command(join_paths(meson.source_root(), 'find-ca-certificates'), 
get_option('ca_certificates_path'))
-assert(res.returncode() == 0, msg + ' could not find any CA certificate store. Use 
-Dca_certificates_path=PATH to set')
-ca_certificates_path = res.stdout().strip()
-message(msg + ca_certificates_path)
-config_h.set_quoted('GTLS_SYSTEM_CA_FILE', ca_certificates_path, description: 'The system CA list')
+gnutls_dep = dependency('gnutls', version: '>= 3.4', required: true)
 
 # *** Checks for p11-kit  ***
 enable_pkcs11_support = get_option('pkcs11_support')
@@ -126,5 +119,4 @@ meson.add_install_script('meson_post_install.py', gio_module_dir)
 output = '\n\n  libproxy support:    ' + enable_libproxy_support.to_string() + '\n'
 output += '  GNOME proxy support: ' + enable_gnome_proxy_support.to_string() + '\n'
 output += '  PKCS#11 support:     ' + enable_pkcs11_support.to_string() + '\n'
-output += '  TLS CA file:         ' + ca_certificates_path + '\n'
 message(output)
diff --git a/meson_options.txt b/meson_options.txt
index 8cf58ed..1e04d19 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,6 +1,5 @@
 option('libproxy_support', type: 'boolean', value: true, description: 'support for libproxy proxy 
configration')
 option('gnome_proxy_support', type: 'boolean', value: true, description: 'support for GNOME desktop proxy 
configuration')
-option('ca_certificates_path', type: 'string', value: '', description: 'path to system Certificate Authority 
list')
 option('pkcs11_support', type: 'boolean', value: true, description: 'support for PKCS#11 using p11-kit')
 option('installed_tests', type: 'boolean', value: false, description: 'enable installed tests')
 option('static_modules', type: 'boolean', value: false, description: 'build static modules')
diff --git a/tls/gnutls/gtlsbackend-gnutls.c b/tls/gnutls/gtlsbackend-gnutls.c
index 0a6b5d4..97502d3 100644
--- a/tls/gnutls/gtlsbackend-gnutls.c
+++ b/tls/gnutls/gtlsbackend-gnutls.c
@@ -114,11 +114,7 @@ static GTlsDatabase*
 g_tls_backend_gnutls_real_create_database (GTlsBackendGnutls  *self,
                                            GError            **error)
 {
-  const gchar *anchor_file = NULL;
-#ifdef GTLS_SYSTEM_CA_FILE
-  anchor_file = GTLS_SYSTEM_CA_FILE;
-#endif
-  return g_tls_file_database_new (anchor_file, error);
+  return g_tls_file_database_new (NULL, error);
 }
 
 static void
diff --git a/tls/gnutls/gtlsfiledatabase-gnutls.c b/tls/gnutls/gtlsfiledatabase-gnutls.c
index 5a5c965..3fb7b4a 100644
--- a/tls/gnutls/gtlsfiledatabase-gnutls.c
+++ b/tls/gnutls/gtlsfiledatabase-gnutls.c
@@ -149,13 +149,24 @@ create_handle_for_certificate (const gchar *filename,
   gchar *uri;
 
   /*
-   * Here we create a URI that looks like:
+   * Here we create a URI that looks like
    * 
file:///etc/ssl/certs/ca-certificates.crt#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f
+   * or system-trust:#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f.
+   *
+   * system-trust is a meaningless URI scheme; we just need some stable way to
+   * uniquely identify these certificates.
    */
 
-  uri_part = g_filename_to_uri (filename, NULL, NULL);
-  if (!uri_part)
-    return NULL;
+  if (filename)
+    {
+      uri_part = g_filename_to_uri (filename, NULL, NULL);
+      if (!uri_part)
+        return NULL;
+    }
+  else
+    {
+      uri_part = g_strdup ("system-trust:");
+    }
 
   bookmark = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, der);
   uri = g_strconcat (uri_part, "#", bookmark, NULL);
@@ -189,40 +200,29 @@ create_handles_array_unlocked (const gchar *filename,
   return handles;
 }
 
-static gboolean
-load_anchor_file (const gchar  *filename,
-                  GHashTable   *subjects,
-                  GHashTable   *issuers,
-                  GHashTable   *complete,
-                  GError      **error)
+static void
+initialize_tables (gnutls_x509_trust_list_t  trust_list,
+                   GHashTable               *subjects,
+                   GHashTable               *issuers,
+                   GHashTable               *complete)
 {
-  GList *list, *l;
-  gnutls_x509_crt_t cert;
+  gnutls_x509_trust_list_iter_t iter = NULL;
+  gnutls_x509_crt_t cert = NULL;
   gnutls_datum_t dn;
-  GBytes *der;
-  GBytes *subject;
-  GBytes *issuer;
+  GBytes *der = NULL;
+  GBytes *subject = NULL;
+  GBytes *issuer = NULL;
   gint gerr;
-  GError *my_error = NULL;
-
-  list = g_tls_certificate_list_new_from_file (filename, &my_error);
-  if (my_error)
-    {
-      g_propagate_error (error, my_error);
-      return FALSE;
-    }
 
-  for (l = list; l; l = l->next)
+  while ((gerr = gnutls_x509_trust_list_iter_get_ca (trust_list, &iter, &cert)) == 0)
     {
-      cert = g_tls_certificate_gnutls_get_cert (l->data);
       gerr = gnutls_x509_crt_get_raw_dn (cert, &dn);
       if (gerr < 0)
         {
           g_warning ("failed to get subject of anchor certificate: %s",
                      gnutls_strerror (gerr));
-          continue;
+          goto next;
         }
-
       subject = g_bytes_new_with_free_func (dn.data, dn.size, gnutls_free, dn.data);
 
       gerr = gnutls_x509_crt_get_raw_issuer_dn (cert, &dn);
@@ -230,13 +230,18 @@ load_anchor_file (const gchar  *filename,
         {
           g_warning ("failed to get issuer of anchor certificate: %s",
                      gnutls_strerror (gerr));
-          continue;
+          goto next;
         }
-
       issuer = g_bytes_new_with_free_func (dn.data, dn.size, gnutls_free, dn.data);
 
-      der = g_tls_certificate_gnutls_get_bytes (l->data);
-      g_return_val_if_fail (der != NULL, FALSE);
+      gerr = gnutls_x509_crt_export2 (cert, GNUTLS_X509_FMT_DER, &dn);
+      if (gerr < 0)
+        {
+          g_warning ("failed to get certificate DER: %s",
+                     gnutls_strerror (gerr));
+          goto next;
+        }
+      der = g_bytes_new_with_free_func (dn.data, dn.size, gnutls_free, dn.data);
 
       /* Three different ways of looking up same certificate */
       bytes_multi_table_insert (subjects, subject, der);
@@ -245,15 +250,12 @@ load_anchor_file (const gchar  *filename,
       g_hash_table_insert (complete, g_bytes_ref (der),
                            g_bytes_ref (der));
 
-      g_bytes_unref (der);
-      g_bytes_unref (subject);
-      g_bytes_unref (issuer);
-
-      g_object_unref (l->data);
+next:
+      g_clear_pointer (&der, g_bytes_unref);
+      g_clear_pointer (&subject, g_bytes_unref);
+      g_clear_pointer (&issuer, g_bytes_unref);
+      g_clear_pointer (&cert, gnutls_x509_crt_deinit);
     }
-  g_list_free (list);
-
-  return TRUE;
 }
 
 
@@ -267,11 +269,10 @@ g_tls_file_database_gnutls_finalize (GObject *object)
   g_clear_pointer (&self->issuers, g_hash_table_destroy);
   g_clear_pointer (&self->complete, g_hash_table_destroy);
   g_clear_pointer (&self->handles, g_hash_table_destroy);
-  if (self->anchor_filename)
-    {
-      g_free (self->anchor_filename);
-      gnutls_x509_trust_list_deinit (self->trust_list, 1);
-    }
+  g_clear_pointer (&self->anchor_filename, g_free);
+
+  gnutls_x509_trust_list_deinit (self->trust_list, 1);
+
   g_mutex_clear (&self->mutex);
 
   G_OBJECT_CLASS (g_tls_file_database_gnutls_parent_class)->finalize (object);
@@ -303,6 +304,7 @@ g_tls_file_database_gnutls_set_property (GObject      *object,
 {
   GTlsFileDatabaseGnutls *self = G_TLS_FILE_DATABASE_GNUTLS (object);
   const char *anchor_path;
+  int gerr;
 
   switch (prop_id)
     {
@@ -320,11 +322,24 @@ g_tls_file_database_gnutls_set_property (GObject      *object,
           g_free (self->anchor_filename);
           gnutls_x509_trust_list_deinit (self->trust_list, 1);
         }
+
       self->anchor_filename = g_strdup (anchor_path);
       gnutls_x509_trust_list_init (&self->trust_list, 0);
-      gnutls_x509_trust_list_add_trust_file (self->trust_list,
-                                             anchor_path, NULL,
-                                             GNUTLS_X509_FMT_PEM, 0, 0);
+
+      if (self->anchor_filename)
+        {
+          gnutls_x509_trust_list_add_trust_file (self->trust_list,
+                                                 anchor_path, NULL,
+                                                 GNUTLS_X509_FMT_PEM, 0, 0);
+        }
+      else
+        {
+          gerr = gnutls_x509_trust_list_add_system_trust (self->trust_list, 0, 0);
+          if (gerr == GNUTLS_E_UNIMPLEMENTED_FEATURE)
+            g_warning ("Failed to load system trust store: gnutls_x509_trust_list_add_system_trust is not 
implemented for this platform");
+          else if (gerr < 0)
+            g_warning ("Failed to load system trust store: %s", gnutls_strerror (gerr));
+        }
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -641,7 +656,7 @@ g_tls_file_database_gnutls_initable_init (GInitable     *initable,
 {
   GTlsFileDatabaseGnutls *self = G_TLS_FILE_DATABASE_GNUTLS (initable);
   GHashTable *subjects, *issuers, *complete;
-  gboolean result;
+  gboolean result = TRUE;
 
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
     return FALSE;
@@ -653,11 +668,7 @@ g_tls_file_database_gnutls_initable_init (GInitable     *initable,
                                     (GDestroyNotify)g_bytes_unref,
                                     (GDestroyNotify)g_bytes_unref);
 
-  if (self->anchor_filename)
-    result = load_anchor_file (self->anchor_filename, subjects, issuers,
-        complete, error);
-  else
-    result = TRUE;
+  initialize_tables (self->trust_list, subjects, issuers, complete);
 
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
     result = FALSE;


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