[glib-networking/tls-database] gnutls: Supply GTlsDatabase in backend, and use for cert verification.



commit 033e8dfcc6ce428f80ee2972efa80b22931f8ece
Author: Stef Walter <stefw collabora co uk>
Date:   Tue Dec 28 04:37:16 2010 -0600

    gnutls: Supply GTlsDatabase in backend, and use for cert verification.
    
     * Replace the certificate verification with GTlsDatabase
     * Implement the necessary bits to expose the gnutls file database
       via GTlsBackend.
     * Update GTlsFileDatabaseGnutls to match GTlsFileDatabase changes.
     * GTlsFileDatabaseGnutls no longer assumes that GHashTable has
       thread-safe lookups.

 tls/gnutls/gtlsbackend-gnutls.c          |  124 ++++++++++++++---------------
 tls/gnutls/gtlsbackend-gnutls.h          |   10 +--
 tls/gnutls/gtlsclientconnection-gnutls.c |   23 +++++-
 tls/gnutls/gtlsconnection-gnutls.c       |   46 +++--------
 tls/gnutls/gtlsfiledatabase-gnutls.c     |  127 ++++++++++++++---------------
 tls/gnutls/gtlsserverconnection-gnutls.c |   25 ++++++-
 6 files changed, 181 insertions(+), 174 deletions(-)
---
diff --git a/tls/gnutls/gtlsbackend-gnutls.c b/tls/gnutls/gtlsbackend-gnutls.c
index da15b01..5028bdb 100644
--- a/tls/gnutls/gtlsbackend-gnutls.c
+++ b/tls/gnutls/gtlsbackend-gnutls.c
@@ -32,8 +32,15 @@
 #include "gtlsbackend-gnutls.h"
 #include "gtlscertificate-gnutls.h"
 #include "gtlsclientconnection-gnutls.h"
+#include "gtlsfiledatabase-gnutls.h"
 #include "gtlsserverconnection-gnutls.h"
 
+struct _GTlsBackendGnutlsPrivate
+{
+  GMutex *mutex;
+  GTlsDatabase *default_database;
+};
+
 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
 
 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendGnutls, g_tls_backend_gnutls, G_TYPE_OBJECT, 0,
@@ -120,95 +127,80 @@ g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
    * g_io_modules_scan_all_in_directory()).
    */
   g_once (&gnutls_inited, gtls_gnutls_init, NULL);
+
+  backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, G_TYPE_TLS_BACKEND_GNUTLS, GTlsBackendGnutlsPrivate);
+  backend->priv->mutex = g_mutex_new ();
 }
 
 static void
-g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
+g_tls_backend_gnutls_finalize (GObject *object)
 {
+  GTlsBackendGnutls *backend = G_TLS_BACKEND_GNUTLS (object);
+
+  if (backend->priv->default_database)
+    g_object_unref (backend->priv->default_database);
+  g_mutex_free (backend->priv->mutex);
+
+  G_OBJECT_CLASS (g_tls_backend_gnutls_parent_class)->finalize (object);
 }
 
 static void
-g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
+g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
 {
+  GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
+  gobject_class->finalize = g_tls_backend_gnutls_finalize;
+  g_type_class_add_private (backend_class, sizeof (GTlsBackendGnutlsPrivate));
 }
 
 static void
-g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
+g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
 {
-  iface->get_certificate_type       = g_tls_certificate_gnutls_get_type;
-  iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
-  iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
 }
 
-#ifdef GTLS_SYSTEM_CA_FILE
-/* Parsing the system CA list takes a noticeable amount of time.
- * So we only do it once, and only when we actually need to see it.
- */
-static const GList *
-get_ca_lists (gnutls_x509_crt_t **cas,
-	      int                *num_cas)
+static GTlsDatabase*
+g_tls_backend_gnutls_get_default_database (GTlsBackend *backend)
 {
-  static gnutls_x509_crt_t *ca_list_gnutls;
-  static int ca_list_length;
-  static GList *ca_list;
+  GTlsBackendGnutls *self = G_TLS_BACKEND_GNUTLS (backend);
+  const gchar *anchor_file = NULL;
+  GTlsDatabase *result;
+  GError *error = NULL;
 
-  if (g_once_init_enter ((volatile gsize *)&ca_list_gnutls))
-    {
-      GError *error = NULL;
-      gnutls_x509_crt_t *x509_crts;
-      GList *c;
-      int i;
+  g_mutex_lock (self->priv->mutex);
 
-      ca_list = g_tls_certificate_list_new_from_file (GTLS_SYSTEM_CA_FILE, &error);
+  if (self->priv->default_database)
+    {
+      result = g_object_ref (self->priv->default_database);
+    }
+  else
+    {
+#ifdef GTLS_SYSTEM_CA_FILE
+      anchor_file = GTLS_SYSTEM_CA_FILE;
+#endif
+      result = g_tls_file_database_new (anchor_file, &error);
       if (error)
-	{
-	  g_warning ("Failed to read system CA file %s: %s.",
-		     GTLS_SYSTEM_CA_FILE, error->message);
-	  g_error_free (error);
-	  /* Note that this is not a security problem, since if
-	   * G_TLS_VALIDATE_CA is set, then this just means validation
-	   * will always fail, and if it isn't set, then it doesn't
-	   * matter that we couldn't read the CAs.
-	   */
-	}
-
-      ca_list_length = g_list_length (ca_list);
-      x509_crts = g_new (gnutls_x509_crt_t, ca_list_length);
-      for (c = ca_list, i = 0; c; c = c->next, i++)
-	x509_crts[i] = g_tls_certificate_gnutls_get_cert (c->data);
-
-      g_once_init_leave ((volatile gsize *)&ca_list_gnutls, GPOINTER_TO_SIZE (x509_crts));
+        {
+          g_warning ("couldn't load TLS file database: %s",
+                     error->message);
+          g_clear_error (&error);
+        }
+      else
+        {
+          self->priv->default_database = g_object_ref (result);
+        }
     }
 
-  if (cas)
-    *cas = ca_list_gnutls;
-  if (num_cas)
-    *num_cas = ca_list_length;
-  
-  return ca_list;
-}
-#endif
+  g_mutex_unlock (self->priv->mutex);
 
-const GList *
-g_tls_backend_gnutls_get_system_ca_list_gtls (void)
-{
-#ifdef GTLS_SYSTEM_CA_FILE
-  return get_ca_lists (NULL, NULL);
-#else
-  return NULL;
-#endif
+  return result;
 }
-
-void
-g_tls_backend_gnutls_get_system_ca_list_gnutls (gnutls_x509_crt_t **cas,
-						int                *num_cas)
+static void
+g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
 {
-#ifdef GTLS_SYSTEM_CA_FILE
-  get_ca_lists (cas, num_cas);
-#else
-  *cas = NULL;
-  *num_cas = 0;
-#endif
+  iface->get_certificate_type       = g_tls_certificate_gnutls_get_type;
+  iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
+  iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
+  iface->get_file_database_type =     g_tls_file_database_gnutls_get_type;
+  iface->get_default_database =       g_tls_backend_gnutls_get_default_database;
 }
 
 /* Session cache support; all the details are sort of arbitrary. Note
diff --git a/tls/gnutls/gtlsbackend-gnutls.h b/tls/gnutls/gtlsbackend-gnutls.h
index 97ebd90..6ab0344 100644
--- a/tls/gnutls/gtlsbackend-gnutls.h
+++ b/tls/gnutls/gtlsbackend-gnutls.h
@@ -25,8 +25,9 @@ G_BEGIN_DECLS
 #define G_IS_TLS_BACKEND_GNUTLS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_BACKEND_GNUTLS))
 #define G_TLS_BACKEND_GNUTLS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_BACKEND_GNUTLS, GTlsBackendGnutlsClass))
 
-typedef struct _GTlsBackendGnutlsClass GTlsBackendGnutlsClass;
-typedef struct _GTlsBackendGnutls      GTlsBackendGnutls;
+typedef struct _GTlsBackendGnutls        GTlsBackendGnutls;
+typedef struct _GTlsBackendGnutlsClass   GTlsBackendGnutlsClass;
+typedef struct _GTlsBackendGnutlsPrivate GTlsBackendGnutlsPrivate;
 
 struct _GTlsBackendGnutlsClass
 {
@@ -36,15 +37,12 @@ struct _GTlsBackendGnutlsClass
 struct _GTlsBackendGnutls
 {
   GObject parent_instance;
+  GTlsBackendGnutlsPrivate *priv;
 };
 
 GType g_tls_backend_gnutls_get_type (void) G_GNUC_CONST;
 void  g_tls_backend_gnutls_register (GIOModule *module);
 
-const GList *g_tls_backend_gnutls_get_system_ca_list_gtls   (void) G_GNUC_CONST;
-void         g_tls_backend_gnutls_get_system_ca_list_gnutls (gnutls_x509_crt_t **cas,
-							     int                *num_cas);
-
 void         g_tls_backend_gnutls_cache_session_data        (const gchar *session_id,
 							     guchar      *session_data,
 							     gsize        session_data_length);
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 888f7e7..c67286b 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -316,12 +316,29 @@ g_tls_client_connection_gnutls_verify_peer (GTlsConnectionGnutls  *conn_gnutls,
 					    GTlsCertificateFlags  *errors)
 {
   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn_gnutls);
+  GTlsDatabase *database;
   gboolean accepted;
+  GError *error = NULL;
 
-  if (gnutls->priv->server_identity)
+  database = g_tls_connection_get_database (G_TLS_CONNECTION (conn_gnutls));
+  if (database == NULL)
+    {
+      *errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+      *errors |= g_tls_certificate_verify (peer_certificate, gnutls->priv->server_identity, NULL);
+    }
+  else
     {
-      *errors |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (peer_certificate),
-							   gnutls->priv->server_identity);
+      *errors |= g_tls_database_verify_chain (database, peer_certificate,
+                                              G_TLS_DATABASE_PURPOSE_SERVER_AUTH,
+                                              gnutls->priv->server_identity,
+                                              G_TLS_DATABASE_VERIFY_NONE,
+                                              NULL, &error);
+      if (error)
+        {
+          g_warning ("failure verifying certificate chain: %s",
+                     error->message);
+          g_clear_error (&error);
+        }
     }
 
   if (*errors & gnutls->priv->validation_flags)
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index c0fb898..2937996 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -98,7 +98,7 @@ enum
   PROP_BASE_IO_STREAM,
   PROP_REQUIRE_CLOSE_NOTIFY,
   PROP_REHANDSHAKE_MODE,
-  PROP_USE_SYSTEM_CERTDB,
+  PROP_DATABASE,
   PROP_CERTIFICATE,
   PROP_PEER_CERTIFICATE,
   PROP_PEER_CERTIFICATE_ERRORS
@@ -110,7 +110,6 @@ struct _GTlsConnectionGnutlsPrivate
   GPollableInputStream *base_istream;
   GPollableOutputStream *base_ostream;
 
-  GList *ca_list;
   gnutls_certificate_credentials creds;
   gnutls_session session;
 
@@ -118,7 +117,7 @@ struct _GTlsConnectionGnutlsPrivate
   GTlsCertificateFlags peer_certificate_errors;
   gboolean require_close_notify;
   GTlsRehandshakeMode rehandshake_mode;
-  gboolean use_system_certdb;
+  GTlsDatabase *database;
   gboolean need_handshake, handshaking, ever_handshaked;
   gboolean closing;
 
@@ -157,7 +156,7 @@ g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
   g_object_class_override_property (gobject_class, PROP_BASE_IO_STREAM, "base-io-stream");
   g_object_class_override_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, "require-close-notify");
   g_object_class_override_property (gobject_class, PROP_REHANDSHAKE_MODE, "rehandshake-mode");
-  g_object_class_override_property (gobject_class, PROP_USE_SYSTEM_CERTDB, "use-system-certdb");
+  g_object_class_override_property (gobject_class, PROP_DATABASE, "database");
   g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
   g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE, "peer-certificate");
   g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE_ERRORS, "peer-certificate-errors");
@@ -172,6 +171,8 @@ g_tls_connection_gnutls_initable_iface_init (GInitableIface *iface)
 static void
 g_tls_connection_gnutls_init (GTlsConnectionGnutls *gnutls)
 {
+  GTlsBackend *backend;
+
   gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls, G_TYPE_TLS_CONNECTION_GNUTLS, GTlsConnectionGnutlsPrivate);
 
   gnutls_certificate_allocate_credentials (&gnutls->priv->creds);
@@ -179,6 +180,9 @@ g_tls_connection_gnutls_init (GTlsConnectionGnutls *gnutls)
 				       GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
 
   gnutls->priv->need_handshake = TRUE;
+
+  backend = g_tls_backend_get_default ();
+  gnutls->priv->database = g_tls_backend_get_default_database (backend);
 }
 
 static gnutls_priority_t priorities[2][2];
@@ -274,6 +278,8 @@ g_tls_connection_gnutls_finalize (GObject *object)
   if (connection->priv->creds)
     gnutls_certificate_free_credentials (connection->priv->creds);
 
+  if (connection->priv->database)
+    g_object_unref (connection->priv->database);
   if (connection->priv->certificate)
     g_object_unref (connection->priv->certificate);
   if (connection->priv->peer_certificate)
@@ -307,8 +313,8 @@ g_tls_connection_gnutls_get_property (GObject    *object,
       g_value_set_enum (value, gnutls->priv->rehandshake_mode);
       break;
 
-    case PROP_USE_SYSTEM_CERTDB:
-      g_value_set_boolean (value, gnutls->priv->use_system_certdb);
+    case PROP_DATABASE:
+      g_value_set_object (value, gnutls->priv->database);
       break;
 
     case PROP_CERTIFICATE:
@@ -370,18 +376,8 @@ g_tls_connection_gnutls_set_property (GObject      *object,
       gnutls->priv->rehandshake_mode = g_value_get_enum (value);
       break;
 
-    case PROP_USE_SYSTEM_CERTDB:
-      gnutls->priv->use_system_certdb = g_value_get_boolean (value);
-
-      gnutls_certificate_free_cas (gnutls->priv->creds);
-      if (gnutls->priv->use_system_certdb)
-	{
-	  gnutls_x509_crt_t *cas;
-	  int num_cas;
-
-	  g_tls_backend_gnutls_get_system_ca_list_gnutls (&cas, &num_cas);
-	  gnutls_certificate_set_x509_trust (gnutls->priv->creds, cas, num_cas);
-	}
+    case PROP_DATABASE:
+      gnutls->priv->database = g_value_dup_object (value);
       break;
 
     case PROP_CERTIFICATE:
@@ -855,20 +851,6 @@ handshake_internal (GTlsConnectionGnutls  *gnutls,
 
   if (peer_certificate)
     {
-      int status;
-
-      status = gnutls_certificate_verify_peers (gnutls->priv->session);
-      peer_certificate_errors = g_tls_certificate_gnutls_convert_flags (status);
-      if (peer_certificate_errors)
-	{
-	  /* gnutls_certificate_verify_peers() bails out on the first
-	   * error, which may be G_TLS_CERTIFICATE_UNKNOWN_CA, but the
-	   * caller may be planning to check that part themselves. So
-	   * call g_tls_certificate_verify() to get any other errors.
-	   */
-	  peer_certificate_errors |= g_tls_certificate_verify (peer_certificate, NULL, NULL);
-	}
-
       if (!G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->verify_peer (gnutls, peer_certificate, &peer_certificate_errors))
 	{
 	  g_object_unref (peer_certificate);
diff --git a/tls/gnutls/gtlsfiledatabase-gnutls.c b/tls/gnutls/gtlsfiledatabase-gnutls.c
index 4917867..34cfe31 100644
--- a/tls/gnutls/gtlsfiledatabase-gnutls.c
+++ b/tls/gnutls/gtlsfiledatabase-gnutls.c
@@ -28,13 +28,21 @@
 #include <glib/gi18n-lib.h>
 #include <gnutls/x509.h>
 
-G_DEFINE_TYPE (GTlsFileDatabaseGnutls, g_tls_file_database_gnutls,
-               G_TYPE_TLS_DATABASE_GNUTLS);
+static void g_tls_file_database_gnutls_file_database_interface_init (GTlsFileDatabaseInterface *iface);
+
+static void g_tls_file_database_gnutls_initable_interface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsFileDatabaseGnutls, g_tls_file_database_gnutls, G_TYPE_TLS_DATABASE_GNUTLS,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_TLS_FILE_DATABASE,
+                                                g_tls_file_database_gnutls_file_database_interface_init);
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                g_tls_file_database_gnutls_initable_interface_init);
+);
 
 enum
 {
   PROP_0,
-  PROP_ANCHOR_FILENAME,
+  PROP_ANCHOR_FILE,
 };
 
 struct _GTlsFileDatabaseGnutlsPrivate
@@ -43,7 +51,7 @@ struct _GTlsFileDatabaseGnutlsPrivate
   gchar *anchor_filename;
 
   /* protected by mutex */
-  GStaticMutex mutex;
+  GMutex *mutex;
   GHashTable *anchors;
 };
 
@@ -142,48 +150,6 @@ load_anchor_file (const gchar *filename,
   return TRUE;
 }
 
-static GHashTable*
-ensure_and_ref_anchors (GTlsFileDatabaseGnutls *self)
-{
-  GHashTable *anchors;
-  GError *error = NULL;
-
-  g_static_mutex_lock (&self->priv->mutex);
-
-  if (self->priv->anchors)
-    {
-      anchors = g_hash_table_ref (self->priv->anchors);
-    }
-  else
-    {
-      anchors = g_hash_table_new_full (byte_array_hash, byte_array_equal,
-                                       (GDestroyNotify)g_byte_array_unref,
-                                       (GDestroyNotify)g_byte_array_unref);
-
-      if (load_anchor_file (self->priv->anchor_filename, anchors, &error))
-        {
-          self->priv->anchors = g_hash_table_ref (anchors);
-        }
-      else
-        {
-          /*
-           * Note that this is not a security problem, since if
-           * G_TLS_VALIDATE_CA is set, then this just means validation
-           * will always fail, and if it isn't set, then it doesn't
-           * matter that we couldn't read the CAs.
-           */
-          g_warning ("couldn't load certificate anchor file: %s: %s",
-                     self->priv->anchor_filename,
-                     error && error->message ? error->message : "");
-        }
-    }
-
-  g_static_mutex_unlock (&self->priv->mutex);
-
-  /* We always return one, even if it's just empty */
-  return anchors;
-}
-
 static void
 g_tls_file_database_gnutls_finalize (GObject *object)
 {
@@ -195,7 +161,7 @@ g_tls_file_database_gnutls_finalize (GObject *object)
   g_free (self->priv->anchor_filename);
   self->priv->anchor_filename = NULL;
 
-  g_static_mutex_free (&self->priv->mutex);
+  g_mutex_free (self->priv->mutex);
 
   G_OBJECT_CLASS (g_tls_file_database_gnutls_parent_class)->finalize (object);
 }
@@ -210,7 +176,7 @@ g_tls_file_database_gnutls_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_ANCHOR_FILENAME:
+    case PROP_ANCHOR_FILE:
       g_value_set_string (value, self->priv->anchor_filename);
       break;
     default:
@@ -228,7 +194,7 @@ g_tls_file_database_gnutls_set_property (GObject      *object,
 
   switch (prop_id)
     {
-    case PROP_ANCHOR_FILENAME:
+    case PROP_ANCHOR_FILE:
       self->priv->anchor_filename = g_value_dup_string (value);
       break;
     default:
@@ -242,7 +208,7 @@ g_tls_file_database_gnutls_init (GTlsFileDatabaseGnutls *self)
   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
                                             G_TYPE_TLS_FILE_DATABASE_GNUTLS,
                                             GTlsFileDatabaseGnutlsPrivate);
-  g_static_mutex_init (&self->priv->mutex);
+  self->priv->mutex = g_mutex_new ();
 }
 
 static gboolean
@@ -257,7 +223,6 @@ g_tls_file_database_gnutls_lookup_assertion (GTlsDatabaseGnutls          *databa
   GTlsFileDatabaseGnutls *self = G_TLS_FILE_DATABASE_GNUTLS (database);
   GByteArray *der = NULL;
   gboolean contains;
-  GHashTable *anchors;
 
   g_return_val_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (certificate), FALSE);
   g_return_val_if_fail (purpose, FALSE);
@@ -276,10 +241,11 @@ g_tls_file_database_gnutls_lookup_assertion (GTlsDatabaseGnutls          *databa
   g_object_get (certificate, "certificate", &der, NULL);
   g_return_val_if_fail (der, FALSE);
 
-  anchors = ensure_and_ref_anchors (self);
-  contains = g_hash_table_lookup (anchors, der) ? TRUE : FALSE;
+  g_mutex_lock (self->priv->mutex);
+  contains = g_hash_table_lookup (self->priv->anchors, der) ? TRUE : FALSE;
+  g_mutex_unlock (self->priv->mutex);
+
   g_byte_array_unref (der);
-  g_hash_table_unref (anchors);
 
   /* All certificates in our file are anchored certificates */
   return contains;
@@ -294,7 +260,6 @@ g_tls_file_database_gnutls_lookup_issuer (GTlsDatabase          *database,
   GTlsFileDatabaseGnutls *self = G_TLS_FILE_DATABASE_GNUTLS (database);
   gnutls_datum_t dn = { NULL, 0 };
   GByteArray *subject, *der;
-  GHashTable *anchors;
   gnutls_datum_t datum;
   GTlsCertificate *issuer = NULL;
   gnutls_x509_crt_t cert;
@@ -317,8 +282,9 @@ g_tls_file_database_gnutls_lookup_issuer (GTlsDatabase          *database,
   gnutls_free (dn.data);
 
   /* Find the full DER value of the certificate */
-  anchors = ensure_and_ref_anchors (self);
-  der = g_hash_table_lookup (anchors, subject);
+  g_mutex_lock (self->priv->mutex);
+  der = g_hash_table_lookup (self->priv->anchors, subject);
+  g_mutex_unlock (self->priv->mutex);
 
   g_byte_array_unref (subject);
 
@@ -329,7 +295,6 @@ g_tls_file_database_gnutls_lookup_issuer (GTlsDatabase          *database,
       issuer = g_tls_certificate_gnutls_new (&datum, NULL);
     }
 
-  g_hash_table_unref (anchors);
   return issuer;
 }
 
@@ -349,12 +314,42 @@ g_tls_file_database_gnutls_class_init (GTlsFileDatabaseGnutlsClass *klass)
   database_class->lookup_issuer = g_tls_file_database_gnutls_lookup_issuer;
   gnutls_class->lookup_assertion = g_tls_file_database_gnutls_lookup_assertion;
 
-  g_object_class_install_property (gobject_class, PROP_ANCHOR_FILENAME,
-                                   g_param_spec_string ("anchor-filename",
-                                                         N_("Anchor Filename"),
-                                                         N_("Path to system certificate anchor file"),
-                                                         NULL,
-                                                         G_PARAM_READWRITE |
-                                                         G_PARAM_CONSTRUCT |
-                                                         G_PARAM_STATIC_STRINGS));
+  g_object_class_override_property (gobject_class, PROP_ANCHOR_FILE, "anchor-file");
+}
+
+static void
+g_tls_file_database_gnutls_file_database_interface_init (GTlsFileDatabaseInterface *iface)
+{
+
+}
+
+static gboolean
+g_tls_file_database_gnutls_initable_init (GInitable    *initable,
+                                          GCancellable *cancellable,
+                                          GError      **error)
+{
+  GTlsFileDatabaseGnutls *self = G_TLS_FILE_DATABASE_GNUTLS (initable);
+  GHashTable *anchors;
+
+  anchors = g_hash_table_new_full (byte_array_hash, byte_array_equal,
+                                   (GDestroyNotify)g_byte_array_unref,
+                                   (GDestroyNotify)g_byte_array_unref);
+
+  if (!load_anchor_file (self->priv->anchor_filename, anchors, error))
+    {
+      g_hash_table_unref (anchors);
+      return FALSE;
+    }
+
+  g_mutex_lock (self->priv->mutex);
+  g_assert (!self->priv->anchors);
+  self->priv->anchors = anchors;
+  g_mutex_unlock (self->priv->mutex);
+  return TRUE;
+}
+
+static void
+g_tls_file_database_gnutls_initable_interface_init (GInitableIface *iface)
+{
+  iface->init = g_tls_file_database_gnutls_initable_init;
 }
diff --git a/tls/gnutls/gtlsserverconnection-gnutls.c b/tls/gnutls/gtlsserverconnection-gnutls.c
index e374b63..2223277 100644
--- a/tls/gnutls/gtlsserverconnection-gnutls.c
+++ b/tls/gnutls/gtlsserverconnection-gnutls.c
@@ -174,8 +174,31 @@ g_tls_server_connection_gnutls_verify_peer (GTlsConnectionGnutls  *gnutls,
 					    GTlsCertificate       *peer_certificate,
 					    GTlsCertificateFlags  *errors)
 {
+  GTlsDatabase *database;
+  GError *error = NULL;
+
+  database = g_tls_connection_get_database (G_TLS_CONNECTION (gnutls));
+  if (database == NULL)
+    {
+      *errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+      *errors |= g_tls_certificate_verify (peer_certificate, NULL, NULL);
+    }
+  else
+    {
+      *errors |= g_tls_database_verify_chain (database, peer_certificate,
+                                              G_TLS_DATABASE_PURPOSE_CLIENT_AUTH,
+                                              NULL, G_TLS_DATABASE_VERIFY_NONE,
+                                              NULL, &error);
+      if (error)
+        {
+          g_warning ("failure verifying certificate chain: %s",
+                     error->message);
+          g_clear_error (&error);
+        }
+    }
+
   return g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls),
-						   peer_certificate, *errors);
+                                                   peer_certificate, *errors);
 }
 
 static void



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