Commit f1c8feee authored by Michael Catanzaro's avatar Michael Catanzaro
Browse files

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
parent 8f8f47b9
#!/usr/bin/env python3
import errno
import os
import sys
locations = [ '/etc/pki/tls/certs/ca-bundle.crt',
'/etc/ssl/certs/ca-certificates.crt',
'/etc/ssl/ca-bundle.pem'
]
if len(sys.argv) > 1:
locations.insert(0, sys.argv[1])
for location in locations:
if os.path.isfile(location):
sys.stdout.write(location)
sys.exit(0)
sys.exit(errno.ENOENT)
......@@ -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)
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')
......@@ -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
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment