diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml
index d67b79e..c7e511e 100644
--- a/docs/reference/gio/gio-docs.xml
+++ b/docs/reference/gio/gio-docs.xml
@@ -138,6 +138,10 @@
       <xi:include href="xml/gtlsclientconnection.xml"/>
       <xi:include href="xml/gtlsserverconnection.xml"/>
       <xi:include href="xml/gtlsbackend.xml"/>
+      <xi:include href="xml/gtlsdatabase.xml"/>
+      <xi:include href="xml/gtlsfiledatabase.xml"/>
+      <xi:include href="xml/gtlsinteraction.xml"/>
+      <xi:include href="xml/gtlspassword.xml"/>
     </chapter>
     <chapter id="resolver">
       <title>DNS resolution</title>
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 87617a6..203aab0 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -3020,9 +3020,11 @@ GTlsBackend
 GTlsBackendInterface
 g_tls_backend_get_default
 g_tls_backend_supports_tls
+g_tls_backend_get_default_database
 g_tls_backend_get_certificate_type
 g_tls_backend_get_client_connection_type
 g_tls_backend_get_server_connection_type
+g_tls_backend_get_file_database_type
 <SUBSECTION Standard>
 G_IS_TLS_BACKEND
 G_TLS_BACKEND
@@ -3071,6 +3073,10 @@ g_tls_connection_set_rehandshake_mode
 g_tls_connection_get_rehandshake_mode
 g_tls_connection_set_use_system_certdb
 g_tls_connection_get_use_system_certdb
+g_tls_connection_get_database
+g_tls_connection_set_database
+g_tls_connection_get_interaction
+g_tls_connection_set_interaction
 <SUBSECTION>
 g_tls_connection_handshake
 g_tls_connection_handshake_async
@@ -3113,6 +3119,58 @@ g_tls_client_connection_get_type
 </SECTION>
 
 <SECTION>
+<FILE>gtlsdatabase</FILE>
+<TITLE>GTlsDatabase</TITLE>
+GTlsDatabase
+GTlsDatabaseVerifyFlags
+G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER
+G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT
+g_tls_database_verify_chain
+g_tls_database_verify_chain_async
+g_tls_database_verify_chain_finish
+GTlsDatabaseLookupFlags
+g_tls_database_lookup_certificate_issuer
+g_tls_database_lookup_certificate_issuer_async
+g_tls_database_lookup_certificate_issuer_finish
+g_tls_database_lookup_certificates_issued_by
+g_tls_database_lookup_certificates_issued_by_async
+g_tls_database_lookup_certificates_issued_by_finish
+g_tls_database_create_certificate_handle
+g_tls_database_lookup_certificate_for_handle
+g_tls_database_lookup_certificate_for_handle_async
+g_tls_database_lookup_certificate_for_handle_finish
+<SUBSECTION Standard>
+G_IS_TLS_DATABASE
+G_IS_TLS_DATABASE_CLASS
+G_TLS_DATABASE
+G_TLS_DATABASE_CLASS
+G_TLS_DATABASE_GET_CLASS
+G_TYPE_TLS_DATABASE
+G_TYPE_TLS_DATABASE_LOOKUP_FLAGS
+G_TYPE_TLS_DATABASE_VERIFY_FLAGS
+<SUBSECTION Private>
+g_tls_database_lookup_flags_get_type
+g_tls_database_verify_flags_get_type
+g_tls_database_get_type
+GTlsDatabasePrivate
+</SECTION>
+
+<SECTION>
+<FILE>gtlsfiledatabase</FILE>
+<TITLE>GTlsFileDatabase</TITLE>
+GTlsFileDatabase
+GTlsFileDatabaseInterface
+g_tls_file_database_new
+<SUBSECTION Standard>
+G_TLS_FILE_DATABASE
+G_TLS_FILE_DATABASE_GET_INTERFACE
+G_TYPE_TLS_FILE_DATABASE
+G_IS_TLS_FILE_DATABASE
+<SUBSECTION Private>
+g_tls_file_database_get_type
+</SECTION>
+
+<SECTION>
 <FILE>gtlsserverconnection</FILE>
 <TITLE>GTlsServerConnection</TITLE>
 GTlsServerConnection
@@ -3128,6 +3186,59 @@ g_tls_server_connection_get_type
 </SECTION>
 
 <SECTION>
+<FILE>gtlspassword</FILE>
+<TITLE>GTlsPassword</TITLE>
+GTlsPassword
+GTlsPasswordInterface
+GTlsPasswordFlags
+g_tls_password_set_value
+g_tls_password_take_value
+g_tls_password_get_value
+g_tls_password_get_description
+g_tls_password_get_flags
+<SUBSECTION Standard>
+g_tls_password_flags_get_type
+g_tls_password_get_type
+G_IS_TLS_PASSWORD
+G_TLS_PASSWORD
+G_TLS_PASSWORD_GET_INTERFACE
+G_TYPE_TLS_PASSWORD
+G_TYPE_TLS_PASSWORD_FLAGS
+</SECTION>
+
+<SECTION>
+<FILE>gtlsinteraction</FILE>
+<TITLE>GTlsInteraction</TITLE>
+GTlsInteraction
+GTlsInteractionResult
+g_tls_interaction_ask_password
+g_tls_interaction_ask_password_finish
+<SUBSECTION Standard>
+GTlsInteractionClass
+G_IS_TLS_INTERACTION
+G_IS_TLS_INTERACTION_CLASS
+G_TYPE_TLS_INTERACTION
+G_TLS_INTERACTION
+G_TLS_INTERACTION_CLASS
+G_TLS_INTERACTION_GET_CLASS
+G_TYPE_TLS_INTERACTION_RESULT
+<SUBSECTION Private>
+GTlsInteractionPrivate
+g_tls_interaction_get_type
+g_tls_interaction_result_get_type
+GTlsConsoleInteraction
+GTlsConsoleInteractionClass
+G_IS_TLS_CONSOLE_INTERACTION
+G_IS_TLS_CONSOLE_INTERACTION_CLASS
+g_tls_console_interaction_new
+G_TLS_CONSOLE_INTERACTION
+G_TYPE_TLS_CONSOLE_INTERACTION
+G_TLS_CONSOLE_INTERACTION_CLASS
+G_TLS_CONSOLE_INTERACTION_GET_CLASS
+g_tls_console_interaction_get_type
+</SECTION>
+
+<SECTION>
 <FILE>gtimezonemonitor</FILE>
 <TITLE>GTimeZoneMonitor</TITLE>
 GTimeZoneMonitor
diff --git a/docs/reference/gio/gio.types b/docs/reference/gio/gio.types
index 335e0eb..685a900 100644
--- a/docs/reference/gio/gio.types
+++ b/docs/reference/gio/gio.types
@@ -110,6 +110,8 @@ g_tls_backend_get_type
 g_tls_certificate_get_type
 g_tls_client_connection_get_type
 g_tls_connection_get_type
+g_tls_database_get_type
+g_tls_file_database_get_type
 g_tls_server_connection_get_type
 g_unix_connection_get_type
 g_unix_fd_list_get_type
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 7bd6618..c411d6f 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -381,7 +381,11 @@ libgio_2_0_la_SOURCES =		\
 	gtlscertificate.c	\
 	gtlsclientconnection.c	\
 	gtlsconnection.c	\
+	gtlsdatabase.c		\
+	gtlsfiledatabase.c	\
+	gtlsinteraction.c	\
 	gtlsserverconnection.c	\
+	gtlspassword.c		\
 	gunionvolumemonitor.c 	\
 	gunionvolumemonitor.h 	\
 	gvfs.c 			\
@@ -532,7 +536,11 @@ gio_headers =			\
 	gtlscertificate.h	\
 	gtlsclientconnection.h	\
 	gtlsconnection.h	\
+	gtlsdatabase.h		\
+	gtlsfiledatabase.h	\
+	gtlsinteraction.h	\
 	gtlsserverconnection.h	\
+	gtlspassword.h		\
 	gvfs.h 			\
 	gvolume.h 		\
 	gvolumemonitor.h 	\
diff --git a/gio/gdummytlsbackend.c b/gio/gdummytlsbackend.c
index f297f74..5a2463b 100644
--- a/gio/gdummytlsbackend.c
+++ b/gio/gdummytlsbackend.c
@@ -30,6 +30,8 @@
 #include "gtlsbackend.h"
 #include "gtlscertificate.h"
 #include "gtlsclientconnection.h"
+#include "gtlsdatabase.h"
+#include "gtlsfiledatabase.h"
 #include "gtlsserverconnection.h"
 #include "gsimpleasyncresult.h"
 
@@ -40,9 +42,11 @@
 
 static GType _g_dummy_tls_certificate_get_type (void);
 static GType _g_dummy_tls_connection_get_type (void);
+static GType _g_dummy_tls_database_get_type (void);
 
 struct _GDummyTlsBackend {
-  GObject parent_instance;
+  GObject       parent_instance;
+  GTlsDatabase *database;
 };
 
 static void g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface);
@@ -67,12 +71,20 @@ g_dummy_tls_backend_class_init (GDummyTlsBackendClass *backend_class)
 {
 }
 
+static GTlsDatabase*
+g_dummy_tls_backend_get_default_database (GTlsBackend *backend)
+{
+  return g_object_new (_g_dummy_tls_database_get_type (), NULL);
+}
+
 static void
 g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface)
 {
   iface->get_certificate_type = _g_dummy_tls_certificate_get_type;
   iface->get_client_connection_type = _g_dummy_tls_connection_get_type;
   iface->get_server_connection_type = _g_dummy_tls_connection_get_type;
+  iface->get_file_database_type = _g_dummy_tls_database_get_type;
+  iface->get_default_database = g_dummy_tls_backend_get_default_database;
 }
 
 /* Dummy certificate type */
@@ -188,6 +200,7 @@ enum
   PROP_CONN_REQUIRE_CLOSE_NOTIFY,
   PROP_CONN_REHANDSHAKE_MODE,
   PROP_CONN_CERTIFICATE,
+  PROP_CONN_DATABASE,
   PROP_CONN_PEER_CERTIFICATE,
   PROP_CONN_PEER_CERTIFICATE_ERRORS,
   PROP_CONN_VALIDATION_FLAGS,
@@ -251,6 +264,7 @@ g_dummy_tls_connection_class_init (GDummyTlsConnectionClass *connection_class)
   g_object_class_override_property (gobject_class, PROP_CONN_REQUIRE_CLOSE_NOTIFY, "require-close-notify");
   g_object_class_override_property (gobject_class, PROP_CONN_REHANDSHAKE_MODE, "rehandshake-mode");
   g_object_class_override_property (gobject_class, PROP_CONN_CERTIFICATE, "certificate");
+  g_object_class_override_property (gobject_class, PROP_CONN_DATABASE, "database");
   g_object_class_override_property (gobject_class, PROP_CONN_PEER_CERTIFICATE, "peer-certificate");
   g_object_class_override_property (gobject_class, PROP_CONN_PEER_CERTIFICATE_ERRORS, "peer-certificate-errors");
   g_object_class_override_property (gobject_class, PROP_CONN_VALIDATION_FLAGS, "validation-flags");
@@ -281,3 +295,92 @@ g_dummy_tls_connection_initable_iface_init (GInitableIface  *iface)
   iface->init = g_dummy_tls_connection_initable_init;
 }
 
+/* Dummy database type.
+ */
+
+typedef struct _GDummyTlsDatabase      GDummyTlsDatabase;
+typedef struct _GDummyTlsDatabaseClass GDummyTlsDatabaseClass;
+
+struct _GDummyTlsDatabase {
+  GTlsDatabase parent_instance;
+};
+
+struct _GDummyTlsDatabaseClass {
+  GTlsDatabaseClass parent_class;
+};
+
+enum
+{
+  PROP_DATABASE_0,
+
+  PROP_ANCHORS,
+};
+
+static void g_dummy_tls_database_file_database_iface_init (GTlsFileDatabaseInterface *iface);
+static void g_dummy_tls_database_initable_iface_init (GInitableIface *iface);
+
+#define g_dummy_tls_database_get_type _g_dummy_tls_database_get_type
+G_DEFINE_TYPE_WITH_CODE (GDummyTlsDatabase, g_dummy_tls_database, G_TYPE_TLS_DATABASE,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_TLS_FILE_DATABASE,
+                                                g_dummy_tls_database_file_database_iface_init);
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                g_dummy_tls_database_initable_iface_init);)
+
+
+static void
+g_dummy_tls_database_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  /* We need to define this method to make GObject happy, but it will
+   * never be possible to construct a working GDummyTlsDatabase, so
+   * it doesn't have to do anything useful.
+   */
+}
+
+static void
+g_dummy_tls_database_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  /* Just ignore all attempts to set properties. */
+}
+
+static void
+g_dummy_tls_database_class_init (GDummyTlsDatabaseClass *database_class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (database_class);
+
+  gobject_class->get_property = g_dummy_tls_database_get_property;
+  gobject_class->set_property = g_dummy_tls_database_set_property;
+
+  g_object_class_override_property (gobject_class, PROP_ANCHORS, "anchors");
+}
+
+static void
+g_dummy_tls_database_init (GDummyTlsDatabase *database)
+{
+}
+
+static void
+g_dummy_tls_database_file_database_iface_init (GTlsFileDatabaseInterface  *iface)
+{
+}
+
+static gboolean
+g_dummy_tls_database_initable_init (GInitable       *initable,
+                                    GCancellable    *cancellable,
+                                    GError         **error)
+{
+  g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_UNAVAILABLE,
+                       _("TLS support is not available"));
+  return FALSE;
+}
+
+static void
+g_dummy_tls_database_initable_iface_init (GInitableIface  *iface)
+{
+  iface->init = g_dummy_tls_database_initable_init;
+}
diff --git a/gio/gio.h b/gio/gio.h
index 2958059..9281dde 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -124,7 +124,11 @@
 #include <gio/gtlscertificate.h>
 #include <gio/gtlsclientconnection.h>
 #include <gio/gtlsconnection.h>
+#include <gio/gtlsdatabase.h>
+#include <gio/gtlsfiledatabase.h>
+#include <gio/gtlsinteraction.h>
 #include <gio/gtlsserverconnection.h>
+#include <gio/gtlspassword.h>
 #include <gio/gvfs.h>
 #include <gio/gvolume.h>
 #include <gio/gvolumemonitor.h>
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 00d5328..07eec98 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -781,6 +781,7 @@ g_tls_authentication_mode_get_type
 g_tls_certificate_flags_get_type
 g_tls_rehandshake_mode_get_type
 g_emblemed_icon_get_type
+g_tls_database_verify_flags_get_type
 g_emblemed_icon_new
 g_emblemed_icon_get_icon
 g_emblemed_icon_get_emblems
@@ -1420,6 +1421,7 @@ g_tls_certificate_new_from_pem
 g_tls_certificate_verify
 g_tls_connection_emit_accept_certificate
 g_tls_connection_get_certificate
+g_tls_connection_get_interaction
 g_tls_connection_get_peer_certificate
 g_tls_connection_get_peer_certificate_errors
 g_tls_connection_get_rehandshake_mode
@@ -1430,6 +1432,7 @@ g_tls_connection_handshake
 g_tls_connection_handshake_async
 g_tls_connection_handshake_finish
 g_tls_connection_set_certificate
+g_tls_connection_set_interaction
 g_tls_connection_set_rehandshake_mode
 g_tls_connection_set_require_close_notify
 g_tls_connection_set_use_system_certdb
@@ -1444,6 +1447,24 @@ g_tls_client_connection_set_use_ssl3
 g_tls_client_connection_set_validation_flags
 g_tls_server_connection_get_type
 g_tls_server_connection_new
+g_tls_database_get_type
+g_tls_database_lookup_issuer
+g_tls_database_lookup_issuer_async
+g_tls_database_lookup_issuer_finish
+g_tls_database_verify_chain
+g_tls_database_verify_chain_async
+g_tls_database_verify_chain_finish
+g_tls_file_database_get_type
+g_tls_file_database_new
+g_tls_interaction_get_type
+g_tls_interaction_ask_password
+g_tls_interaction_ask_password_finish
+g_tls_password_get_type
+g_tls_password_get_value
+g_tls_password_set_value
+g_tls_password_take_value
+g_tls_password_get_flags
+g_tls_password_get_description
 g_time_zone_monitor_get_type
 g_time_zone_monitor_get
 g_dbus_interface_get_info
diff --git a/gio/gioenums.h b/gio/gioenums.h
index 4ea72a9..b724f2a 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1393,6 +1393,48 @@ typedef enum {
 } GTlsRehandshakeMode;
 
 /**
+ * GTlsPasswordFlags:
+ * @G_TLS_PASSWORD_NONE: No flags
+ * @G_TLS_PASSWORD_RETRY: The password was wrong, and the user should retry.
+ * @G_TLS_PASSWORD_MANY_TRIES: Hint to the user that the password has been
+ *    wrong many times, and the user may not have many chances left.
+ * @G_TLS_PASSWORD_FINAL_TRY: Hint to the user that this is the last try to get
+ *    this password right.
+ *
+ * Various flags for the password.
+ *
+ * Since: 2.30
+ */
+
+typedef enum _GTlsPasswordFlags
+{
+  G_TLS_PASSWORD_NONE = 0,
+  G_TLS_PASSWORD_RETRY = 1 << 1,
+  G_TLS_PASSWORD_MANY_TRIES = 1 << 2,
+  G_TLS_PASSWORD_FINAL_TRY = 1 << 3
+} GTlsPasswordFlags;
+
+/**
+ * GTlsInteractionResult:
+ * @G_TLS_INTERACTION_HANDLED: The interaction completed, and resulting data
+ *     is available.
+ * @G_TLS_INTERACTION_ABORTED: The user cancelled the interaction, and requested
+ *     the operation to be aborted.
+ * @G_TLS_INTERACTION_UNHANDLED: The interaction was unhandled (i.e. not
+ *     implemented).
+ *
+ * #GTlsInteractionResult is returned by various functions in #GTlsInteraction
+ * when finishing an interaction request.
+ *
+ * Since: 2.30
+ */
+typedef enum {
+  G_TLS_INTERACTION_HANDLED,
+  G_TLS_INTERACTION_ABORTED,
+  G_TLS_INTERACTION_UNHANDLED
+} GTlsInteractionResult;
+
+/**
  * GDBusInterfaceSkeletonFlags:
  * @G_DBUS_INTERFACE_SKELETON_FLAGS_NONE: No flags set.
  * @G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD: Each method invocation is handled in
@@ -1428,6 +1470,34 @@ typedef enum
   G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START = (1<<0)
 } GDBusObjectManagerClientFlags;
 
+/**
+ * GTlsDatabaseVerifyFlags:
+ * @G_TLS_DATABASE_VERIFY_NONE: No verification flags
+ *
+ * Flags for g_tls_database_verify_chain().
+ *
+ * Since: 2.30
+ */
+typedef enum {
+  G_TLS_DATABASE_VERIFY_NONE = 0,
+} GTlsDatabaseVerifyFlags;
+
+/**
+ * GTlsDatabaseLookupFlags:
+ * @G_TLS_DATABASE_LOOKUP_NONE: No lookup flags
+ * @G_TLS_DATABASE_LOOKUP_KEYPAIR: Restrict lookup to certificates that have
+ *     a private key.
+ *
+ * Flags for g_tls_database_lookup_handle(), g_tls_database_lookup_issuer(),
+ * and g_tls_database_lookup_issued().
+ *
+ * Since: 2.30
+ */
+typedef enum {
+  G_TLS_DATABASE_LOOKUP_NONE = 0,
+  G_TLS_DATABASE_LOOKUP_KEYPAIR = 1,
+} GTlsDatabaseLookupFlags;
+
 G_END_DECLS
 
 #endif /* __GIO_ENUMS_H__ */
diff --git a/gio/giotypes.h b/gio/giotypes.h
index af27586..4deba75 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -206,6 +206,11 @@ typedef struct _GThemedIcon                   GThemedIcon;
 typedef struct _GTlsCertificate               GTlsCertificate;
 typedef struct _GTlsClientConnection          GTlsClientConnection; /* Dummy typedef */
 typedef struct _GTlsConnection                GTlsConnection;
+typedef struct _GTlsContext                   GTlsContext;
+typedef struct _GTlsDatabase                  GTlsDatabase;
+typedef struct _GTlsFileDatabase              GTlsFileDatabase;
+typedef struct _GTlsInteraction               GTlsInteraction;
+typedef struct _GTlsPassword                  GTlsPassword; /* Dummy typedef */
 typedef struct _GTlsServerConnection          GTlsServerConnection; /* Dummy typedef */
 typedef struct _GVfs                          GVfs; /* Dummy typedef */
 
diff --git a/gio/gtlsbackend.c b/gio/gtlsbackend.c
index a87137f..d528c5d 100644
--- a/gio/gtlsbackend.c
+++ b/gio/gtlsbackend.c
@@ -150,6 +150,24 @@ g_tls_backend_supports_tls (GTlsBackend *backend)
 }
 
 /**
+ * g_tls_backend_get_default_database:
+ * @backend: the #GTlsBackend
+ *
+ * Gets the default #GTlsDatabase used to verify TLS connections.
+ *
+ * Return value: the default database, which should be unreffed when done.
+ *
+ * Since: 2.30
+ */
+GTlsDatabase *
+g_tls_backend_get_default_database (GTlsBackend *backend)
+{
+  g_return_val_if_fail (G_IS_TLS_BACKEND (backend), NULL);
+  g_return_val_if_fail (G_TLS_BACKEND_GET_INTERFACE (backend)->get_default_database, NULL);
+  return G_TLS_BACKEND_GET_INTERFACE (backend)->get_default_database (backend);
+}
+
+/**
  * g_tls_backend_get_certificate_type:
  * @backend: the #GTlsBackend
  *
@@ -199,3 +217,19 @@ g_tls_backend_get_server_connection_type (GTlsBackend *backend)
 {
   return G_TLS_BACKEND_GET_INTERFACE (backend)->get_server_connection_type ();
 }
+
+/**
+ * g_tls_backend_get_file_database_type:
+ * @backend: the #GTlsBackend
+ *
+ * Gets the #GTyep of @backend's #GTlsFileDatabase implementation.
+ *
+ * Return value: the #GType of backend's #GTlsFileDatabase implementation.
+ *
+ * Since: 2.30
+ */
+GType
+g_tls_backend_get_file_database_type (GTlsBackend *backend)
+{
+  return G_TLS_BACKEND_GET_INTERFACE (backend)->get_file_database_type ();
+}
diff --git a/gio/gtlsbackend.h b/gio/gtlsbackend.h
index 24ae911..813dc55 100644
--- a/gio/gtlsbackend.h
+++ b/gio/gtlsbackend.h
@@ -58,9 +58,12 @@ typedef struct _GTlsBackendInterface GTlsBackendInterface;
 /**
  * GTlsBackendInterface:
  * @g_iface: The parent interface.
+ * @supports_tls: returns whether the backend supports TLS.
+ * @get_default_database: returns a default #GTlsDatabase instance.
  * @get_certificate_type: returns the #GTlsCertificate implementation type
  * @get_client_connection_type: returns the #GTlsClientConnection implementation type
  * @get_server_connection_type: returns the #GTlsServerConnection implementation type
+ * @get_file_database_type: returns the #GTlsFileDatabase implementation type.
  *
  * Provides an interface for describing TLS-related types.
  *
@@ -71,21 +74,26 @@ struct _GTlsBackendInterface
   GTypeInterface g_iface;
 
   /* methods */
-  gboolean ( *supports_tls)               (GTlsBackend *backend);
-  GType    ( *get_certificate_type)       (void);
-  GType    ( *get_client_connection_type) (void);
-  GType    ( *get_server_connection_type) (void);
+  gboolean       ( *supports_tls)               (GTlsBackend *backend);
+  GTlsDatabase * ( *get_default_database)       (GTlsBackend *backend);
+  GType          ( *get_certificate_type)       (void);
+  GType          ( *get_client_connection_type) (void);
+  GType          ( *get_server_connection_type) (void);
+  GType          ( *get_file_database_type)     (void);
 };
 
-GType        g_tls_backend_get_type                   (void) G_GNUC_CONST;
+GType          g_tls_backend_get_type                   (void) G_GNUC_CONST;
 
-GTlsBackend *g_tls_backend_get_default                (void);
+GTlsBackend *  g_tls_backend_get_default                (void);
 
-gboolean     g_tls_backend_supports_tls               (GTlsBackend *backend);
+GTlsDatabase * g_tls_backend_get_default_database       (GTlsBackend *backend);
 
-GType        g_tls_backend_get_certificate_type       (GTlsBackend *backend);
-GType        g_tls_backend_get_client_connection_type (GTlsBackend *backend);
-GType        g_tls_backend_get_server_connection_type (GTlsBackend *backend);
+gboolean       g_tls_backend_supports_tls               (GTlsBackend *backend);
+
+GType          g_tls_backend_get_certificate_type       (GTlsBackend *backend);
+GType          g_tls_backend_get_client_connection_type (GTlsBackend *backend);
+GType          g_tls_backend_get_server_connection_type (GTlsBackend *backend);
+GType          g_tls_backend_get_file_database_type     (GTlsBackend *backend);
 
 G_END_DECLS
 
diff --git a/gio/gtlsconnection.c b/gio/gtlsconnection.c
index 74da0e4..4cbf7b8 100644
--- a/gio/gtlsconnection.c
+++ b/gio/gtlsconnection.c
@@ -28,6 +28,8 @@
 #include "gtlsbackend.h"
 #include "gtlscertificate.h"
 #include "gtlsclientconnection.h"
+#include "gtlsdatabase.h"
+#include "gtlsinteraction.h"
 #include "glibintl.h"
 
 /**
@@ -77,6 +79,8 @@ enum {
   PROP_REQUIRE_CLOSE_NOTIFY,
   PROP_REHANDSHAKE_MODE,
   PROP_USE_SYSTEM_CERTDB,
+  PROP_DATABASE,
+  PROP_INTERACTION,
   PROP_CERTIFICATE,
   PROP_PEER_CERTIFICATE,
   PROP_PEER_CERTIFICATE_ERRORS
@@ -112,7 +116,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass)
    * verify peer certificates. See
    * g_tls_connection_set_use_system_certdb().
    *
-   * Since: 2.28
+   * Deprecated: 2.30: Use GTlsConnection:database instead
    */
   g_object_class_install_property (gobject_class, PROP_USE_SYSTEM_CERTDB,
 				   g_param_spec_boolean ("use-system-certdb",
@@ -123,6 +127,38 @@ g_tls_connection_class_init (GTlsConnectionClass *klass)
 							 G_PARAM_CONSTRUCT |
 							 G_PARAM_STATIC_STRINGS));
   /**
+   * GTlsConnection:database:
+   *
+   * The certificate database to use when verifying this TLS connection.
+   * If no cerificate database is set, then the default database will be
+   * used. See g_tls_backend_get_default_database().
+   *
+   * Since: 2.30
+   */
+  g_object_class_install_property (gobject_class, PROP_DATABASE,
+				   g_param_spec_object ("database",
+							 P_("Database"),
+							 P_("Certificate database to use for looking up or verifying certificates"),
+							 G_TYPE_TLS_DATABASE,
+							 G_PARAM_READWRITE |
+							 G_PARAM_STATIC_STRINGS));
+  /**
+   * GTlsConnection:interaction:
+   *
+   * A #GTlsInteraction object to be used when the connection or certificate
+   * database need to interact with the user. This will be used to prompt the
+   * user for passwords where necessary.
+   *
+   * Since: 2.30
+   */
+  g_object_class_install_property (gobject_class, PROP_INTERACTION,
+                                   g_param_spec_object ("interaction",
+                                                        P_("Interaction"),
+                                                        P_("Optional object for user interaction"),
+                                                        G_TYPE_TLS_INTERACTION,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_STRINGS));
+  /**
    * GTlsConnection:require-close-notify:
    *
    * Whether or not proper TLS close notification is required.
@@ -306,7 +342,7 @@ g_tls_connection_set_property (GObject      *object,
  * client-side connections, unless that bit is not set in
  * #GTlsClientConnection:validation-flags).
  *
- * Since: 2.28
+ * Deprecated: 2.30: Use g_tls_connection_set_database() instead
  */
 void
 g_tls_connection_set_use_system_certdb (GTlsConnection *conn,
@@ -328,7 +364,7 @@ g_tls_connection_set_use_system_certdb (GTlsConnection *conn,
  *
  * Return value: whether @conn uses the system certificate database
  *
- * Since: 2.28
+ * Deprecated: 2.30: Use g_tls_connection_get_database() instead
  */
 gboolean
 g_tls_connection_get_use_system_certdb (GTlsConnection *conn)
@@ -344,6 +380,60 @@ g_tls_connection_get_use_system_certdb (GTlsConnection *conn)
 }
 
 /**
+ * g_tls_connection_set_database:
+ * @conn: a #GTlsConnection
+ * @database: a #GTlsDatabase
+ *
+ * Sets the certificate database that is used to verify peer certificates.
+ * This is set to the default database by default. See
+ * g_tls_backend_get_default_database(). If set to %NULL, then
+ * peer certificate validation will always set the
+ * %G_TLS_CERTIFICATE_UNKNOWN_CA error (meaning
+ * #GTlsConnection::accept-certificate will always be emitted on
+ * client-side connections, unless that bit is not set in
+ * #GTlsClientConnection:validation-flags).
+ *
+ * Since: 2.30
+ */
+void
+g_tls_connection_set_database (GTlsConnection *conn,
+                               GTlsDatabase   *database)
+{
+  g_return_if_fail (G_IS_TLS_CONNECTION (conn));
+  g_return_if_fail (!database || G_IS_TLS_DATABASE (database));
+
+  g_object_set (G_OBJECT (conn),
+		"database", database,
+		NULL);
+}
+
+/**
+ * g_tls_connection_get_database:
+ * @conn: a #GTlsConnection
+ *
+ * Gets the certificate database that @conn uses to verify
+ * peer certificates. See g_tls_connection_set_database().
+ *
+ * Return value: the certificate database that @conn uses or %NULL
+ *
+ * Since: 2.30
+ */
+GTlsDatabase*
+g_tls_connection_get_database (GTlsConnection *conn)
+{
+  GTlsDatabase *database = NULL;
+
+  g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), NULL);
+
+  g_object_get (G_OBJECT (conn),
+		"database", &database,
+		NULL);
+  if (database)
+    g_object_unref (database);
+  return database;
+}
+
+/**
  * g_tls_connection_set_certificate:
  * @conn: a #GTlsConnection
  * @certificate: the certificate to use for @conn
@@ -405,6 +495,56 @@ g_tls_connection_get_certificate (GTlsConnection *conn)
 }
 
 /**
+ * g_tls_connection_set_interaction:
+ * @conn: a connection
+ * @interaction: (allow-none): an interaction object, or %NULL
+ *
+ * Set the object that will be used to interact with the user. It will be used
+ * for things like prompting the user for passwords.
+ *
+ * The @interaction argument will normally be a derived subclass of
+ * #GTlsInteraction. %NULL can also be provided if no user interaction
+ * should occur for this connection.
+ *
+ * Since: 2.30
+ */
+void
+g_tls_connection_set_interaction (GTlsConnection       *conn,
+                                  GTlsInteraction      *interaction)
+{
+  g_return_if_fail (G_IS_TLS_CONNECTION (conn));
+  g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction));
+
+  g_object_set (G_OBJECT (conn), "interaction", interaction, NULL);
+}
+
+/**
+ * g_tls_connection_get_interaction:
+ * @conn: a connection
+ *
+ * Get the object that will be used to interact with the user. It will be used
+ * for things like prompting the user for passwords. If %NULL is returned, then
+ * no user interaction will occur for this connection.
+ *
+ * Returns: (transfer none): The interaction object.
+ *
+ * Since: 2.30
+ */
+GTlsInteraction *
+g_tls_connection_get_interaction (GTlsConnection       *conn)
+{
+  GTlsInteraction *interaction = NULL;
+
+  g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), NULL);
+
+  g_object_get (G_OBJECT (conn), "interaction", &interaction, NULL);
+  if (interaction)
+    g_object_unref (interaction);
+
+  return interaction;
+}
+
+/**
  * g_tls_connection_get_peer_certificate:
  * @conn: a #GTlsConnection
  *
diff --git a/gio/gtlsconnection.h b/gio/gtlsconnection.h
index 7786c43..79a8f85 100644
--- a/gio/gtlsconnection.h
+++ b/gio/gtlsconnection.h
@@ -83,14 +83,24 @@ struct _GTlsConnectionClass
 
 GType                 g_tls_connection_get_type                    (void) G_GNUC_CONST;
 
+#ifndef G_DISABLE_DEPRECATED
 void                  g_tls_connection_set_use_system_certdb       (GTlsConnection       *conn,
 								    gboolean              use_system_certdb);
 gboolean              g_tls_connection_get_use_system_certdb       (GTlsConnection       *conn);
+#endif /* G_DISABLE_DEPRECATED */
+
+void                  g_tls_connection_set_database                (GTlsConnection       *conn,
+								    GTlsDatabase         *database);
+GTlsDatabase *        g_tls_connection_get_database                (GTlsConnection       *conn);
 
 void                  g_tls_connection_set_certificate             (GTlsConnection       *conn,
-								    GTlsCertificate      *certificate);
+                                                                    GTlsCertificate      *certificate);
 GTlsCertificate      *g_tls_connection_get_certificate             (GTlsConnection       *conn);
 
+void                  g_tls_connection_set_interaction             (GTlsConnection       *conn,
+                                                                    GTlsInteraction      *interaction);
+GTlsInteraction *     g_tls_connection_get_interaction             (GTlsConnection       *conn);
+
 GTlsCertificate      *g_tls_connection_get_peer_certificate        (GTlsConnection       *conn);
 GTlsCertificateFlags  g_tls_connection_get_peer_certificate_errors (GTlsConnection       *conn);
 
diff --git a/gio/gtlsdatabase.c b/gio/gtlsdatabase.c
new file mode 100644
index 0000000..ce14eb8
--- /dev/null
+++ b/gio/gtlsdatabase.c
@@ -0,0 +1,974 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2010 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "gtlsdatabase.h"
+
+#include "gasyncresult.h"
+#include "gcancellable.h"
+#include "glibintl.h"
+#include "gsimpleasyncresult.h"
+#include "gsocketconnectable.h"
+#include "gtlscertificate.h"
+#include "gtlsinteraction.h"
+
+/**
+ * SECTION:gtlsdatabase
+ * @short_description: TLS database type
+ * @include: gio/gio.h
+ *
+ * #GTlsDatabase is used to lookup certificates and other information
+ * from a certificate or key store. It is an abstract base class which
+ * TLS library specific subtypes override.
+ *
+ * Most common client applications will not directly interact with
+ * #GTlsDatabase. It is used internally by #GTlsConnection.
+ *
+ * Since: 2.30
+ */
+
+/**
+ * GTlsDatabase:
+ *
+ * Abstract base class for the backend-specific database types.
+ *
+ * Since: 2.30
+ */
+
+G_DEFINE_ABSTRACT_TYPE (GTlsDatabase, g_tls_database, G_TYPE_OBJECT);
+
+enum {
+  UNLOCK_REQUIRED,
+
+  LAST_SIGNAL
+};
+
+/**
+ * G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER:
+ *
+ * The purpose used to verify the server certificate in a TLS connection. This
+ * is the most common purpose in use. Used by TLS clients.
+ */
+
+/**
+ * G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT:
+ *
+ * The purpose used to verify the client certificate in a TLS connection.
+ * Used by TLS servers.
+ */
+
+static void
+g_tls_database_init (GTlsDatabase *cert)
+{
+
+}
+
+typedef struct _AsyncVerifyChain {
+  GTlsCertificate *chain;
+  gchar *purpose;
+  GSocketConnectable *identity;
+  GTlsInteraction *interaction;
+  GTlsDatabaseVerifyFlags flags;
+  GTlsCertificateFlags verify_result;
+} AsyncVerifyChain;
+
+static void
+async_verify_chain_free (gpointer data)
+{
+  AsyncVerifyChain *args = data;
+  g_object_unref (args->chain);
+  g_free (args->purpose);
+  if (args->identity)
+    g_object_unref (args->identity);
+  if (args->interaction)
+    g_object_unref (args->interaction);
+  g_slice_free (AsyncVerifyChain, args);
+}
+
+static void
+async_verify_chain_thread (GSimpleAsyncResult *res,
+                           GObject            *object,
+                           GCancellable       *cancellable)
+{
+  AsyncVerifyChain *args = g_simple_async_result_get_op_res_gpointer (res);
+  GError *error = NULL;
+
+  args->verify_result = g_tls_database_verify_chain (G_TLS_DATABASE (object),
+                                                     args->chain,
+                                                     args->purpose,
+                                                     args->identity,
+                                                     args->interaction,
+                                                     args->flags,
+                                                     cancellable,
+                                                     &error);
+
+  if (error)
+      g_simple_async_result_take_error (res, error);
+}
+
+static void
+g_tls_database_real_verify_chain_async (GTlsDatabase           *self,
+                                        GTlsCertificate        *chain,
+                                        const gchar            *purpose,
+                                        GSocketConnectable     *identity,
+                                        GTlsInteraction        *interaction,
+                                        GTlsDatabaseVerifyFlags flags,
+                                        GCancellable           *cancellable,
+                                        GAsyncReadyCallback     callback,
+                                        gpointer                user_data)
+{
+  GSimpleAsyncResult *res;
+  AsyncVerifyChain *args;
+
+  args = g_slice_new0 (AsyncVerifyChain);
+  args->chain = g_object_ref (chain);
+  args->purpose = g_strdup (purpose);
+  args->identity = identity ? g_object_ref (identity) : NULL;
+  args->interaction = interaction ? g_object_ref (interaction) : NULL;
+  args->flags = flags;
+
+  res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+                                   g_tls_database_real_verify_chain_async);
+  g_simple_async_result_set_op_res_gpointer (res, args, async_verify_chain_free);
+  g_simple_async_result_run_in_thread (res, async_verify_chain_thread,
+                                       G_PRIORITY_DEFAULT, cancellable);
+  g_object_unref (res);
+}
+
+static GTlsCertificateFlags
+g_tls_database_real_verify_chain_finish (GTlsDatabase          *self,
+                                         GAsyncResult          *result,
+                                         GError               **error)
+{
+  AsyncVerifyChain *args;
+
+  g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+                        g_tls_database_real_verify_chain_async), FALSE);
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+    return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+  args = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+  return args->verify_result;
+}
+
+typedef struct {
+  gchar *handle;
+  GTlsInteraction *interaction;
+  GTlsDatabaseLookupFlags flags;
+  GTlsCertificate *result;
+} AsyncLookupCertificateForHandle;
+
+static void
+async_lookup_certificate_for_handle_free (gpointer data)
+{
+  AsyncLookupCertificateForHandle *args = data;
+
+  g_free (args->handle);
+  if (args->interaction)
+    g_object_unref (args->interaction);
+  if (args->result)
+    g_object_unref (args->result);
+  g_slice_free (AsyncLookupCertificateForHandle, args);
+}
+
+static void
+async_lookup_certificate_for_handle_thread (GSimpleAsyncResult *res,
+                                            GObject            *object,
+                                            GCancellable       *cancellable)
+{
+  AsyncLookupCertificateForHandle *args = g_simple_async_result_get_op_res_gpointer (res);
+  GError *error = NULL;
+
+  args->result = g_tls_database_lookup_certificate_for_handle (G_TLS_DATABASE (object),
+                                                               args->handle,
+                                                               args->interaction,
+                                                               args->flags,
+                                                               cancellable,
+                                                               &error);
+
+  if (error)
+      g_simple_async_result_take_error (res, error);
+}
+
+static void
+g_tls_database_real_lookup_certificate_for_handle_async (GTlsDatabase           *self,
+                                                         const gchar            *handle,
+                                                         GTlsInteraction        *interaction,
+                                                         GTlsDatabaseLookupFlags flags,
+                                                         GCancellable           *cancellable,
+                                                         GAsyncReadyCallback     callback,
+                                                         gpointer                user_data)
+{
+  GSimpleAsyncResult *res;
+  AsyncLookupCertificateForHandle *args;
+
+  g_return_if_fail (callback);
+
+  args = g_slice_new0 (AsyncLookupCertificateForHandle);
+  args->handle = g_strdup (handle);
+  args->interaction = interaction ? g_object_ref (interaction) : NULL;
+
+  res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+                                   g_tls_database_real_lookup_certificate_for_handle_async);
+  g_simple_async_result_set_op_res_gpointer (res, args, async_lookup_certificate_for_handle_free);
+  g_simple_async_result_run_in_thread (res, async_lookup_certificate_for_handle_thread,
+                                       G_PRIORITY_DEFAULT, cancellable);
+  g_object_unref (res);
+}
+
+static GTlsCertificate*
+g_tls_database_real_lookup_certificate_for_handle_finish (GTlsDatabase          *self,
+                                                          GAsyncResult          *result,
+                                                          GError               **error)
+{
+  AsyncLookupCertificateForHandle *args;
+  GTlsCertificate *certificate;
+
+  g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+                        g_tls_database_real_lookup_certificate_for_handle_async), FALSE);
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+    return NULL;
+
+  args = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+  certificate = args->result;
+  args->result = NULL;
+  return certificate;
+}
+
+
+typedef struct {
+  GTlsCertificate *certificate;
+  GTlsInteraction *interaction;
+  GTlsDatabaseLookupFlags flags;
+  GTlsCertificate *issuer;
+} AsyncLookupCertificateIssuer;
+
+static void
+async_lookup_certificate_issuer_free (gpointer data)
+{
+  AsyncLookupCertificateIssuer *args = data;
+
+  g_object_unref (args->certificate);
+  if (args->interaction)
+    g_object_unref (args->interaction);
+  if (args->issuer)
+    g_object_unref (args->issuer);
+  g_slice_free (AsyncLookupCertificateIssuer, args);
+}
+
+static void
+async_lookup_certificate_issuer_thread (GSimpleAsyncResult *res,
+                            GObject            *object,
+                            GCancellable       *cancellable)
+{
+  AsyncLookupCertificateIssuer *args = g_simple_async_result_get_op_res_gpointer (res);
+  GError *error = NULL;
+
+  args->issuer = g_tls_database_lookup_certificate_issuer (G_TLS_DATABASE (object),
+                                                           args->certificate,
+                                                           args->interaction,
+                                                           args->flags,
+                                                           cancellable,
+                                                           &error);
+
+  if (error)
+      g_simple_async_result_take_error (res, error);
+}
+
+static void
+g_tls_database_real_lookup_certificate_issuer_async (GTlsDatabase           *self,
+                                                     GTlsCertificate        *certificate,
+                                                     GTlsInteraction        *interaction,
+                                                     GTlsDatabaseLookupFlags flags,
+                                                     GCancellable           *cancellable,
+                                                     GAsyncReadyCallback     callback,
+                                                     gpointer                user_data)
+{
+  GSimpleAsyncResult *res;
+  AsyncLookupCertificateIssuer *args;
+
+  g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate));
+  g_return_if_fail (callback);
+
+  args = g_slice_new0 (AsyncLookupCertificateIssuer);
+  args->certificate = g_object_ref (certificate);
+  args->flags = flags;
+  args->interaction = interaction ? g_object_ref (interaction) : NULL;
+
+  res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+                                   g_tls_database_real_lookup_certificate_issuer_async);
+  g_simple_async_result_set_op_res_gpointer (res, args, async_lookup_certificate_issuer_free);
+  g_simple_async_result_run_in_thread (res, async_lookup_certificate_issuer_thread,
+                                       G_PRIORITY_DEFAULT, cancellable);
+  g_object_unref (res);
+}
+
+static GTlsCertificate*
+g_tls_database_real_lookup_certificate_issuer_finish (GTlsDatabase          *self,
+                                                      GAsyncResult          *result,
+                                                      GError               **error)
+{
+  AsyncLookupCertificateIssuer *args;
+  GTlsCertificate *issuer;
+
+  g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+                        g_tls_database_real_lookup_certificate_issuer_async), FALSE);
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+    return NULL;
+
+  args = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+  issuer = args->issuer;
+  args->issuer = NULL;
+  return issuer;
+}
+
+typedef struct {
+  GByteArray *issuer;
+  GTlsInteraction *interaction;
+  GTlsDatabaseLookupFlags flags;
+  GList *results;
+} AsyncLookupCertificatesIssuedBy;
+
+static void
+async_lookup_certificates_issued_by_free (gpointer data)
+{
+  AsyncLookupCertificatesIssuedBy *args = data;
+  GList *l;
+
+  g_byte_array_unref (args->issuer);
+  if (args->interaction)
+    g_object_unref (args->interaction);
+  for (l = args->results; l; l = g_list_next (l))
+    g_object_unref (l->data);
+  g_list_free (args->results);
+  g_slice_free (AsyncLookupCertificatesIssuedBy, args);
+}
+
+static void
+async_lookup_certificates_issued_by_thread (GSimpleAsyncResult *res,
+                                            GObject            *object,
+                                            GCancellable       *cancellable)
+{
+  AsyncLookupCertificatesIssuedBy *args = g_simple_async_result_get_op_res_gpointer (res);
+  GError *error = NULL;
+
+  args->results = g_tls_database_lookup_certificates_issued_by (G_TLS_DATABASE (object),
+                                                                args->issuer,
+                                                                args->interaction,
+                                                                args->flags,
+                                                                cancellable,
+                                                                &error);
+
+  if (error)
+      g_simple_async_result_take_error (res, error);
+}
+
+static void
+g_tls_database_real_lookup_certificates_issued_by_async (GTlsDatabase           *self,
+                                                         GByteArray             *issuer,
+                                                         GTlsInteraction        *interaction,
+                                                         GTlsDatabaseLookupFlags flags,
+                                                         GCancellable           *cancellable,
+                                                         GAsyncReadyCallback     callback,
+                                                         gpointer                user_data)
+{
+  GSimpleAsyncResult *res;
+  AsyncLookupCertificatesIssuedBy *args;
+
+  g_return_if_fail (callback);
+
+  args = g_slice_new0 (AsyncLookupCertificatesIssuedBy);
+  args->issuer = g_byte_array_ref (issuer);
+  args->flags = flags;
+  args->interaction = interaction ? g_object_ref (interaction) : NULL;
+
+  res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+                                   g_tls_database_real_lookup_certificates_issued_by_async);
+  g_simple_async_result_set_op_res_gpointer (res, args, async_lookup_certificates_issued_by_free);
+  g_simple_async_result_run_in_thread (res, async_lookup_certificates_issued_by_thread,
+                                       G_PRIORITY_DEFAULT, cancellable);
+  g_object_unref (res);
+}
+
+static GList*
+g_tls_database_real_lookup_certificates_issued_by_finish (GTlsDatabase          *self,
+                                                          GAsyncResult          *result,
+                                                          GError               **error)
+{
+  AsyncLookupCertificatesIssuedBy *args;
+  GList *results;
+
+  g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+                        g_tls_database_real_lookup_certificates_issued_by_async), FALSE);
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+    return NULL;
+
+  args = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+  results = args->results;
+  args->results = NULL;
+  return results;
+}
+
+static void
+g_tls_database_class_init (GTlsDatabaseClass *klass)
+{
+  klass->verify_chain_async = g_tls_database_real_verify_chain_async;
+  klass->verify_chain_finish = g_tls_database_real_verify_chain_finish;
+  klass->lookup_certificate_for_handle_async = g_tls_database_real_lookup_certificate_for_handle_async;
+  klass->lookup_certificate_for_handle_finish = g_tls_database_real_lookup_certificate_for_handle_finish;
+  klass->lookup_certificate_issuer_async = g_tls_database_real_lookup_certificate_issuer_async;
+  klass->lookup_certificate_issuer_finish = g_tls_database_real_lookup_certificate_issuer_finish;
+  klass->lookup_certificates_issued_by_async = g_tls_database_real_lookup_certificates_issued_by_async;
+  klass->lookup_certificates_issued_by_finish = g_tls_database_real_lookup_certificates_issued_by_finish;
+}
+
+/**
+ * g_tls_database_verify_chain:
+ * @self: a #GTlsDatabase
+ * @chain: a #GTlsCertificate chain
+ * @purpose: the purpose that this certificate chain will be used for.
+ * @identity: (allow-none): the expected peer identity
+ * @interaction: (allow-none): used to interact with the user if necessary
+ * @flags: additional verify flags
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a #GError, or %NULL
+ *
+ * Verify's a certificate chain after looking up and adding any missing
+ * certificates to the chain.
+ *
+ * @chain is a chain of #GTlsCertificate objects each pointing to the next
+ * certificate in the chain by its %issuer property. The chain may initially
+ * consist of one or more certificates. After the verification process is
+ * complete, @chain may be modified by adding missing certificates, or removing
+ * extra certificates. If a certificate anchor was found, then it is added to
+ * the @chain.
+ *
+ * @purpose describes the purpose (or usage) for which the certificate
+ * is being used. Typically @purpose will be set to #G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER
+ * which means that the certificate is being used to authenticate a server
+ * (and we are acting as the client).
+ *
+ * The @identity is used to check for pinned certificates (trust exceptions)
+ * in the database. These will override the normal verification process on a
+ * host by host basis.
+ *
+ * Currently there are no @flags, and %G_TLS_DATABASE_VERIFY_NONE should be
+ * used.
+ *
+ * This function can block, use g_tls_database_verify_chain_async() to perform
+ * the verification operation asynchronously.
+ *
+ * Return value: the appropriate #GTlsCertificateFlags which represents the
+ * result of verification.
+ *
+ * Since: 2.30
+ */
+GTlsCertificateFlags
+g_tls_database_verify_chain (GTlsDatabase           *self,
+                             GTlsCertificate        *chain,
+                             const gchar            *purpose,
+                             GSocketConnectable     *identity,
+                             GTlsInteraction        *interaction,
+                             GTlsDatabaseVerifyFlags flags,
+                             GCancellable           *cancellable,
+                             GError                **error)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self),
+                        G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE (chain),
+                        G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (purpose, G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (!interaction || G_IS_TLS_INTERACTION (interaction),
+                        G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (!identity || G_IS_SOCKET_CONNECTABLE (identity),
+                        G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (!error || !*error, G_TLS_CERTIFICATE_GENERIC_ERROR);
+
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->verify_chain,
+                        G_TLS_CERTIFICATE_GENERIC_ERROR);
+
+  return G_TLS_DATABASE_GET_CLASS (self)->verify_chain (self,
+                                                        chain,
+                                                        purpose,
+                                                        identity,
+                                                        interaction,
+                                                        flags,
+                                                        cancellable,
+                                                        error);
+}
+
+/**
+ * g_tls_database_verify_chain_async:
+ * @self: a #GTlsDatabase
+ * @chain: a #GTlsCertificate chain
+ * @purpose: the purpose that this certificate chain will be used for.
+ * @identity: (allow-none): the expected peer identity
+ * @interaction: (allow-none): used to interact with the user if necessary
+ * @flags: additional verify flags
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @callback: callback to call when the operation completes
+ * @user_data: the data to pass to the callback function
+ *
+ * Asynchronously verify's a certificate chain after looking up and adding
+ * any missing certificates to the chain. See g_tls_database_verify_chain()
+ * for more information.
+ *
+ * Since: 2.30
+ */
+void
+g_tls_database_verify_chain_async (GTlsDatabase           *self,
+                                   GTlsCertificate        *chain,
+                                   const gchar            *purpose,
+                                   GSocketConnectable     *identity,
+                                   GTlsInteraction        *interaction,
+                                   GTlsDatabaseVerifyFlags flags,
+                                   GCancellable           *cancellable,
+                                   GAsyncReadyCallback     callback,
+                                   gpointer                user_data)
+{
+  g_return_if_fail (G_IS_TLS_DATABASE (self));
+  g_return_if_fail (G_IS_TLS_CERTIFICATE (chain));
+  g_return_if_fail (purpose);
+  g_return_if_fail (!interaction || G_IS_TLS_INTERACTION (interaction));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (!identity || G_IS_SOCKET_CONNECTABLE (identity));
+  g_return_if_fail (callback);
+
+  g_return_if_fail (G_TLS_DATABASE_GET_CLASS (self)->verify_chain_async);
+  G_TLS_DATABASE_GET_CLASS (self)->verify_chain_async (self,
+                                                       chain,
+                                                       purpose,
+                                                       identity,
+                                                       interaction,
+                                                       flags,
+                                                       cancellable,
+                                                       callback,
+                                                       user_data);
+}
+
+/**
+ * g_tls_database_verify_chain_finish:
+ * @self: a #GTlsDatabase
+ * @result: a #GAsyncResult.
+ * @error: a #GError pointer, or %NULL
+ *
+ * Finish an asynchronous verify chain operation. See
+ * g_tls_database_verify_chain() for more information. *
+ * Return value: the appropriate #GTlsCertificateFlags which represents the
+ * result of verification.
+ *
+ * Since: 2.30
+ */
+GTlsCertificateFlags
+g_tls_database_verify_chain_finish (GTlsDatabase          *self,
+                                    GAsyncResult          *result,
+                                    GError               **error)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (!error || !*error, G_TLS_CERTIFICATE_GENERIC_ERROR);
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->verify_chain_finish,
+                        G_TLS_CERTIFICATE_GENERIC_ERROR);
+  return G_TLS_DATABASE_GET_CLASS (self)->verify_chain_finish (self,
+                                                               result,
+                                                               error);
+}
+
+/**
+ * g_tls_database_create_certificate_handle:
+ * @self: a #GTlsDatabase
+ * @certificate: certificate for which to create a handle.
+ *
+ * Create a handle string for the certificate. The database will only be able
+ * to create a handle for certificates that originate from the database. In
+ * cases where the database cannot create a handle for a certificate, %NULL
+ * will be returned.
+ *
+ * This handle should be stable across various instances of the application,
+ * and between applications. If a certificate is modified in the database,
+ * then it is not guaranteed that this handle will continue to point to it.
+ *
+ * Returns: (allow-none): a newly allocated string containing the handle.
+ * Since: 2.30
+ */
+gchar*
+g_tls_database_create_certificate_handle (GTlsDatabase            *self,
+                                          GTlsCertificate         *certificate)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL);
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE (certificate), NULL);
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->create_certificate_handle, NULL);
+  return G_TLS_DATABASE_GET_CLASS (self)->create_certificate_handle (self,
+                                                                     certificate);
+}
+
+/**
+ * g_tls_database_lookup_certificate_for_handle:
+ * @self: a #GTlsDatabase
+ * @handle: a certificate handle
+ * @interaction: (allow-none): used to interact with the user if necessary
+ * @flags: Flags which affect the lookup.
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a #GError, or %NULL
+ *
+ * Lookup a certificate by its handle.
+ *
+ * The handle should have been created by calling g_tls_database_create_handle()
+ * on a #GTlsDatabase object of the same TLS backend. The handle is designed
+ * to remain valid across instantiations of the database.
+ *
+ * If the handle is no longer valid, or does not point to a certificate in
+ * this database, then %NULL will be returned.
+ *
+ * This function can block, use g_tls_database_lookup_certificate_for_handle_async() to perform
+ * the lookup operation asynchronously.
+ *
+ * Return value: (transfer full) (allow-none): a newly allocated
+ * #GTlsCertificate, or %NULL. Use g_object_unref() to release the certificate.
+ *
+ * Since: 2.30
+ */
+GTlsCertificate*
+g_tls_database_lookup_certificate_for_handle (GTlsDatabase            *self,
+                                              const gchar             *handle,
+                                              GTlsInteraction         *interaction,
+                                              GTlsDatabaseLookupFlags  flags,
+                                              GCancellable            *cancellable,
+                                              GError                 **error)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL);
+  g_return_val_if_fail (handle, NULL);
+  g_return_val_if_fail (!interaction || G_IS_TLS_INTERACTION (interaction), NULL);
+  g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
+  g_return_val_if_fail (!error || !*error, NULL);
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_for_handle, NULL);
+  return G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_for_handle (self,
+                                                                         handle,
+                                                                         interaction,
+                                                                         flags,
+                                                                         cancellable,
+                                                                         error);
+}
+
+
+/**
+ * g_tls_database_lookup_certificate_for_handle_async:
+ * @self: a #GTlsDatabase
+ * @handle: a certificate handle
+ * @interaction: (allow-none): used to interact with the user if necessary
+ * @flags: Flags which affect the lookup.
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @callback: callback to call when the operation completes
+ * @user_data: the data to pass to the callback function
+ *
+ * Asynchronously lookup a certificate by its handle in the database. See
+ * g_tls_database_lookup_handle() for more information.
+ *
+ * Since: 2.30
+ */
+void
+g_tls_database_lookup_certificate_for_handle_async (GTlsDatabase            *self,
+                                                    const gchar             *handle,
+                                                    GTlsInteraction         *interaction,
+                                                    GTlsDatabaseLookupFlags  flags,
+                                                    GCancellable            *cancellable,
+                                                    GAsyncReadyCallback      callback,
+                                                    gpointer                 user_data)
+{
+  g_return_if_fail (G_IS_TLS_DATABASE (self));
+  g_return_if_fail (handle);
+  g_return_if_fail (!interaction || G_IS_TLS_INTERACTION (interaction));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_for_handle_async);
+  return G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_for_handle_async (self,
+                                                                               handle,
+                                                                               interaction,
+                                                                               flags,
+                                                                               cancellable,
+                                                                               callback,
+                                                                               user_data);
+}
+
+/**
+ * g_tls_database_lookup_certificate_for_handle_finish:
+ * @self: a #GTlsDatabase
+ * @result: a #GAsyncResult.
+ * @error: a #GError pointer, or %NULL
+ *
+ * Finish an asynchronous lookup of a certificate by its handle. See
+ * g_tls_database_lookup_handle() for more information.
+ *
+ * If the handle is no longer valid, or does not point to a certificate in
+ * this database, then %NULL will be returned.
+ *
+ * Return value: (transfer full): a newly allocated #GTlsCertificate object.
+ * Use g_object_unref() to release the certificate.
+ *
+ * Since: 2.30
+ */
+GTlsCertificate*
+g_tls_database_lookup_certificate_for_handle_finish (GTlsDatabase            *self,
+                                                     GAsyncResult            *result,
+                                                     GError                 **error)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+  g_return_val_if_fail (!error || !*error, NULL);
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_for_handle_finish, NULL);
+  return G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_for_handle_finish (self,
+                                                                                result,
+                                                                                error);
+}
+
+/**
+ * g_tls_database_lookup_certificate_issuer:
+ * @self: a #GTlsDatabase
+ * @certificate: a #GTlsCertificate
+ * @interaction: (allow-none): used to interact with the user if necessary
+ * @flags: flags which affect the lookup operation
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a #GError, or %NULL
+ *
+ * Lookup the issuer of @certificate in the database.
+ *
+ * The %issuer property
+ * of @certificate is not modified, and the two certificates are not hooked
+ * into a chain.
+ *
+ * This function can block, use g_tls_database_lookup_certificate_issuer_async() to perform
+ * the lookup operation asynchronously.
+ *
+ * Return value: (transfer full): a newly allocated issuer #GTlsCertificate,
+ * or %NULL. Use g_object_unref() to release the certificate.
+ *
+ * Since: 2.30
+ */
+GTlsCertificate*
+g_tls_database_lookup_certificate_issuer (GTlsDatabase           *self,
+                                          GTlsCertificate        *certificate,
+                                          GTlsInteraction        *interaction,
+                                          GTlsDatabaseLookupFlags flags,
+                                          GCancellable           *cancellable,
+                                          GError                **error)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL);
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE (certificate), NULL);
+  g_return_val_if_fail (!interaction || G_IS_TLS_INTERACTION (interaction), NULL);
+  g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
+  g_return_val_if_fail (!error || !*error, NULL);
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer, NULL);
+  return G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer (self,
+                                                                     certificate,
+                                                                     interaction,
+                                                                     flags,
+                                                                     cancellable,
+                                                                     error);
+}
+
+/**
+ * g_tls_database_lookup_certificate_issuer_async:
+ * @self: a #GTlsDatabase
+ * @certificate: a #GTlsCertificate
+ * @interaction: (allow-none): used to interact with the user if necessary
+ * @flags: flags which affect the lookup operation
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @callback: callback to call when the operation completes
+ * @user_data: the data to pass to the callback function
+ *
+ * Asynchronously lookup the issuer of @certificate in the database. See
+ * g_tls_database_lookup_certificate_issuer() for more information.
+ *
+ * Since: 2.30
+ */
+void
+g_tls_database_lookup_certificate_issuer_async (GTlsDatabase           *self,
+                                                GTlsCertificate        *certificate,
+                                                GTlsInteraction        *interaction,
+                                                GTlsDatabaseLookupFlags flags,
+                                                GCancellable           *cancellable,
+                                                GAsyncReadyCallback     callback,
+                                                gpointer                user_data)
+{
+  g_return_if_fail (G_IS_TLS_DATABASE (self));
+  g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate));
+  g_return_if_fail (!interaction || G_IS_TLS_INTERACTION (interaction));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (callback);
+  g_return_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer_async);
+  G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer_async (self,
+                                                        certificate,
+                                                        interaction,
+                                                        flags,
+                                                        cancellable,
+                                                        callback,
+                                                        user_data);
+}
+
+/**
+ * g_tls_database_lookup_certificate_issuer_finish:
+ * @self: a #GTlsDatabase
+ * @result: a #GAsyncResult.
+ * @error: a #GError pointer, or %NULL
+ *
+ * Finish an asynchronous lookup issuer operation. See
+ * g_tls_database_lookup_certificate_issuer() for more information.
+ *
+ * Return value: (transfer full): a newly allocated issuer #GTlsCertificate,
+ * or %NULL. Use g_object_unref() to release the certificate.
+ *
+ * Since: 2.30
+ */
+GTlsCertificate*
+g_tls_database_lookup_certificate_issuer_finish (GTlsDatabase          *self,
+                                                 GAsyncResult          *result,
+                                                 GError               **error)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+  g_return_val_if_fail (!error || !*error, NULL);
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer_finish, NULL);
+  return G_TLS_DATABASE_GET_CLASS (self)->lookup_certificate_issuer_finish (self,
+                                                                result,
+                                                                error);
+}
+
+/**
+ * g_tls_database_lookup_certificates_issued_by:
+ * @self: a #GTlsDatabase
+ * @issuer_raw_dn: a #GByteArray which holds the DER encoded issuer DN.
+ * @interaction: (allow-none): used to interact with the user if necessary
+ * @flags: Flags which affect the lookup operation.
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a #GError, or %NULL
+ *
+ * Lookup certificates issued by this issuer in the database.
+ *
+ * This function can block, use g_tls_database_lookup_certificates_issued_by_async() to perform
+ * the lookup operation asynchronously.
+ *
+ * Return value: (transfer full): a newly allocated list of #GTlsCertificate objects.
+ * Use g_object_unref() on each certificate, and g_list_free() on the release the list.
+ *
+ * Since: 2.30
+ */
+GList*
+g_tls_database_lookup_certificates_issued_by (GTlsDatabase           *self,
+                                              GByteArray             *issuer_raw_dn,
+                                              GTlsInteraction        *interaction,
+                                              GTlsDatabaseLookupFlags flags,
+                                              GCancellable           *cancellable,
+                                              GError                **error)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL);
+  g_return_val_if_fail (issuer_raw_dn, NULL);
+  g_return_val_if_fail (!interaction || G_IS_TLS_INTERACTION (interaction), NULL);
+  g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
+  g_return_val_if_fail (!error || !*error, NULL);
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificates_issued_by, NULL);
+  return G_TLS_DATABASE_GET_CLASS (self)->lookup_certificates_issued_by (self,
+                                                                         issuer_raw_dn,
+                                                                         interaction,
+                                                                         flags,
+                                                                         cancellable,
+                                                                         error);
+}
+
+/**
+ * g_tls_database_lookup_certificates_issued_by_async:
+ * @self: a #GTlsDatabase
+ * @issuer_raw_dn: a #GByteArray which holds the DER encoded issuer DN.
+ * @interaction: (allow-none): used to interact with the user if necessary
+ * @flags: Flags which affect the lookup operation.
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @callback: callback to call when the operation completes
+ * @user_data: the data to pass to the callback function
+ *
+ * Asynchronously lookup certificates issued by this issuer in the database. See
+ * g_tls_database_lookup_certificates_issued_by() for more information.
+ *
+ * The database may choose to hold a reference to the issuer byte array for the duration
+ * of of this asynchronous operation. The byte array should not be modified during
+ * this time.
+ *
+ * Since: 2.30
+ */
+void
+g_tls_database_lookup_certificates_issued_by_async (GTlsDatabase           *self,
+                                                    GByteArray             *issuer_raw_dn,
+                                                    GTlsInteraction        *interaction,
+                                                    GTlsDatabaseLookupFlags flags,
+                                                    GCancellable           *cancellable,
+                                                    GAsyncReadyCallback     callback,
+                                                    gpointer                user_data)
+{
+  g_return_if_fail (G_IS_TLS_DATABASE (self));
+  g_return_if_fail (issuer_raw_dn);
+  g_return_if_fail (!interaction || G_IS_TLS_INTERACTION (interaction));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (callback);
+  g_return_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificates_issued_by_async);
+  G_TLS_DATABASE_GET_CLASS (self)->lookup_certificates_issued_by_async (self,
+                                                                        issuer_raw_dn,
+                                                                        interaction,
+                                                                        flags,
+                                                                        cancellable,
+                                                                        callback,
+                                                                        user_data);
+}
+
+/**
+ * g_tls_database_lookup_certificates_issued_by_finish:
+ * @self: a #GTlsDatabase
+ * @result: a #GAsyncResult.
+ * @error: a #GError pointer, or %NULL
+ *
+ * Finish an asynchronous lookup of certificates. See
+ * g_tls_database_lookup_certificates_issued_by() for more information.
+ *
+ * Return value: (transfer full): a newly allocated list of #GTlsCertificate objects.
+ * Use g_object_unref() on each certificate, and g_list_free() on the release the list.
+ *
+ * Since: 2.30
+ */
+GList*
+g_tls_database_lookup_certificates_issued_by_finish (GTlsDatabase          *self,
+                                                     GAsyncResult          *result,
+                                                     GError               **error)
+{
+  g_return_val_if_fail (G_IS_TLS_DATABASE (self), NULL);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
+  g_return_val_if_fail (!error || !*error, NULL);
+  g_return_val_if_fail (G_TLS_DATABASE_GET_CLASS (self)->lookup_certificates_issued_by_finish, NULL);
+  return G_TLS_DATABASE_GET_CLASS (self)->lookup_certificates_issued_by_finish (self,
+                                                                                result,
+                                                                                error);
+}
diff --git a/gio/gtlsdatabase.h b/gio/gtlsdatabase.h
new file mode 100644
index 0000000..9f93cc9
--- /dev/null
+++ b/gio/gtlsdatabase.h
@@ -0,0 +1,235 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2010 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_TLS_DATABASE_H__
+#define __G_TLS_DATABASE_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER "1.3.6.1.5.5.7.3.1"
+#define G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT "1.3.6.1.5.5.7.3.2"
+
+#define G_TYPE_TLS_DATABASE            (g_tls_database_get_type ())
+#define G_TLS_DATABASE(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_DATABASE, GTlsDatabase))
+#define G_TLS_DATABASE_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_DATABASE, GTlsDatabaseClass))
+#define G_IS_TLS_DATABASE(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_DATABASE))
+#define G_IS_TLS_DATABASE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_DATABASE))
+#define G_TLS_DATABASE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_DATABASE, GTlsDatabaseClass))
+
+typedef struct _GTlsDatabaseClass   GTlsDatabaseClass;
+typedef struct _GTlsDatabasePrivate GTlsDatabasePrivate;
+
+struct _GTlsDatabase
+{
+  GObject parent_instance;
+
+  GTlsDatabasePrivate *priv;
+};
+
+struct _GTlsDatabaseClass
+{
+  GObjectClass parent_class;
+
+  /* virtual methods */
+
+  GTlsCertificateFlags  (*verify_chain)                         (GTlsDatabase            *self,
+                                                                 GTlsCertificate         *chain,
+                                                                 const gchar             *purpose,
+                                                                 GSocketConnectable      *identity,
+                                                                 GTlsInteraction         *interaction,
+                                                                 GTlsDatabaseVerifyFlags  flags,
+                                                                 GCancellable            *cancellable,
+                                                                 GError                 **error);
+
+  void                  (*verify_chain_async)                   (GTlsDatabase            *self,
+                                                                 GTlsCertificate         *chain,
+                                                                 const gchar             *purpose,
+                                                                 GSocketConnectable      *identity,
+                                                                 GTlsInteraction         *interaction,
+                                                                 GTlsDatabaseVerifyFlags  flags,
+                                                                 GCancellable            *cancellable,
+                                                                 GAsyncReadyCallback      callback,
+                                                                 gpointer                 user_data);
+
+  GTlsCertificateFlags  (*verify_chain_finish)                  (GTlsDatabase            *self,
+                                                                 GAsyncResult            *result,
+                                                                 GError                 **error);
+
+  gchar*                (*create_certificate_handle)            (GTlsDatabase            *self,
+                                                                 GTlsCertificate         *certificate);
+
+  GTlsCertificate*      (*lookup_certificate_for_handle)        (GTlsDatabase            *self,
+                                                                 const gchar             *handle,
+                                                                 GTlsInteraction         *interaction,
+                                                                 GTlsDatabaseLookupFlags  flags,
+                                                                 GCancellable            *cancellable,
+                                                                 GError                 **error);
+
+  void                  (*lookup_certificate_for_handle_async)  (GTlsDatabase            *self,
+                                                                 const gchar             *handle,
+                                                                 GTlsInteraction         *interaction,
+                                                                 GTlsDatabaseLookupFlags  flags,
+                                                                 GCancellable            *cancellable,
+                                                                 GAsyncReadyCallback      callback,
+                                                                 gpointer                 user_data);
+
+  GTlsCertificate*      (*lookup_certificate_for_handle_finish) (GTlsDatabase            *self,
+                                                                 GAsyncResult            *result,
+                                                                 GError                 **error);
+
+  GTlsCertificate*      (*lookup_certificate_issuer)            (GTlsDatabase            *self,
+                                                                 GTlsCertificate         *certificate,
+                                                                 GTlsInteraction         *interaction,
+                                                                 GTlsDatabaseLookupFlags  flags,
+                                                                 GCancellable            *cancellable,
+                                                                 GError                 **error);
+
+  void                  (*lookup_certificate_issuer_async)      (GTlsDatabase            *self,
+                                                                 GTlsCertificate         *certificate,
+                                                                 GTlsInteraction         *interaction,
+                                                                 GTlsDatabaseLookupFlags  flags,
+                                                                 GCancellable            *cancellable,
+                                                                 GAsyncReadyCallback      callback,
+                                                                 gpointer                 user_data);
+
+  GTlsCertificate*      (*lookup_certificate_issuer_finish)     (GTlsDatabase            *self,
+                                                                 GAsyncResult            *result,
+                                                                 GError                 **error);
+
+  GList*                (*lookup_certificates_issued_by)        (GTlsDatabase            *self,
+                                                                 GByteArray              *issuer_raw_dn,
+                                                                 GTlsInteraction         *interaction,
+                                                                 GTlsDatabaseLookupFlags  flags,
+                                                                 GCancellable            *cancellable,
+                                                                 GError                 **error);
+
+  void                  (*lookup_certificates_issued_by_async)  (GTlsDatabase            *self,
+                                                                 GByteArray              *issuer_raw_dn,
+                                                                 GTlsInteraction         *interaction,
+                                                                 GTlsDatabaseLookupFlags  flags,
+                                                                 GCancellable            *cancellable,
+                                                                 GAsyncReadyCallback      callback,
+                                                                 gpointer                 user_data);
+
+  GList*                (*lookup_certificates_issued_by_finish) (GTlsDatabase            *self,
+                                                                 GAsyncResult            *result,
+                                                                 GError                 **error);
+
+  /*< private >*/
+  /* Padding for future expansion */
+  gpointer padding[16];
+};
+
+GType                g_tls_database_get_type                              (void) G_GNUC_CONST;
+
+GTlsCertificateFlags g_tls_database_verify_chain                          (GTlsDatabase            *self,
+                                                                           GTlsCertificate         *chain,
+                                                                           const gchar             *purpose,
+                                                                           GSocketConnectable      *identity,
+                                                                           GTlsInteraction         *interaction,
+                                                                           GTlsDatabaseVerifyFlags  flags,
+                                                                           GCancellable            *cancellable,
+                                                                           GError                 **error);
+
+void                 g_tls_database_verify_chain_async                    (GTlsDatabase            *self,
+                                                                           GTlsCertificate         *chain,
+                                                                           const gchar             *purpose,
+                                                                           GSocketConnectable      *identity,
+                                                                           GTlsInteraction         *interaction,
+                                                                           GTlsDatabaseVerifyFlags  flags,
+                                                                           GCancellable            *cancellable,
+                                                                           GAsyncReadyCallback      callback,
+                                                                           gpointer                 user_data);
+
+GTlsCertificateFlags g_tls_database_verify_chain_finish                   (GTlsDatabase            *self,
+                                                                           GAsyncResult            *result,
+                                                                           GError                 **error);
+
+gchar*               g_tls_database_create_certificate_handle             (GTlsDatabase            *self,
+                                                                           GTlsCertificate         *certificate);
+
+GTlsCertificate*     g_tls_database_lookup_certificate_for_handle         (GTlsDatabase            *self,
+                                                                           const gchar             *handle,
+                                                                           GTlsInteraction         *interaction,
+                                                                           GTlsDatabaseLookupFlags  flags,
+                                                                           GCancellable            *cancellable,
+                                                                           GError                 **error);
+
+void                 g_tls_database_lookup_certificate_for_handle_async   (GTlsDatabase            *self,
+                                                                           const gchar             *handle,
+                                                                           GTlsInteraction         *interaction,
+                                                                           GTlsDatabaseLookupFlags  flags,
+                                                                           GCancellable            *cancellable,
+                                                                           GAsyncReadyCallback      callback,
+                                                                           gpointer                 user_data);
+
+GTlsCertificate*     g_tls_database_lookup_certificate_for_handle_finish  (GTlsDatabase            *self,
+                                                                           GAsyncResult            *result,
+                                                                           GError                 **error);
+
+GTlsCertificate*     g_tls_database_lookup_certificate_issuer             (GTlsDatabase            *self,
+                                                                           GTlsCertificate         *certificate,
+                                                                           GTlsInteraction         *interaction,
+                                                                           GTlsDatabaseLookupFlags  flags,
+                                                                           GCancellable            *cancellable,
+                                                                           GError                 **error);
+
+void                 g_tls_database_lookup_certificate_issuer_async       (GTlsDatabase            *self,
+                                                                           GTlsCertificate         *certificate,
+                                                                           GTlsInteraction         *interaction,
+                                                                           GTlsDatabaseLookupFlags  flags,
+                                                                           GCancellable            *cancellable,
+                                                                           GAsyncReadyCallback      callback,
+                                                                           gpointer                 user_data);
+
+GTlsCertificate*     g_tls_database_lookup_certificate_issuer_finish      (GTlsDatabase            *self,
+                                                                           GAsyncResult            *result,
+                                                                           GError                 **error);
+
+GList*               g_tls_database_lookup_certificates_issued_by         (GTlsDatabase            *self,
+                                                                           GByteArray              *issuer_raw_dn,
+                                                                           GTlsInteraction         *interaction,
+                                                                           GTlsDatabaseLookupFlags  flags,
+                                                                           GCancellable            *cancellable,
+                                                                           GError                 **error);
+
+void                 g_tls_database_lookup_certificates_issued_by_async    (GTlsDatabase            *self,
+                                                                            GByteArray              *issuer_raw_dn,
+                                                                            GTlsInteraction         *interaction,
+                                                                            GTlsDatabaseLookupFlags  flags,
+                                                                            GCancellable            *cancellable,
+                                                                            GAsyncReadyCallback      callback,
+                                                                            gpointer                 user_data);
+
+GList*               g_tls_database_lookup_certificates_issued_by_finish   (GTlsDatabase            *self,
+                                                                            GAsyncResult            *result,
+                                                                            GError                 **error);
+
+G_END_DECLS
+
+#endif /* __G_TLS_DATABASE_H__ */
diff --git a/gio/gtlsfiledatabase.c b/gio/gtlsfiledatabase.c
new file mode 100644
index 0000000..0c59722
--- /dev/null
+++ b/gio/gtlsfiledatabase.c
@@ -0,0 +1,104 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2010 Collabora, Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "gtlsfiledatabase.h"
+
+#include "ginitable.h"
+#include "gtlsbackend.h"
+#include "gtlsdatabase.h"
+#include "glibintl.h"
+
+/**
+ * SECTION:gtlsfiledatabase
+ * @short_description: TLS file based database type
+ * @include: gio/gio.h
+ *
+ * #GTlsFileDatabase is implemented by #GTlsDatabase objects which load
+ * their certificate information from a file. It is in interface which
+ * TLS library specific subtypes implement.
+ *
+ * Since: 2.30
+ */
+
+/**
+ * GTlsFileDatabase:
+ *
+ * Implemented by a #GTlsDatabase which allows you to load certificates
+ * from a file.
+ *
+ * Since: 2.30
+ */
+G_DEFINE_INTERFACE (GTlsFileDatabase, g_tls_file_database, G_TYPE_TLS_DATABASE)
+
+static void
+g_tls_file_database_default_init (GTlsFileDatabaseInterface *iface)
+{
+  /**
+   * GTlsFileDatabase:anchors:
+   *
+   * The path to a file containing PEM encoded certificate authority
+   * root anchors. The certificates in this file will be treated as
+   * root authorities for the purpose of verifying other certificates
+   * via the g_tls_database_verify_chain() operation.
+   *
+   * Since: 2.30
+   */
+  g_object_interface_install_property (iface,
+                                       g_param_spec_string ("anchors",
+                                                           P_("Anchors"),
+                                                           P_("The certificate authority anchor file"),
+                                                           NULL,
+                                                           G_PARAM_READWRITE |
+                                                           G_PARAM_CONSTRUCT |
+                                                           G_PARAM_STATIC_STRINGS));
+}
+
+/**
+ * g_tls_file_database_new:
+ * @anchors: filename of anchor certificate authorities.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Creates a new #GTlsFileDatabase which uses anchor certificate authorities
+ * in @anchors to verify certificate chains.
+ *
+ * The certificates in @anchors must be PEM encoded.
+ *
+ * Return value: the new #GTlsFileDatabase, or %NULL on error
+ *
+ * Since: 2.30
+ */
+GTlsDatabase*
+g_tls_file_database_new (const gchar     *anchors,
+                         GError         **error)
+{
+  GObject *database;
+  GTlsBackend *backend;
+
+  backend = g_tls_backend_get_default ();
+  database = g_initable_new (g_tls_backend_get_file_database_type (backend),
+                             NULL, error,
+                             "anchors", anchors,
+                             NULL);
+  return G_TLS_DATABASE (database);
+}
diff --git a/gio/gtlsfiledatabase.h b/gio/gtlsfiledatabase.h
new file mode 100644
index 0000000..bc6a17f
--- /dev/null
+++ b/gio/gtlsfiledatabase.h
@@ -0,0 +1,56 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright © 2010 Collabora, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_TLS_FILE_DATABASE_H__
+#define __G_TLS_FILE_DATABASE_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_FILE_DATABASE                (g_tls_file_database_get_type ())
+#define G_TLS_FILE_DATABASE(inst)               (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_FILE_DATABASE, GTlsFileDatabase))
+#define G_IS_TLS_FILE_DATABASE(inst)            (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_FILE_DATABASE))
+#define G_TLS_FILE_DATABASE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), G_TYPE_TLS_FILE_DATABASE, GTlsFileDatabaseInterface))
+
+typedef struct _GTlsFileDatabaseInterface GTlsFileDatabaseInterface;
+
+/**
+ * GTlsFileDatabaseInterface:
+ * @g_iface: The parent interface.
+ *
+ * Provides an interface for #GTlsFileDatabase implementations.
+ *
+ */
+struct _GTlsFileDatabaseInterface
+{
+  GTypeInterface g_iface;
+
+  /*< private >*/
+  /* Padding for future expansion */
+  gpointer padding[8];
+};
+
+GType                        g_tls_file_database_get_type              (void) G_GNUC_CONST;
+
+GTlsDatabase*                g_tls_file_database_new                   (const gchar  *anchors,
+                                                                        GError      **error);
+
+G_END_DECLS
+
+#endif /* __G_TLS_FILE_DATABASE_H___ */
diff --git a/gio/gtlsinteraction.c b/gio/gtlsinteraction.c
new file mode 100644
index 0000000..5045722
--- /dev/null
+++ b/gio/gtlsinteraction.c
@@ -0,0 +1,162 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gtlsinteraction.h"
+#include "gtlspassword.h"
+#include "gasyncresult.h"
+#include "gsimpleasyncresult.h"
+#include "gioenumtypes.h"
+#include "glibintl.h"
+
+
+/**
+ * SECTION:gtlsinteraction
+ * @short_description: Interaction with the user during TLS operations.
+ * @include: gio/gio.h
+ *
+ * #GTlsInteraction provides a mechanism for the TLS connection and database
+ * code to interact with the user. It can be used to ask the user for passwords.
+ *
+ * To use a #GTlsInteraction with a TLS connection use
+ * g_tls_connection_set_interaction().
+ *
+ * Callers should instantiate a subclass of this that implements all the
+ * various callbacks to show the required dialogs, such as
+ * #GtkTlsInteraction. If no interaction is desired, usually %NULL can be
+ * passed, see each method taking a #GTlsInteraction for details.
+ */
+
+/**
+ * GTlsInteraction:
+ *
+ * An object representing interaction that the TLS connection and database
+ * might have with the user.
+ *
+ * Since: 2.30
+ */
+
+/**
+ * GTlsInteractionClass:
+ *
+ * The class for #GTlsInteraction.
+ *
+ * Since: 2.30
+ */
+
+G_DEFINE_TYPE (GTlsInteraction, g_tls_interaction, G_TYPE_OBJECT);
+
+void
+g_tls_interaction_default_ask_password (GTlsInteraction    *interaction,
+                                        GTlsPassword       *password,
+                                        GAsyncReadyCallback callback,
+                                        gpointer            user_data)
+{
+  GSimpleAsyncResult *res;
+
+  res = g_simple_async_result_new (G_OBJECT (interaction), callback, user_data,
+                                   g_tls_interaction_default_ask_password);
+  g_simple_async_result_complete_in_idle (res);
+  g_object_unref (res);
+}
+
+GTlsInteractionResult
+g_tls_interaction_default_ask_password_finish (GTlsInteraction    *interaction,
+                                               GAsyncResult       *result)
+{
+  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (interaction),
+                        g_tls_interaction_default_ask_password), G_TLS_INTERACTION_ABORTED);
+  return G_TLS_INTERACTION_UNHANDLED;
+}
+
+static void
+g_tls_interaction_init (GTlsInteraction *interaction)
+{
+}
+
+static void
+g_tls_interaction_class_init (GTlsInteractionClass *klass)
+{
+  klass->ask_password = g_tls_interaction_default_ask_password;
+  klass->ask_password_finish = g_tls_interaction_default_ask_password_finish;
+}
+
+/**
+ * g_tls_interaction_ask_password:
+ * @interaction: a #GTlsInteraction object
+ * @password: a #GTlsPassword object
+ * @callback: will be called when the interaction completes
+ * @user_data: (allow-none): data to pass to the @callback
+ *
+ * This function is normally called by #GTlsConnection or #GTlsDatabase to
+ * ask the user for a password.
+ *
+ * Derived subclasses usually implement a password prompt, although they may
+ * also choose to provide a password from elsewhere. The @password value will
+ * be filled in and then @callback will be called. Alternatively the user may
+ * abort this password request, which will usually abort the TLS connection.
+ *
+ * The @callback should call g_tls_interaction_ask_password_finish() to get
+ * the status of the user interaction.
+ *
+ * Since: 2.30
+ */
+void
+g_tls_interaction_ask_password (GTlsInteraction    *interaction,
+                                GTlsPassword       *password,
+                                GAsyncReadyCallback callback,
+                                gpointer            user_data)
+{
+  g_return_if_fail (G_IS_TLS_INTERACTION (interaction));
+  g_return_if_fail (G_IS_TLS_PASSWORD (password));
+  g_return_if_fail (callback);
+  G_TLS_INTERACTION_GET_CLASS (interaction)->ask_password (interaction, password,
+                                                           callback, user_data);
+
+}
+
+/**
+ * g_tls_interaction_ask_password_finish:
+ * @interaction: a #GTlsInteraction object
+ * @result: the result passed to the callback
+ *
+ * Complete an ask password user interaction request. This should be once
+ * the g_tls_interaction_ask_password() completion callback is called.
+ *
+ * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsPassword passed
+ * to g_tls_interaction_ask_password() will have its password filled in.
+ *
+ * Returns: The status of the ask password interaction.
+ *
+ * Since: 2.30
+ */
+GTlsInteractionResult
+g_tls_interaction_ask_password_finish (GTlsInteraction    *interaction,
+                                       GAsyncResult       *result)
+{
+  g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_ABORTED);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_ABORTED);
+  return G_TLS_INTERACTION_GET_CLASS (interaction)->ask_password_finish (interaction, result);
+}
diff --git a/gio/gtlsinteraction.h b/gio/gtlsinteraction.h
new file mode 100644
index 0000000..077a33d
--- /dev/null
+++ b/gio/gtlsinteraction.h
@@ -0,0 +1,94 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_TLS_INTERACTION_H__
+#define __G_TLS_INTERACTION_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_INTERACTION         (g_tls_interaction_get_type ())
+#define G_TLS_INTERACTION(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TLS_INTERACTION, GTlsInteraction))
+#define G_TLS_INTERACTION_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_TLS_INTERACTION, GTlsInteractionClass))
+#define G_IS_TLS_INTERACTION(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TLS_INTERACTION))
+#define G_IS_TLS_INTERACTION_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_TLS_INTERACTION))
+#define G_TLS_INTERACTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_TLS_INTERACTION, GTlsInteractionClass))
+
+typedef struct _GTlsInteractionClass   GTlsInteractionClass;
+typedef struct _GTlsInteractionPrivate GTlsInteractionPrivate;
+
+struct _GTlsInteraction
+{
+  GObject parent_instance;
+
+  GTlsInteractionPrivate *priv;
+};
+
+struct _GTlsInteractionClass
+{
+  GObjectClass parent_class;
+
+  /* virtual methods: */
+
+  void                   (* ask_password)        (GTlsInteraction    *interaction,
+                                                  GTlsPassword       *password,
+                                                  GAsyncReadyCallback callback,
+                                                  gpointer            user_data);
+
+  GTlsInteractionResult  (* ask_password_finish) (GTlsInteraction    *interaction,
+                                                  GAsyncResult       *result);
+
+  /*< private >*/
+  /* Padding for future expansion */
+  void (*_g_reserved1) (void);
+  void (*_g_reserved2) (void);
+  void (*_g_reserved3) (void);
+  void (*_g_reserved4) (void);
+  void (*_g_reserved5) (void);
+  void (*_g_reserved6) (void);
+  void (*_g_reserved7) (void);
+  void (*_g_reserved8) (void);
+  void (*_g_reserved9) (void);
+  void (*_g_reserved10) (void);
+  void (*_g_reserved11) (void);
+  void (*_g_reserved12) (void);
+  void (*_g_reserved13) (void);
+  void (*_g_reserved14) (void);
+};
+
+GType                  g_tls_interaction_get_type            (void) G_GNUC_CONST;
+
+void                   g_tls_interaction_ask_password        (GTlsInteraction    *interaction,
+                                                              GTlsPassword       *password,
+                                                              GAsyncReadyCallback callback,
+                                                              gpointer            user_data);
+GTlsInteractionResult  g_tls_interaction_ask_password_finish (GTlsInteraction    *interaction,
+                                                              GAsyncResult       *result);
+
+G_END_DECLS
+
+#endif /* __G_TLS_INTERACTION_H__ */
diff --git a/gio/gtlspassword.c b/gio/gtlspassword.c
new file mode 100644
index 0000000..eeca9ab
--- /dev/null
+++ b/gio/gtlspassword.c
@@ -0,0 +1,167 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+#include "glib.h"
+
+#include "gtlspassword.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gtlspassword
+ * @title: GTlsPassword
+ * @short_description: TLS Passwords for prompting
+ * @include: gio/gio.h
+ *
+ * Holds a password used in TLS.
+ */
+
+/**
+ * GTlsPassword:
+ *
+ * An abstract interface representing a password used in TLS. Often used in
+ * user interaction such as unlocking a key storage token.
+ *
+ * Since: 2.30
+ */
+
+G_DEFINE_INTERFACE (GTlsPassword, g_tls_password, G_TYPE_OBJECT);
+
+static void
+g_tls_password_default_init (GTlsPasswordInterface *iface)
+{
+}
+
+/**
+ * g_tls_password_get_value:
+ * @password: a #GTlsPassword object
+ * @length: (allow-none): location to place the length of the password.
+ *
+ * Get the password value. If @length is not %NULL then it will be filled
+ * in with the length of the password value.
+ *
+ * Returns: The password value owned by the password object.
+ *
+ * Since: 2.30
+ */
+const guchar *
+g_tls_password_get_value (GTlsPassword  *password,
+                          gsize         *length)
+{
+  g_return_val_if_fail (G_IS_TLS_PASSWORD (password), NULL);
+  return G_TLS_PASSWORD_GET_INTERFACE (password)->get_value (password,
+                                                             length);
+}
+
+/**
+ * g_tls_password_set_value:
+ * @password: a #GTlsPassword object
+ * @value: the new password value
+ * @length: the length of the password, or -1
+ *
+ * Set the value for this password. The @value will be copied by the password
+ * object.
+ *
+ * Specify the @length, for a non-null-terminated password. Pass -1 as
+ * @length if using a null-terminated password, and @length will be calculated
+ * automatically.
+ *
+ * Since: 2.30
+ */
+void
+g_tls_password_set_value (GTlsPassword  *password,
+                          const guchar  *value,
+                          gssize         length)
+{
+  g_return_if_fail (G_IS_TLS_PASSWORD (password));
+
+  if (length < 0)
+    length = strlen ((gchar *)value);
+
+  g_tls_password_take_value (password, g_memdup (value, length), length, g_free);
+}
+
+/**
+ * g_tls_password_take_value:
+ * @password: a #GTlsPassword object
+ * @value: the value for the password
+ * @length: the length of the password, or -1
+ * @destroy: (allow-none): a function to use to free the password.
+ *
+ * Provide the value for this password.
+ *
+ * The @value will be owned by the password object, and later freed using
+ * the @destroy function callback.
+ *
+ * Specify the @length, for a non-null-terminated password. Pass -1 as
+ * @length if using a null-terminated password, and @length will be calculated
+ * automatically.
+ *
+ * Since: 2.30
+ */
+void
+g_tls_password_take_value (GTlsPassword  *password,
+                           guchar        *value,
+                           gssize         length,
+                           GDestroyNotify destroy)
+{
+  g_return_if_fail (G_IS_TLS_PASSWORD (password));
+  G_TLS_PASSWORD_GET_INTERFACE (password)->take_value (password,
+                                                       value,
+                                                       length,
+                                                       destroy);
+}
+
+/**
+ * g_tls_password_get_flags:
+ * @password: a #GTlsPassword object
+ *
+ * Get flags describing the password.
+ *
+ * Return value: The flags about the password.
+ *
+ * Since: 2.30
+ */
+GTlsPasswordFlags
+g_tls_password_get_flags (GTlsPassword *password)
+{
+  g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_PASSWORD_NONE);
+  return G_TLS_PASSWORD_GET_INTERFACE (password)->get_flags (password);
+}
+
+/**
+ * g_tls_password_get_description:
+ * @password: a #GTlsPassword object
+ *
+ * Get a description string about what the password will be used for.
+ *
+ * Return value: The description of the password.
+ *
+ * Since: 2.30
+ */
+const gchar*
+g_tls_password_get_description (GTlsPassword *password)
+{
+  g_return_val_if_fail (G_IS_TLS_PASSWORD (password), NULL);
+  return G_TLS_PASSWORD_GET_INTERFACE (password)->get_description (password);
+}
diff --git a/gio/gtlspassword.h b/gio/gtlspassword.h
new file mode 100644
index 0000000..5d90b7c
--- /dev/null
+++ b/gio/gtlspassword.h
@@ -0,0 +1,96 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_TLS_PASSWORD_H__
+#define __G_TLS_PASSWORD_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_PASSWORD               (g_tls_password_get_type ())
+#define G_TLS_PASSWORD(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_TLS_PASSWORD, GTlsPassword))
+#define G_IS_TLS_PASSWORD(obj)	         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_TLS_PASSWORD))
+#define G_TLS_PASSWORD_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_TLS_PASSWORD, GTlsPasswordInterface))
+
+typedef struct _GTlsPasswordInterface GTlsPasswordInterface;
+
+/**
+ * GTlsPasswordInterface:
+ * @g_iface: The parent interface.
+ * @get_value: get password value for this object
+ * @take_value: provide password value for this object
+ * @get_flags: returns flags about the password
+ * @get_description: returns a description about what the password is used for
+ *
+ * Provides an interface for #GTlsPassword implementations.
+ *
+ * Since: 2.30
+ */
+struct _GTlsPasswordInterface
+{
+  GTypeInterface g_iface;
+
+  /* methods */
+
+  const guchar *    ( *get_value)            (GTlsPassword  *password,
+                                              gsize         *length);
+
+  void              ( *take_value)           (GTlsPassword  *password,
+                                              guchar        *value,
+                                              gssize         length,
+                                              GDestroyNotify destroy);
+
+  GTlsPasswordFlags ( *get_flags)            (GTlsPassword  *password);
+
+  const gchar*      ( *get_description)      (GTlsPassword  *password);
+
+  /*< private >*/
+  /* Padding for future expansion */
+  gpointer padding[4];
+};
+
+GType             g_tls_password_get_type            (void) G_GNUC_CONST;
+
+const guchar *    g_tls_password_get_value           (GTlsPassword  *password,
+                                                      gsize         *length);
+
+void              g_tls_password_set_value           (GTlsPassword  *password,
+                                                      const guchar  *value,
+                                                      gssize         length);
+
+void              g_tls_password_take_value          (GTlsPassword  *password,
+                                                      guchar        *value,
+                                                      gssize         length,
+                                                      GDestroyNotify destroy);
+
+GTlsPasswordFlags g_tls_password_get_flags           (GTlsPassword  *password);
+
+const gchar*      g_tls_password_get_description     (GTlsPassword  *password);
+
+G_END_DECLS
+
+#endif /* __G_TLS_PASSWORD_H__ */
diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore
index 7df867e..a24e332 100644
--- a/gio/tests/.gitignore
+++ b/gio/tests/.gitignore
@@ -78,6 +78,7 @@ socket-client
 socket-server
 srvtarget
 test.mo
+tls
 unix-fd
 unix-streams
 volumemonitor
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 9929254..8765154 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -50,6 +50,7 @@ TEST_PROGS +=	 		\
 	gdbus-message		\
 	socket			\
 	pollable		\
+	tls				\
 	$(NULL)
 
 if OS_UNIX
@@ -193,10 +194,15 @@ socket_server_SOURCES	  = socket-server.c
 socket_server_LDADD	  = $(progs_ldadd) \
 	$(top_builddir)/gthread/libgthread-2.0.la
 
-socket_client_SOURCES	  = socket-client.c
+socket_client_SOURCES	  = socket-client.c \
+                            gtlsconsoleinteraction.c \
+                            gtlsconsoleinteraction.h
 socket_client_LDADD	  = $(progs_ldadd) \
 	$(top_builddir)/gthread/libgthread-2.0.la
 
+tls_SOURCES	  = tls.c
+tls_LDADD	  = $(progs_ldadd)
+
 echo_server_SOURCES	  = echo-server.c
 echo_server_LDADD	  = $(progs_ldadd) \
 	$(top_builddir)/gthread/libgthread-2.0.la
@@ -440,6 +446,17 @@ schema_tests = \
 	schema-tests/range.gschema.xml					\
 	schema-tests/wrong-category.gschema.xml
 
+tls_tests = \
+	tls-tests/ca.pem		\
+	tls-tests/ca-roots.pem		\
+	tls-tests/client-and-key.pem		\
+	tls-tests/client-future.pem		\
+	tls-tests/client-past.pem		\
+	tls-tests/client.pem		\
+	tls-tests/server-and-key.pem		\
+	tls-tests/server.der		\
+	tls-tests/server.pem
+
 proxy_SOURCES = proxy.c
 proxy_LDADD   = $(progs_ldadd) \
 	$(top_builddir)/gthread/libgthread-2.0.la
@@ -464,6 +481,7 @@ EXTRA_DIST += \
 	enums.xml.template		\
 	de.po				\
 	$(schema_tests)			\
+	$(tls_tests)			\
 	appinfo-test.desktop		\
 	appinfo-test2.desktop		\
 	appinfo-test-gnome.desktop	\
diff --git a/gio/tests/gtlsconsoleinteraction.c b/gio/tests/gtlsconsoleinteraction.c
new file mode 100644
index 0000000..c051b67
--- /dev/null
+++ b/gio/tests/gtlsconsoleinteraction.c
@@ -0,0 +1,98 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gtlsconsoleinteraction.h"
+
+/*
+ * WARNING: This is not the example you're looking for [slow hand wave]. This
+ * is not industrial strength, it's just for testing. It uses embarassing
+ * functions like getpass() and does lazy things with threads.
+ */
+
+G_DEFINE_TYPE (GTlsConsoleInteraction, g_tls_console_interaction, G_TYPE_TLS_INTERACTION);
+
+static void
+ask_password_with_getpass (GSimpleAsyncResult    *res,
+                           GObject               *object,
+                           GCancellable          *cancellable)
+{
+  GTlsPassword *password;
+  const gchar *value;
+  gchar *prompt;
+
+  password = g_simple_async_result_get_op_res_gpointer (res);
+
+  prompt = g_strdup_printf ("Password \"%s\"': ", g_tls_password_get_description (password));
+  value = getpass (prompt);
+  g_free (prompt);
+
+  g_tls_password_set_value (password, (guchar *)value, -1);
+}
+
+void
+g_tls_console_interaction_ask_password (GTlsInteraction    *interaction,
+                                        GTlsPassword       *password,
+                                        GAsyncReadyCallback callback,
+                                        gpointer            user_data)
+{
+  GSimpleAsyncResult *res;
+
+  res = g_simple_async_result_new (G_OBJECT (interaction), callback, user_data,
+                                   g_tls_console_interaction_ask_password);
+  g_simple_async_result_set_op_res_gpointer (res, g_object_ref (password), g_object_unref);
+  g_simple_async_result_run_in_thread (res, ask_password_with_getpass,
+                                       G_PRIORITY_DEFAULT, NULL);
+  g_object_unref (res);
+}
+
+GTlsInteractionResult
+g_tls_console_interaction_ask_password_finish (GTlsInteraction    *interaction,
+                                               GAsyncResult       *result)
+{
+  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (interaction),
+                        g_tls_console_interaction_ask_password), G_TLS_INTERACTION_ABORTED);
+  return G_TLS_INTERACTION_HANDLED;
+}
+
+static void
+g_tls_console_interaction_init (GTlsConsoleInteraction *interaction)
+{
+
+}
+
+static void
+g_tls_console_interaction_class_init (GTlsConsoleInteractionClass *klass)
+{
+  GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
+  interaction_class->ask_password = g_tls_console_interaction_ask_password;
+  interaction_class->ask_password_finish = g_tls_console_interaction_ask_password_finish;
+}
+
+GTlsInteraction *
+g_tls_console_interaction_new (void)
+{
+  return g_object_new (G_TYPE_TLS_CONSOLE_INTERACTION, NULL);
+}
diff --git a/gio/tests/gtlsconsoleinteraction.h b/gio/tests/gtlsconsoleinteraction.h
new file mode 100644
index 0000000..eaf4d18
--- /dev/null
+++ b/gio/tests/gtlsconsoleinteraction.h
@@ -0,0 +1,56 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#ifndef __G_TLS_CONSOLE_INTERACTION_H__
+#define __G_TLS_CONSOLE_INTERACTION_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_CONSOLE_INTERACTION         (g_tls_console_interaction_get_type ())
+#define G_TLS_CONSOLE_INTERACTION(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TLS_CONSOLE_INTERACTION, GTlsConsoleInteraction))
+#define G_TLS_CONSOLE_INTERACTION_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_TLS_CONSOLE_INTERACTION, GTlsConsoleInteractionClass))
+#define G_IS_TLS_CONSOLE_INTERACTION(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TLS_CONSOLE_INTERACTION))
+#define G_IS_TLS_CONSOLE_INTERACTION_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_TLS_CONSOLE_INTERACTION))
+#define G_TLS_CONSOLE_INTERACTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_TLS_CONSOLE_INTERACTION, GTlsConsoleInteractionClass))
+
+typedef struct _GTlsConsoleInteraction        GTlsConsoleInteraction;
+typedef struct _GTlsConsoleInteractionClass   GTlsConsoleInteractionClass;
+
+struct _GTlsConsoleInteraction
+{
+  GTlsInteraction parent_instance;
+};
+
+struct _GTlsConsoleInteractionClass
+{
+  GTlsInteractionClass parent_class;
+};
+
+GType                  g_tls_console_interaction_get_type    (void) G_GNUC_CONST;
+
+GTlsInteraction *      g_tls_console_interaction_new         (void);
+
+G_END_DECLS
+
+#endif /* __G_TLS_CONSOLE_INTERACTION_H__ */
diff --git a/gio/tests/socket-client.c b/gio/tests/socket-client.c
index 6068034..578b0c8 100644
--- a/gio/tests/socket-client.c
+++ b/gio/tests/socket-client.c
@@ -5,6 +5,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "gtlsconsoleinteraction.h"
+
 GMainLoop *loop;
 
 gboolean verbose = FALSE;
@@ -59,59 +61,57 @@ accept_certificate (GTlsClientConnection *conn, GTlsCertificate *cert,
   return TRUE;
 }
 
-int
-main (int argc,
-      char *argv[])
+static GTlsCertificate *
+lookup_client_certificate (GTlsClientConnection *conn, GError **error)
 {
-  GSocket *socket;
-  GSocketAddress *src_address;
-  GSocketAddress *address;
-  GSocketType socket_type;
-  GSocketFamily socket_family;
-  GError *error = NULL;
-  GOptionContext *context;
-  GCancellable *cancellable;
-  GSocketAddressEnumerator *enumerator;
-  GSocketConnectable *connectable;
-  GIOStream *connection;
-  GInputStream *istream;
-  GOutputStream *ostream;
-
-  g_thread_init (NULL);
-
-  g_type_init ();
-
-  context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff");
-  g_option_context_add_main_entries (context, cmd_entries, NULL);
-  if (!g_option_context_parse (context, &argc, &argv, &error))
+  GList *l, *accepted;
+  GList *c, *certificates;
+  GTlsDatabase *database;
+  GTlsCertificate *certificate = NULL;
+  GTlsConnection *base;
+
+  accepted = g_tls_client_connection_get_accepted_cas (conn);
+  for (l = accepted; l != NULL; l = g_list_next (l))
     {
-      g_printerr ("%s: %s\n", argv[0], error->message);
-      return 1;
+      base = G_TLS_CONNECTION (conn);
+      database = g_tls_connection_get_database (base);
+      certificates = g_tls_database_lookup_certificates_issued_by (database, l->data,
+                                                                   g_tls_connection_get_interaction (base),
+                                                                   G_TLS_DATABASE_LOOKUP_KEYPAIR,
+                                                                   NULL, error);
+      if (error && *error)
+        break;
+
+      if (certificates)
+          certificate = g_object_ref (certificates->data);
+
+      for (c = certificates; c != NULL; c = g_list_next (c))
+        g_object_unref (c->data);
+      g_list_free (certificates);
     }
 
-  if (argc != 2)
-    {
-      g_printerr ("%s: %s\n", argv[0], "Need to specify hostname / unix socket name");
-      return 1;
-    }
+  for (l = accepted; l != NULL; l = g_list_next (l))
+    g_byte_array_unref (l->data);
+  g_list_free (accepted);
 
-  if (use_udp && tls)
-    {
-      g_printerr ("DTLS (TLS over UDP) is not supported");
-      return 1;
-    }
-
-  if (cancel_timeout)
-    {
-      cancellable = g_cancellable_new ();
-      g_thread_create (cancel_thread, cancellable, FALSE, NULL);
-    }
-  else
-    {
-      cancellable = NULL;
-    }
+  if (certificate == NULL && error && !*error)
+    g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED,
+                         "Server requested a certificate, but could not find relevant certificate in database.");
+  return certificate;
+}
 
-  loop = g_main_loop_new (NULL, FALSE);
+static gboolean
+make_connection (const char *argument, GTlsCertificate *certificate, GCancellable *cancellable,
+                 GSocket **socket, GSocketAddress **address, GIOStream **connection,
+                 GInputStream **istream, GOutputStream **ostream, GError **error)
+{
+  GSocketType socket_type;
+  GSocketFamily socket_family;
+  GSocketAddressEnumerator *enumerator;
+  GSocketConnectable *connectable;
+  GSocketAddress *src_address;
+  GTlsInteraction *interaction;
+  GError *err = NULL;
 
   if (use_udp)
     socket_type = G_SOCKET_TYPE_DATAGRAM;
@@ -123,116 +123,187 @@ main (int argc,
   else
     socket_family = G_SOCKET_FAMILY_IPV4;
 
-  socket = g_socket_new (socket_family, socket_type, 0, &error);
-  if (socket == NULL)
-    {
-      g_printerr ("%s: %s\n", argv[0], error->message);
-      return 1;
-    }
+  *socket = g_socket_new (socket_family, socket_type, 0, error);
+  if (*socket == NULL)
+    return FALSE;
 
   if (read_timeout)
-    g_socket_set_timeout (socket, read_timeout);
+    g_socket_set_timeout (*socket, read_timeout);
 
   if (unix_socket)
     {
       GSocketAddress *addr;
 
-      addr = socket_address_from_string (argv[1]);
+      addr = socket_address_from_string (argument);
       if (addr == NULL)
-	{
-	  g_printerr ("%s: Could not parse '%s' as unix socket name\n", argv[0], argv[1]);
-	  return 1;
-	}
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Could not parse '%s' as unix socket name", argument);
+          return FALSE;
+        }
       connectable = G_SOCKET_CONNECTABLE (addr);
     }
   else
     {
-      connectable = g_network_address_parse (argv[1], 7777, &error);
+      connectable = g_network_address_parse (argument, 7777, error);
       if (connectable == NULL)
-	{
-	  g_printerr ("%s: %s\n", argv[0], error->message);
-	  return 1;
-	}
+        return FALSE;
     }
 
   enumerator = g_socket_connectable_enumerate (connectable);
   while (TRUE)
     {
-      address = g_socket_address_enumerator_next (enumerator, cancellable, &error);
-      if (address == NULL)
-	{
-	  if (error == NULL)
-	    g_printerr ("%s: No more addresses to try\n", argv[0]);
-	  else
-	    g_printerr ("%s: %s\n", argv[0], error->message);
-	  return 1;
-	}
-
-      if (g_socket_connect (socket, address, cancellable, &error))
-	break;
-      g_printerr ("%s: Connection to %s failed: %s, trying next\n", argv[0], socket_address_to_string (address), error->message);
-      g_error_free (error);
-      error = NULL;
-
-      g_object_unref (address);
+      *address = g_socket_address_enumerator_next (enumerator, cancellable, error);
+      if (*address == NULL)
+        {
+          if (error == NULL)
+            g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                                 "No more addresses to try");
+          return FALSE;
+        }
+
+      if (g_socket_connect (*socket, *address, cancellable, &err))
+        break;
+      g_message ("Connection to %s failed: %s, trying next\n", socket_address_to_string (*address), err->message);
+      g_clear_error (&err);
+
+      g_object_unref (*address);
     }
   g_object_unref (enumerator);
 
   g_print ("Connected to %s\n",
-	   socket_address_to_string (address));
+           socket_address_to_string (*address));
 
-  src_address = g_socket_get_local_address (socket, &error);
+  src_address = g_socket_get_local_address (*socket, error);
   if (!src_address)
     {
-      g_printerr ("Error getting local address: %s\n",
-		  error->message);
-      return 1;
+      g_prefix_error (error, "Error getting local address: ");
+      return FALSE;
     }
+
   g_print ("local address: %s\n",
-	   socket_address_to_string (src_address));
+           socket_address_to_string (src_address));
   g_object_unref (src_address);
 
   if (use_udp)
     {
-      connection = NULL;
-      istream = NULL;
-      ostream = NULL;
+      *connection = NULL;
+      *istream = NULL;
+      *ostream = NULL;
     }
   else
-    connection = G_IO_STREAM (g_socket_connection_factory_create_connection (socket));
+    *connection = G_IO_STREAM (g_socket_connection_factory_create_connection (*socket));
 
   if (tls)
     {
       GIOStream *tls_conn;
 
-      tls_conn = g_tls_client_connection_new (connection, connectable, &error);
+      tls_conn = g_tls_client_connection_new (*connection, connectable, error);
       if (!tls_conn)
-	{
-	  g_printerr ("Could not create TLS connection: %s\n",
-		      error->message);
-	  return 1;
-	}
+        {
+          g_prefix_error (error, "Could not create TLS connection: ");
+          return FALSE;
+        }
 
       g_signal_connect (tls_conn, "accept-certificate",
-			G_CALLBACK (accept_certificate), NULL);
+                        G_CALLBACK (accept_certificate), NULL);
 
-      if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn),
-				       cancellable, &error))
-	{
-	  g_printerr ("Error during TLS handshake: %s\n",
-		      error->message);
-	  return 1;
-	}
+      interaction = g_tls_console_interaction_new ();
+      g_tls_connection_set_interaction (G_TLS_CONNECTION (tls_conn), interaction);
+      g_object_unref (interaction);
 
-      g_object_unref (connection);
-      connection = G_IO_STREAM (tls_conn);
+      if (certificate)
+        g_tls_connection_set_certificate (G_TLS_CONNECTION (tls_conn), certificate);
+
+      g_object_unref (*connection);
+      *connection = G_IO_STREAM (tls_conn);
+
+      if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn),
+                                       cancellable, error))
+        {
+          g_prefix_error (error, "Error during TLS handshake: ");
+          return FALSE;
+        }
     }
   g_object_unref (connectable);
 
-  if (connection)
+  if (*connection)
     {
-      istream = g_io_stream_get_input_stream (connection);
-      ostream = g_io_stream_get_output_stream (connection);
+      *istream = g_io_stream_get_input_stream (*connection);
+      *ostream = g_io_stream_get_output_stream (*connection);
+    }
+
+  return TRUE;
+}
+
+int
+main (int argc,
+      char *argv[])
+{
+  GSocket *socket;
+  GSocketAddress *address;
+  GError *error = NULL;
+  GOptionContext *context;
+  GCancellable *cancellable;
+  GIOStream *connection;
+  GInputStream *istream;
+  GOutputStream *ostream;
+  GSocketAddress *src_address;
+  GTlsCertificate *certificate = NULL;
+  gint i;
+
+  g_thread_init (NULL);
+
+  g_type_init ();
+
+  context = g_option_context_new (" <hostname>[:port] - Test GSocket client stuff");
+  g_option_context_add_main_entries (context, cmd_entries, NULL);
+  if (!g_option_context_parse (context, &argc, &argv, &error))
+    {
+      g_printerr ("%s: %s\n", argv[0], error->message);
+      return 1;
+    }
+
+  if (argc != 2)
+    {
+      g_printerr ("%s: %s\n", argv[0], "Need to specify hostname / unix socket name");
+      return 1;
+    }
+
+  if (use_udp && tls)
+    {
+      g_printerr ("DTLS (TLS over UDP) is not supported");
+      return 1;
+    }
+
+  if (cancel_timeout)
+    {
+      cancellable = g_cancellable_new ();
+      g_thread_create (cancel_thread, cancellable, FALSE, NULL);
+    }
+  else
+    {
+      cancellable = NULL;
+    }
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  for (i = 0; i < 2; i++)
+    {
+      if (make_connection (argv[1], certificate, cancellable, &socket, &address,
+                           &connection, &istream, &ostream, &error))
+          break;
+
+      if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED))
+        {
+          g_clear_error (&error);
+          certificate = lookup_client_certificate (G_TLS_CLIENT_CONNECTION (connection), &error);
+          if (certificate != NULL)
+            continue;
+        }
+
+      g_printerr ("%s: %s", argv[0], error->message);
+      return 1;
     }
 
   /* TODO: Test non-blocking connect/handshake */
diff --git a/gio/tests/tls-tests/ca-roots.pem b/gio/tests/tls-tests/ca-roots.pem
new file mode 100644
index 0000000..cf9e9d5
--- /dev/null
+++ b/gio/tests/tls-tests/ca-roots.pem
@@ -0,0 +1,202 @@
+-----BEGIN CERTIFICATE-----
+MIIDxjCCAy+gAwIBAgIJAOpd4Em2fjp3MA0GCSqGSIb3DQEBBQUAMIGGMRMwEQYK
+CZImiZPyLGQBGRYDQ09NMRcwFQYKCZImiZPyLGQBGRYHRVhBTVBMRTEeMBwGA1UE
+CxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRcwFQYDVQQDEw5jYS5leGFtcGxlLmNv
+bTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBsZS5jb20wHhcNMDcxMjIwMTc1NjA2
+WhcNMzUwNTA4MTc1NjA2WjCBhjETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmS
+JomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0
+eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkqhkiG9w0BCQEWDmNhQGV4
+YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD5OjHuXXN2LG3s
+FHISaZZ6L1RSYgRdTenu1nvqkMn/xvzOz385oede1z/7f6BoXyM0kNWCf4SOXtXr
+EIGmQoeURhFfLCnoK8NHfNcel3IPyMPhdJUMJlc3gfpWm+QxjkyqVyMhyYxC9Pmg
+QC7zx4ZKcQrL3zVGYtg8wxmaKY2HwQIDAQABo4IBODCCATQwHQYDVR0OBBYEFNSE
+nYhMCPaaFynFeQ2R5y25+AcFMIG7BgNVHSMEgbMwgbCAFNSEnYhMCPaaFynFeQ2R
+5y25+AcFoYGMpIGJMIGGMRMwEQYKCZImiZPyLGQBGRYDQ09NMRcwFQYKCZImiZPy
+LGQBGRYHRVhBTVBMRTEeMBwGA1UECxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRcw
+FQYDVQQDEw5jYS5leGFtcGxlLmNvbTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBs
+ZS5jb22CCQDqXeBJtn46dzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAZBgNVHREEEjAQgQ5jYUBleGFtcGxlLmNvbTAZBgNVHRIEEjAQgQ5jYUBleGFt
+cGxlLmNvbTANBgkqhkiG9w0BAQUFAAOBgQA6xjU2aPgMOh2yyz2KCb6d5gNNvfr4
+pLGpZWilbRkA36OOG43zxeRZoumh1ybyOvhm73cMvNihDUyOf7vQe75Qtp5koGPS
+V3mSruhsRGvOZxcV+SJnBj1exKyH3mdaZA74Xg4y5qkUkywPqnP5Y+E6UMJM7Nmw
+kHk2bKJC5vjxoA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
+IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
+IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
+Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
+BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
+MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
+ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
+8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
+zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
+fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
+w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
+G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
+epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
+laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
+QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
+fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
+YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
+ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
+gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
+MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
+IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
+dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
+czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
+dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
+aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
+AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
+b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
+ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
+nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
+18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
+gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
+Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
+sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
+SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
+CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
+GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
+zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
+omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGCDCCA/CgAwIBAgIBATANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
+IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
+IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
+Y2FjZXJ0Lm9yZzAeFw0wNTEwMTQwNzM2NTVaFw0zMzAzMjgwNzM2NTVaMFQxFDAS
+BgNVBAoTC0NBY2VydCBJbmMuMR4wHAYDVQQLExVodHRwOi8vd3d3LkNBY2VydC5v
+cmcxHDAaBgNVBAMTE0NBY2VydCBDbGFzcyAzIFJvb3QwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQCrSTURSHzSJn5TlM9Dqd0o10Iqi/OHeBlYfA+e2ol9
+4fvrcpANdKGWZKufoCSZc9riVXbHF3v1BKxGuMO+f2SNEGwk82GcwPKQ+lHm9WkB
+Y8MPVuJKQs/iRIwlKKjFeQl9RrmK8+nzNCkIReQcn8uUBByBqBSzmGXEQ+xOgo0J
+0b2qW42S0OzekMV/CsLj6+YxWl50PpczWejDAz1gM7/30W9HxM3uYoNSbi4ImqTZ
+FRiRpoWSR7CuSOtttyHshRpocjWr//AQXcD0lKdq1TuSfkyQBX6TwSyLpI5idBVx
+bgtxA+qvFTia1NIFcm+M+SvrWnIl+TlG43IbPgTDZCciECqKT1inA62+tC4T7V2q
+SNfVfdQqe1z6RgRQ5MwOQluM7dvyz/yWk+DbETZUYjQ4jwxgmzuXVjit89Jbi6Bb
+6k6WuHzX1aCGcEDTkSm3ojyt9Yy7zxqSiuQ0e8DYbF/pCsLDpyCaWt8sXVJcukfV
+m+8kKHA4IC/VfynAskEDaJLM4JzMl0tF7zoQCqtwOpiVcK01seqFK6QcgCExqa5g
+eoAmSAC4AcCTY1UikTxW56/bOiXzjzFU6iaLgVn5odFTEcV7nQP2dBHgbbEsPyyG
+kZlxmqZ3izRg0RS0LKydr4wQ05/EavhvE/xzWfdmQnQeiuP43NJvmJzLR5iVQAX7
+6QIDAQABo4G/MIG8MA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUHAQEEUTBPMCMG
+CCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggrBgEFBQcwAoYc
+aHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBBMD8GCCsGAQQB
+gZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9yZy9pbmRleC5w
+aHA/aWQ9MTAwDQYJKoZIhvcNAQEEBQADggIBAH8IiKHaGlBJ2on7oQhy84r3HsQ6
+tHlbIDCxRd7CXdNlafHCXVRUPIVfuXtCkcKZ/RtRm6tGpaEQU55tiKxzbiwzpvD0
+nuB1wT6IRanhZkP+VlrRekF490DaSjrxC1uluxYG5sLnk7mFTZdPsR44Q4Dvmw2M
+77inYACHV30eRBzLI++bPJmdr7UpHEV5FpZNJ23xHGzDwlVks7wU4vOkHx4y/CcV
+Bc/dLq4+gmF78CEQGPZE6lM5+dzQmiDgxrvgu1pPxJnIB721vaLbLmINQjRBvP+L
+ivVRIqqIMADisNS8vmW61QNXeZvo3MhN+FDtkaVSKKKs+zZYPumUK5FQhxvWXtaM
+zPcPEAxSTtAWYeXlCmy/F8dyRlecmPVsYGN6b165Ti/Iubm7aoW8mA3t+T6XhDSU
+rgCvoeXnkm5OvfPi2RSLXNLrAWygF6UtEOucekq9ve7O/e0iQKtwOIj1CodqwqsF
+YMlIBdpTwd5Ed2qz8zw87YC8pjhKKSRf/lk7myV6VmMAZLldpGJ9VzZPrYPvH5JT
+oI53V93lYRE9IwCQTDz6o2CTBKOvNfYOao9PSmCnhQVsRqGP9Md246FZV/dxssRu
+FFxtbUFm3xuTsdQAw+7Lzzw9IYCpX2Nl/N3gX6T0K/CFcUHUZyX7GrGXrtaZghNB
+0m6lG5kngOcLqagA
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC
+WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
+MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
+aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl
+cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp
+Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow
+gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV
+BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm
+BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV
+BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ
+cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK
+P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ
+fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j
+kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB
+gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
+c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95
+B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC
+WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
+MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
+aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl
+cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m
+cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz
+NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx
+EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp
+bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x
+JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG
+SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq
+hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N
+j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef
+QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY
+x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
+MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC
+neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr
+5PjRzneigQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC
+WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
+MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm
+aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl
+cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy
+ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5
+NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw
+EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n
+MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw
+IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3
+DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3
+DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7
+7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j
+Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq
+W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
+b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx
+eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1
+KzGJ
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC
+WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
+MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy
+dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl
+IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl
+cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1
+OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ
+BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg
+Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x
+ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3
+DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI
+NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL
+lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN
+9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
+AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ
+a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU
+Qg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC
+WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du
+MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy
+dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl
+IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
+ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG
+A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw
+ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
+CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ
+VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz
+QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I
+/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC
+6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX
+TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G
+A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD
+TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni
+TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
diff --git a/gio/tests/tls-tests/ca.pem b/gio/tests/tls-tests/ca.pem
new file mode 100644
index 0000000..b8d6008
--- /dev/null
+++ b/gio/tests/tls-tests/ca.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDxjCCAy+gAwIBAgIJAOpd4Em2fjp3MA0GCSqGSIb3DQEBBQUAMIGGMRMwEQYK
+CZImiZPyLGQBGRYDQ09NMRcwFQYKCZImiZPyLGQBGRYHRVhBTVBMRTEeMBwGA1UE
+CxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRcwFQYDVQQDEw5jYS5leGFtcGxlLmNv
+bTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBsZS5jb20wHhcNMDcxMjIwMTc1NjA2
+WhcNMzUwNTA4MTc1NjA2WjCBhjETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmS
+JomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0
+eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkqhkiG9w0BCQEWDmNhQGV4
+YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD5OjHuXXN2LG3s
+FHISaZZ6L1RSYgRdTenu1nvqkMn/xvzOz385oede1z/7f6BoXyM0kNWCf4SOXtXr
+EIGmQoeURhFfLCnoK8NHfNcel3IPyMPhdJUMJlc3gfpWm+QxjkyqVyMhyYxC9Pmg
+QC7zx4ZKcQrL3zVGYtg8wxmaKY2HwQIDAQABo4IBODCCATQwHQYDVR0OBBYEFNSE
+nYhMCPaaFynFeQ2R5y25+AcFMIG7BgNVHSMEgbMwgbCAFNSEnYhMCPaaFynFeQ2R
+5y25+AcFoYGMpIGJMIGGMRMwEQYKCZImiZPyLGQBGRYDQ09NMRcwFQYKCZImiZPy
+LGQBGRYHRVhBTVBMRTEeMBwGA1UECxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MRcw
+FQYDVQQDEw5jYS5leGFtcGxlLmNvbTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBs
+ZS5jb22CCQDqXeBJtn46dzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAZBgNVHREEEjAQgQ5jYUBleGFtcGxlLmNvbTAZBgNVHRIEEjAQgQ5jYUBleGFt
+cGxlLmNvbTANBgkqhkiG9w0BAQUFAAOBgQA6xjU2aPgMOh2yyz2KCb6d5gNNvfr4
+pLGpZWilbRkA36OOG43zxeRZoumh1ybyOvhm73cMvNihDUyOf7vQe75Qtp5koGPS
+V3mSruhsRGvOZxcV+SJnBj1exKyH3mdaZA74Xg4y5qkUkywPqnP5Y+E6UMJM7Nmw
+kHk2bKJC5vjxoA==
+-----END CERTIFICATE-----
diff --git a/gio/tests/tls-tests/client-and-key.pem b/gio/tests/tls-tests/client-and-key.pem
new file mode 100644
index 0000000..897b5f2
--- /dev/null
+++ b/gio/tests/tls-tests/client-and-key.pem
@@ -0,0 +1,45 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAkUCAQkwDQYJKoZIhvcNAQEFBQAwgYYxEzARBgoJkiaJk/IsZAEZFgND
+T00xFzAVBgoJkiaJk/IsZAEZFgdFWEFNUExFMR4wHAYDVQQLExVDZXJ0aWZpY2F0
+ZSBBdXRob3JpdHkxFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcN
+AQkBFg5jYUBleGFtcGxlLmNvbTAeFw0xMTAxMTgwNjA0MTFaFw0yMTAxMTUwNjA0
+MTFaMGIxEzARBgoJkiaJk/IsZAEZFgNDT00xFzAVBgoJkiaJk/IsZAEZFgdFWEFN
+UExFMQ8wDQYDVQQDEwZDbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFt
+cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEgNDM/dg3t
+9DHNAPz/b87LSxEaKhoZ8AcNBym3LEOdCnXGEnKf0b9lkT5caXu5GAM84ahTCJ7n
+79RVNrqGKM7jbBdSX+ZUfkqJQPhOXD2+0niYQicH92nz78kxmjlbizvd3fM1BlO+
+C/++NWf2EAhORVAjvJrHNokJp3PTNRJ1WWteHeU9PwfGmWHKVc1IgvRFMH08604I
+ZzX5CcxIg/b56g27A7CBPh/KO/qKTDLFFNGc1T2asvY/P3+PeN6y+leFHStCTu7R
+Bi/l4hczZdnwq3BGT6mnjEN7wau2s7pA067SXimNOkYi5fgwspMHi8fJWmYyBypU
+mQBRzwfm77ECAwEAATANBgkqhkiG9w0BAQUFAAOBgQA3LuElj2QB9wQvmIxk2Jmb
+IPP2/WS8dwPoCv/N3+6nTx8yRsrILf4QsnEbbsxoYO5jW4r9Kt8m8B/M7YgnBDE9
+zlm7JbXKZf2isSm5TyT627Ymzxrzs5d+7o2eS7SN1DB6PyvRh2ye7EMbyEYD8ULi
+itDUkYkssNCVivYwVvJoMg==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAwSA0Mz92De30Mc0A/P9vzstLERoqGhnwBw0HKbcsQ50KdcYS
+cp/Rv2WRPlxpe7kYAzzhqFMInufv1FU2uoYozuNsF1Jf5lR+SolA+E5cPb7SeJhC
+Jwf3afPvyTGaOVuLO93d8zUGU74L/741Z/YQCE5FUCO8msc2iQmnc9M1EnVZa14d
+5T0/B8aZYcpVzUiC9EUwfTzrTghnNfkJzEiD9vnqDbsDsIE+H8o7+opMMsUU0ZzV
+PZqy9j8/f4943rL6V4UdK0JO7tEGL+XiFzNl2fCrcEZPqaeMQ3vBq7azukDTrtJe
+KY06RiLl+DCykweLx8laZjIHKlSZAFHPB+bvsQIDAQABAoIBAQCQUI1RYnHIdPFO
+qZ+8bvDQ+g8tR30ApjM8QZsBrDRyjg579bhhWVY2jSJdFFdqseTkvoDt9KZzgGQy
+Kj9MYOZru3xRbSfmiWsaLbiUFJJPPaIvpa+BVS2oSjX8BYn2pJbF9MRfclc5CsIS
+qMNl3XUbj8mx2hKdIpJ5EvLD1adKE4Se6peqSZAmEHONNCsrMrQ0GSQqV3viInJr
+tc3kp3HcPffSROWqmc6jAJ77Cs3ApgJavL5RGjx30Kd+dKVq4PXZ+IhWM8dOSput
+wcyxEosiP/W2g0rDgNW2mGOVOwa/D5SnOolicHifdV7idjwLAjkyYgvmBMNSsECj
+yKBkE0gxAoGBAN8iHMumyvriHuj9bSLZ1bcyYFz7jIwUxpHTT7VqN/j/Y1BoBIBy
+ZZLDGMa+ID/brpRHzJQAKSNtbFQ0S1HTSKcFud5OWE8Rp3pQJU+sdeO3pCMWAD1z
+Q4ggF07JjTSSnK+4fcXgEN9P2OdfXy7Rj3HFpSahql55Kp5udoUdzUVFAoGBAN2S
+krlcEuqsEYjqsCJw5pctIwPMvCM51JgirrdETwSGquMklSrobH0PHMlR67gsA/9I
+UGShT0LL4UWYpBn/4xLrLbua5aHIBfQQZp9K6jDZddWS+EFL5JkO/Up4/qM6fUbH
+CuweVv1gd6i2Ti35K60mgx6MqVunaB1k8Q9P3Pl9AoGALSVtxha9Qv21W1bLWh3R
+C/v5W1baHQ2nD6I9omsXYB3sLjydjI+Y1ZT70lptk/4S2JWeYuOVb0GYhYD/LFMf
+hAu4i642V+kuhaTpp7ExOR3S6/ZrngNQSp6TmLFXDKgNY9BkQkEPqN8y971oOMTV
+zSM8QxC6s9q4MM4Q1OYuvjECgYEAsO2V1AW95T45Ukd1FktpFlaomyQlJ0vKgyFO
+unEFV+vhETfpFTY7SzGCHxAXVh1vo62u5Gwayo/a9qQIhepa/IRnJGNv8luyxU1D
+ZPeBQjija0PMkPd1NvNNNuafDuBpoNbX1ev0MqeRZVsN2pAZXE5gbUiNA+8NqEsu
+Yre3EFECgYEA13rXE76zZgsefx+2spjqJDUWEmTDd1460xTtxCCgL9dy4rW5bgwo
+MvINphSUXOwSkn8Oja/IvpN28zSj9W/ci5wU52P5w4blkBmuj8UoCjP2FN1b1OBa
+86mkwVsCYUyyI2apuwrHP77yeb8jXZb+reqSns3hU+HyO/nUTVmnews=
+-----END RSA PRIVATE KEY-----
diff --git a/gio/tests/tls-tests/client-future.pem b/gio/tests/tls-tests/client-future.pem
new file mode 100644
index 0000000..de1cb75
--- /dev/null
+++ b/gio/tests/tls-tests/client-future.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAkUCAQowDQYJKoZIhvcNAQEFBQAwgYYxEzARBgoJkiaJk/IsZAEZFgND
+T00xFzAVBgoJkiaJk/IsZAEZFgdFWEFNUExFMR4wHAYDVQQLExVDZXJ0aWZpY2F0
+ZSBBdXRob3JpdHkxFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcN
+AQkBFg5jYUBleGFtcGxlLmNvbTAeFw0yMDAxMTgxNzI3MDNaFw0yMTAxMTcxNzI3
+MDNaMGIxEzARBgoJkiaJk/IsZAEZFgNDT00xFzAVBgoJkiaJk/IsZAEZFgdFWEFN
+UExFMQ8wDQYDVQQDEwZDbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFt
+cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEgNDM/dg3t
+9DHNAPz/b87LSxEaKhoZ8AcNBym3LEOdCnXGEnKf0b9lkT5caXu5GAM84ahTCJ7n
+79RVNrqGKM7jbBdSX+ZUfkqJQPhOXD2+0niYQicH92nz78kxmjlbizvd3fM1BlO+
+C/++NWf2EAhORVAjvJrHNokJp3PTNRJ1WWteHeU9PwfGmWHKVc1IgvRFMH08604I
+ZzX5CcxIg/b56g27A7CBPh/KO/qKTDLFFNGc1T2asvY/P3+PeN6y+leFHStCTu7R
+Bi/l4hczZdnwq3BGT6mnjEN7wau2s7pA067SXimNOkYi5fgwspMHi8fJWmYyBypU
+mQBRzwfm77ECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBvt8v930fQtxR7f7Vcb1Hg
+irq1CtffsBqtKYupYg6IgloiRA6U5wdU0e6faA3Ppsmd4SmNKb9ZavIgnDBfx8MP
+1/IpsNOkg0366bP/zzkAhcXspo7PU8yZIqep//wT4TOFz04N8Lshqm8HUejShFdA
+fB8C0LX5Y/2219ZVMaaEbw==
+-----END CERTIFICATE-----
diff --git a/gio/tests/tls-tests/client-past.pem b/gio/tests/tls-tests/client-past.pem
new file mode 100644
index 0000000..2dbb4d1
--- /dev/null
+++ b/gio/tests/tls-tests/client-past.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAkUCAQswDQYJKoZIhvcNAQEFBQAwgYYxEzARBgoJkiaJk/IsZAEZFgND
+T00xFzAVBgoJkiaJk/IsZAEZFgdFWEFNUExFMR4wHAYDVQQLExVDZXJ0aWZpY2F0
+ZSBBdXRob3JpdHkxFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcN
+AQkBFg5jYUBleGFtcGxlLmNvbTAeFw0wMDAxMTgxNzI3NDdaFw0wMTAxMTcxNzI3
+NDdaMGIxEzARBgoJkiaJk/IsZAEZFgNDT00xFzAVBgoJkiaJk/IsZAEZFgdFWEFN
+UExFMQ8wDQYDVQQDEwZDbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFt
+cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEgNDM/dg3t
+9DHNAPz/b87LSxEaKhoZ8AcNBym3LEOdCnXGEnKf0b9lkT5caXu5GAM84ahTCJ7n
+79RVNrqGKM7jbBdSX+ZUfkqJQPhOXD2+0niYQicH92nz78kxmjlbizvd3fM1BlO+
+C/++NWf2EAhORVAjvJrHNokJp3PTNRJ1WWteHeU9PwfGmWHKVc1IgvRFMH08604I
+ZzX5CcxIg/b56g27A7CBPh/KO/qKTDLFFNGc1T2asvY/P3+PeN6y+leFHStCTu7R
+Bi/l4hczZdnwq3BGT6mnjEN7wau2s7pA067SXimNOkYi5fgwspMHi8fJWmYyBypU
+mQBRzwfm77ECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBC3BOULAOkRFLKLajHIIB2
+VB0tHOFWuflP/LXso3ogGA8ItqbjacqjRHdTGK79etbxSTdi7k8owMVMPavJnBYk
+TraOkf/xxHo2zWy3XES1lniTUfGgKpjYNlALB6K6DJseZorSOmGA4KllL46MYwNu
+jsLO+5HkS/uNxlKo2l+xGw==
+-----END CERTIFICATE-----
diff --git a/gio/tests/tls-tests/client.pem b/gio/tests/tls-tests/client.pem
new file mode 100644
index 0000000..04bc8ac
--- /dev/null
+++ b/gio/tests/tls-tests/client.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAkUCAQkwDQYJKoZIhvcNAQEFBQAwgYYxEzARBgoJkiaJk/IsZAEZFgND
+T00xFzAVBgoJkiaJk/IsZAEZFgdFWEFNUExFMR4wHAYDVQQLExVDZXJ0aWZpY2F0
+ZSBBdXRob3JpdHkxFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcN
+AQkBFg5jYUBleGFtcGxlLmNvbTAeFw0xMTAxMTgwNjA0MTFaFw0yMTAxMTUwNjA0
+MTFaMGIxEzARBgoJkiaJk/IsZAEZFgNDT00xFzAVBgoJkiaJk/IsZAEZFgdFWEFN
+UExFMQ8wDQYDVQQDEwZDbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFt
+cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEgNDM/dg3t
+9DHNAPz/b87LSxEaKhoZ8AcNBym3LEOdCnXGEnKf0b9lkT5caXu5GAM84ahTCJ7n
+79RVNrqGKM7jbBdSX+ZUfkqJQPhOXD2+0niYQicH92nz78kxmjlbizvd3fM1BlO+
+C/++NWf2EAhORVAjvJrHNokJp3PTNRJ1WWteHeU9PwfGmWHKVc1IgvRFMH08604I
+ZzX5CcxIg/b56g27A7CBPh/KO/qKTDLFFNGc1T2asvY/P3+PeN6y+leFHStCTu7R
+Bi/l4hczZdnwq3BGT6mnjEN7wau2s7pA067SXimNOkYi5fgwspMHi8fJWmYyBypU
+mQBRzwfm77ECAwEAATANBgkqhkiG9w0BAQUFAAOBgQA3LuElj2QB9wQvmIxk2Jmb
+IPP2/WS8dwPoCv/N3+6nTx8yRsrILf4QsnEbbsxoYO5jW4r9Kt8m8B/M7YgnBDE9
+zlm7JbXKZf2isSm5TyT627Ymzxrzs5d+7o2eS7SN1DB6PyvRh2ye7EMbyEYD8ULi
+itDUkYkssNCVivYwVvJoMg==
+-----END CERTIFICATE-----
diff --git a/gio/tests/tls-tests/server-and-key.pem b/gio/tests/tls-tests/server-and-key.pem
new file mode 100644
index 0000000..7bf1cff
--- /dev/null
+++ b/gio/tests/tls-tests/server-and-key.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk
+ARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRp
+ZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkq
+hkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTExMDExNzE5NDcxN1oXDTIxMDEx
+NDE5NDcxN1owSzETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkW
+B0VYQU1QTEUxGzAZBgNVBAMTEnNlcnZlci5leGFtcGxlLmNvbTBcMA0GCSqGSIb3
+DQEBAQUAA0sAMEgCQQDYScTxk55XBmbDM9zzwO+grVySE4rudWuzH2PpObIonqbf
+hRoAalKVluG9jvbHI81eXxCdSObv1KBP1sbN5RzpAgMBAAGjIjAgMAkGA1UdEwQC
+MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAYx6fMqT1
+Gvo0jq88E8mc+bmp4LfXD4wJ7KxYeadQxt75HFRpj4FhFO3DOpVRFgzHlOEo3Fwk
+PZOKjvkT0cbcoEq5whLH25dHoQxGoVQgFyAP5s+7Vp5AlHh8Y/vAoXeEVyy/RCIH
+QkhUlAflfDMcrrYjsmwoOPSjhx6Mm/AopX4=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBANhJxPGTnlcGZsMz3PPA76CtXJITiu51a7MfY+k5siiept+FGgBq
+UpWW4b2O9scjzV5fEJ1I5u/UoE/Wxs3lHOkCAwEAAQJAURSWd9lW6ljD/TlcAyS4
+sAtNQJWC55GtJiEGW0/9savXVHPRllN5IlcOJS/L//rD47UzwmGHcxxzsg3p+s51
+YQIhAPaiU+wbUL0cQrxqwIa/TEtNtrU3T21vNvQaFLSHh+uHAiEA4IBuYuPL+xz2
+nDwSB9UWklYV5fKhwqUA96qyMNxTMA8CIGvD6h+Un+bB3nctvgoitFeDEX6FOHN8
+0OpAKyPmxIEpAiEAiwNb1wYhN9QebG3R6GGtQV3m32VXftR3feSHxDOZm0cCIEpA
+7kMFeeQQZb1qYd1PMFSDCG+BkrWh/Fud+VvFAWxI
+-----END RSA PRIVATE KEY-----
diff --git a/gio/tests/tls-tests/server-self.pem b/gio/tests/tls-tests/server-self.pem
new file mode 100644
index 0000000..20b3500
--- /dev/null
+++ b/gio/tests/tls-tests/server-self.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBiDCCATICCQDJ4QeFpYPYljANBgkqhkiG9w0BAQUFADBLMRMwEQYKCZImiZPy
+LGQBGRYDQ09NMRcwFQYKCZImiZPyLGQBGRYHRVhBTVBMRTEbMBkGA1UEAxMSc2Vy
+dmVyLmV4YW1wbGUuY29tMB4XDTExMDExOTAzMTYzOFoXDTIxMDExNjAzMTYzOFow
+SzETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUx
+GzAZBgNVBAMTEnNlcnZlci5leGFtcGxlLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sA
+MEgCQQDYScTxk55XBmbDM9zzwO+grVySE4rudWuzH2PpObIonqbfhRoAalKVluG9
+jvbHI81eXxCdSObv1KBP1sbN5RzpAgMBAAEwDQYJKoZIhvcNAQEFBQADQQAagc2P
+/lCfDwT3max+D2M7++KMDfGqiO3gI+hMarf/jAaQpcKO/9G95AnNo4lTd6W6/7yj
+YYvUupv+0vi4CtQG
+-----END CERTIFICATE-----
diff --git a/gio/tests/tls-tests/server.der b/gio/tests/tls-tests/server.der
new file mode 100644
index 0000000..cf2de65
Binary files /dev/null and b/gio/tests/tls-tests/server.der differ
diff --git a/gio/tests/tls-tests/server.pem b/gio/tests/tls-tests/server.pem
new file mode 100644
index 0000000..d4bd526
--- /dev/null
+++ b/gio/tests/tls-tests/server.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk
+ARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRp
+ZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkq
+hkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTExMDExNzE5NDcxN1oXDTIxMDEx
+NDE5NDcxN1owSzETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkW
+B0VYQU1QTEUxGzAZBgNVBAMTEnNlcnZlci5leGFtcGxlLmNvbTBcMA0GCSqGSIb3
+DQEBAQUAA0sAMEgCQQDYScTxk55XBmbDM9zzwO+grVySE4rudWuzH2PpObIonqbf
+hRoAalKVluG9jvbHI81eXxCdSObv1KBP1sbN5RzpAgMBAAGjIjAgMAkGA1UdEwQC
+MAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADgYEAYx6fMqT1
+Gvo0jq88E8mc+bmp4LfXD4wJ7KxYeadQxt75HFRpj4FhFO3DOpVRFgzHlOEo3Fwk
+PZOKjvkT0cbcoEq5whLH25dHoQxGoVQgFyAP5s+7Vp5AlHh8Y/vAoXeEVyy/RCIH
+QkhUlAflfDMcrrYjsmwoOPSjhx6Mm/AopX4=
+-----END CERTIFICATE-----
diff --git a/gio/tests/tls.c b/gio/tests/tls.c
new file mode 100644
index 0000000..72996c6
--- /dev/null
+++ b/gio/tests/tls.c
@@ -0,0 +1,874 @@
+/* GIO TLS tests
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include <gio/gio.h>
+
+#include <sys/types.h>
+#include <string.h>
+
+/* -----------------------------------------------------------------------------
+ * CONNECTION AND DATABASE TESTS
+ */
+
+#define TEST_DATA "You win again, gravity!\n"
+#define TEST_DATA_LENGTH 24
+
+typedef struct {
+  GMainLoop *loop;
+  GSocketService *service;
+  GTlsDatabase *database;
+  GIOStream *server_connection;
+  GIOStream *client_connection;
+  GSocketConnectable *identity;
+  GSocketAddress *address;
+  GTlsAuthenticationMode auth_mode;
+  GTlsCertificateFlags accept_flags;
+} TestConnection;
+
+static void
+setup_connection (TestConnection *test, gconstpointer data)
+{
+  GInetAddress *inet;
+  guint16 port;
+
+  test->loop = g_main_loop_new (NULL, FALSE);
+
+  test->auth_mode = G_TLS_AUTHENTICATION_NONE;
+
+  /* This is where the server listens and the client connects */
+  port = g_random_int_range (50000, 65000);
+  inet = g_inet_address_new_from_string ("127.0.0.1");
+  test->address = G_SOCKET_ADDRESS (g_inet_socket_address_new (inet, port));
+  g_object_unref (inet);
+
+  /* The identity matches the server certificate */
+  test->identity = g_network_address_new ("server.example.com", port);
+}
+
+static void
+teardown_connection (TestConnection *test, gconstpointer data)
+{
+  if (test->service)
+    g_object_unref (test->service);
+
+  if (test->server_connection)
+    {
+      g_assert (G_IS_TLS_SERVER_CONNECTION (test->server_connection));
+      g_object_unref (test->server_connection);
+      g_assert (!G_IS_TLS_SERVER_CONNECTION (test->server_connection));
+    }
+
+  if (test->client_connection)
+    {
+      g_assert (G_IS_TLS_CLIENT_CONNECTION (test->client_connection));
+      g_object_unref (test->client_connection);
+      g_assert (!G_IS_TLS_SERVER_CONNECTION (test->client_connection));
+    }
+
+  if (test->database)
+    {
+      g_assert (G_IS_TLS_DATABASE (test->database));
+      g_object_unref (test->database);
+      g_assert (!G_IS_TLS_DATABASE (test->database));
+    }
+
+  g_object_unref (test->address);
+  g_object_unref (test->identity);
+  g_main_loop_unref (test->loop);
+}
+
+static gboolean
+on_accept_certificate (GTlsClientConnection *conn, GTlsCertificate *cert,
+                       GTlsCertificateFlags errors, gpointer user_data)
+{
+  TestConnection *test = user_data;
+  return errors == test->accept_flags;
+}
+
+static void
+on_output_close_finish (GObject        *object,
+                        GAsyncResult   *res,
+                        gpointer        user_data)
+{
+  GError *error = NULL;
+  g_output_stream_close_finish (G_OUTPUT_STREAM (object), res, &error);
+  g_assert_no_error (error);
+}
+
+static void
+on_output_write_finish (GObject        *object,
+                        GAsyncResult   *res,
+                        gpointer        user_data)
+{
+  TestConnection *test = user_data;
+  GError *error = NULL;
+  g_output_stream_write_finish (G_OUTPUT_STREAM (object), res, &error);
+  g_assert_no_error (error);
+
+  g_output_stream_close_async (G_OUTPUT_STREAM (object), G_PRIORITY_DEFAULT, NULL,
+                               on_output_close_finish, test);
+}
+
+static gboolean
+on_incoming_connection (GSocketService     *service,
+                        GSocketConnection  *connection,
+                        GObject            *source_object,
+                        gpointer            user_data)
+{
+  TestConnection *test = user_data;
+  GOutputStream *stream;
+  GTlsCertificate *cert;
+  GError *error = NULL;
+  gchar *path;
+
+  path = g_build_filename (SRCDIR, "tls-tests", "server-and-key.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_free (path);
+
+  test->server_connection = g_tls_server_connection_new (G_IO_STREAM (connection),
+                                                         cert, &error);
+  g_assert_no_error (error);
+  g_object_unref (cert);
+
+  g_object_set (test->server_connection, "authentication-mode", test->auth_mode, NULL);
+  g_signal_connect (test->server_connection, "accept-certificate",
+                    G_CALLBACK (on_accept_certificate), test);
+
+  if (test->database)
+    g_tls_connection_set_database (G_TLS_CONNECTION (test->server_connection), test->database);
+
+  stream = g_io_stream_get_output_stream (test->server_connection);
+
+  g_output_stream_write_async (stream, TEST_DATA, TEST_DATA_LENGTH,
+                               G_PRIORITY_DEFAULT, NULL,
+                               on_output_write_finish, test);
+  return FALSE;
+}
+
+static void
+start_server_service (TestConnection *test, GTlsAuthenticationMode auth_mode)
+{
+  GError *error = NULL;
+
+  test->service = g_socket_service_new ();
+  g_socket_listener_add_address (G_SOCKET_LISTENER (test->service),
+                                 G_SOCKET_ADDRESS (test->address),
+                                 G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP,
+                                 NULL, NULL, &error);
+  g_assert_no_error (error);
+
+  test->auth_mode = auth_mode;
+  g_signal_connect (test->service, "incoming", G_CALLBACK (on_incoming_connection), test);
+}
+
+static GIOStream*
+start_server_and_connect_to_it (TestConnection *test, GTlsAuthenticationMode auth_mode)
+{
+  GSocketClient *client;
+  GError *error = NULL;
+  GSocketConnection *connection;
+
+  start_server_service (test, auth_mode);
+
+  client = g_socket_client_new ();
+  connection = g_socket_client_connect (client, G_SOCKET_CONNECTABLE (test->address),
+                                        NULL, &error);
+  g_assert_no_error (error);
+  g_object_unref (client);
+
+  return G_IO_STREAM (connection);
+}
+
+static void
+on_input_read_finish (GObject        *object,
+                      GAsyncResult   *res,
+                      gpointer        user_data)
+{
+  TestConnection *test = user_data;
+  GError *error = NULL;
+  gchar *line, *check;
+
+  line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (object), res,
+                                               NULL, &error);
+  g_assert_no_error (error);
+  g_assert (line);
+
+  check = g_strdup (TEST_DATA);
+  g_strstrip (check);
+  g_assert_cmpstr (line, ==, check);
+  g_free (check);
+  g_free (line);
+
+  g_main_loop_quit (test->loop);
+}
+
+static void
+read_test_data_async (TestConnection *test)
+{
+  GDataInputStream *stream;
+
+  stream = g_data_input_stream_new (g_io_stream_get_input_stream (test->client_connection));
+  g_assert (stream);
+
+  g_data_input_stream_read_line_async (stream, G_PRIORITY_DEFAULT, NULL,
+                                       on_input_read_finish, test);
+  g_object_unref (stream);
+}
+
+static void
+test_basic_connection (TestConnection *test,
+                       gconstpointer   data)
+{
+  GIOStream *connection;
+  GError *error = NULL;
+
+  connection = start_server_and_connect_to_it (test, G_TLS_AUTHENTICATION_NONE);
+  test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+  g_assert_no_error (error);
+  g_object_unref (connection);
+
+  /* No validation at all in this test */
+  g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+                                                0);
+
+  read_test_data_async (test);
+  g_main_loop_run (test->loop);
+}
+
+static void
+test_verified_connection (TestConnection *test,
+                          gconstpointer   data)
+{
+  GIOStream *connection;
+  GError *error = NULL;
+  gchar *path;
+
+  path = g_build_filename (SRCDIR, "tls-tests", "ca-roots.pem", NULL);
+  test->database = g_tls_file_database_new (path, &error);
+  g_assert_no_error (error);
+  g_assert (test->database);
+  g_free (path);
+
+  connection = start_server_and_connect_to_it (test, G_TLS_AUTHENTICATION_NONE);
+  test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+  g_assert_no_error (error);
+  g_assert (test->client_connection);
+
+  g_tls_connection_set_database (G_TLS_CONNECTION (test->client_connection), test->database);
+
+  /* All validation in this test */
+  g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+                                                G_TLS_CERTIFICATE_VALIDATE_ALL);
+
+  read_test_data_async (test);
+  g_main_loop_run (test->loop);
+}
+
+static void
+test_client_auth_connection (TestConnection *test,
+                             gconstpointer   data)
+{
+  GIOStream *connection;
+  GError *error = NULL;
+  GTlsCertificate *cert;
+  gchar *path;
+
+  path = g_build_filename (SRCDIR, "tls-tests", "ca-roots.pem", NULL);
+  test->database = g_tls_file_database_new (path, &error);
+  g_assert_no_error (error);
+  g_assert (test->database);
+  g_free (path);
+
+  connection = start_server_and_connect_to_it (test, G_TLS_AUTHENTICATION_REQUIRED);
+  test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+  g_assert_no_error (error);
+  g_assert (test->client_connection);
+
+  g_tls_connection_set_database (G_TLS_CONNECTION (test->client_connection), test->database);
+
+  path = g_build_filename (SRCDIR, "tls-tests", "client-and-key.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_free (path);
+
+  g_tls_connection_set_certificate (G_TLS_CONNECTION (test->client_connection), cert);
+  g_object_unref (cert);
+
+  /* All validation in this test */
+  g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+                                                G_TLS_CERTIFICATE_VALIDATE_ALL);
+
+  read_test_data_async (test);
+  g_main_loop_run (test->loop);
+}
+
+static void
+test_connection_no_database (TestConnection *test,
+                             gconstpointer   data)
+{
+  GIOStream *connection;
+  GError *error = NULL;
+
+  connection = start_server_and_connect_to_it (test, G_TLS_AUTHENTICATION_NONE);
+  test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+  g_assert_no_error (error);
+  g_assert (test->client_connection);
+
+  /* Overrides loading of the default database */
+  g_tls_connection_set_database (G_TLS_CONNECTION (test->client_connection), NULL);
+
+  /* All validation in this test */
+  g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+                                                G_TLS_CERTIFICATE_VALIDATE_ALL);
+
+  test->accept_flags = G_TLS_CERTIFICATE_UNKNOWN_CA;
+  g_signal_connect (test->client_connection, "accept-certificate",
+                    G_CALLBACK (on_accept_certificate), test);
+
+  read_test_data_async (test);
+  g_main_loop_run (test->loop);
+}
+
+/* -----------------------------------------------------------------------------
+ * CERTIFICATE TESTS
+ */
+
+typedef struct {
+  gchar *pem;
+  gsize pem_length;
+  GByteArray *der;
+} TestCertificate;
+
+static void
+setup_certificate (TestCertificate *test, gconstpointer data)
+{
+  GError *error = NULL;
+  gchar *path;
+  gchar *contents;
+  gsize length;
+
+  path = g_build_filename (SRCDIR, "tls-tests", "server.pem", NULL);
+  g_file_get_contents (path, &test->pem, &test->pem_length, &error);
+  g_assert_no_error (error);
+  g_free (path);
+
+  path = g_build_filename (SRCDIR, "tls-tests", "server.der", NULL);
+  g_file_get_contents (path, &contents, &length, &error);
+  g_assert_no_error (error);
+  g_free (path);
+
+  test->der = g_byte_array_new ();
+  g_byte_array_append (test->der, (guint8*)contents, length);
+  g_free (contents);
+}
+
+static void
+teardown_certificate (TestCertificate *test, gconstpointer data)
+{
+  g_free (test->pem);
+  g_byte_array_free (test->der, TRUE);
+}
+
+static void
+test_create_destroy_certificate_pem (TestCertificate *test, gconstpointer data)
+{
+  GTlsCertificate *cert;
+  gchar *pem = NULL;
+  GError *error = NULL;
+
+  cert = g_tls_certificate_new_from_pem (test->pem, test->pem_length, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+
+  g_object_get (cert, "certificate-pem", &pem, NULL);
+  g_assert_cmpstr (pem, ==, test->pem);
+  g_free (pem);
+
+  g_object_unref (cert);
+  g_assert (!G_IS_TLS_CERTIFICATE (cert));
+}
+
+static void
+test_create_destroy_certificate_der (TestCertificate *test, gconstpointer data)
+{
+  GTlsCertificate *cert;
+  GByteArray *der = NULL;
+  GError *error = NULL;
+  GTlsBackend *backend;
+
+  backend = g_tls_backend_get_default ();
+  cert = g_initable_new (g_tls_backend_get_certificate_type (backend),
+                         NULL, &error,
+                         "certificate", test->der,
+                         NULL);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+
+  g_object_get (cert, "certificate", &der, NULL);
+  g_assert (der);
+  g_assert_cmpuint (der->len, ==, test->der->len);
+  g_assert (memcmp (der->data, test->der->data, der->len) == 0);
+  g_byte_array_unref (der);
+
+  g_object_unref (cert);
+  g_assert (!G_IS_TLS_CERTIFICATE (cert));
+}
+
+static void
+test_create_certificate_with_issuer (TestCertificate   *test,
+                                     gconstpointer      data)
+{
+  GTlsCertificate *cert, *issuer, *check;
+  GError *error = NULL;
+  GTlsBackend *backend;
+  gchar *path;
+
+  path = g_build_filename (SRCDIR, "tls-tests", "ca.pem", NULL);
+  issuer = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (issuer));
+  g_free (path);
+
+  backend = g_tls_backend_get_default ();
+  cert = g_initable_new (g_tls_backend_get_certificate_type (backend),
+                         NULL, &error,
+                         "certificate-pem", test->pem,
+                         "issuer", issuer,
+                         NULL);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+
+  g_object_unref (issuer);
+  g_assert (G_IS_TLS_CERTIFICATE (issuer));
+
+  check = g_tls_certificate_get_issuer (cert);
+  g_assert (check == issuer);
+
+  g_object_unref (cert);
+  g_assert (!G_IS_TLS_CERTIFICATE (cert));
+  g_assert (!G_IS_TLS_CERTIFICATE (issuer));
+}
+
+/* -----------------------------------------------------------------------------
+ * CERTIFICATE VERIFY
+ */
+
+typedef struct {
+  GTlsCertificate *cert;
+  GTlsCertificate *anchor;
+  GSocketConnectable *identity;
+  GTlsDatabase *database;
+} TestVerify;
+
+static void
+setup_verify (TestVerify     *test,
+              gconstpointer   data)
+{
+  GError *error = NULL;
+  gchar *path;
+
+  path = g_build_filename (SRCDIR, "tls-tests", "server.pem", NULL);
+  test->cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (test->cert));
+  g_free (path);
+
+  test->identity = g_network_address_new ("server.example.com", 80);
+
+  path = g_build_filename (SRCDIR, "tls-tests", "ca.pem", NULL);
+  test->anchor = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (test->anchor));
+  test->database = g_tls_file_database_new (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_DATABASE (test->database));
+  g_free (path);
+}
+
+static void
+teardown_verify (TestVerify      *test,
+                 gconstpointer    data)
+{
+  g_assert (G_IS_TLS_CERTIFICATE (test->cert));
+  g_object_unref (test->cert);
+  g_assert (!G_IS_TLS_CERTIFICATE (test->cert));
+
+  g_assert (G_IS_TLS_CERTIFICATE (test->anchor));
+  g_object_unref (test->anchor);
+  g_assert (!G_IS_TLS_CERTIFICATE (test->anchor));
+
+  g_assert (G_IS_TLS_DATABASE (test->database));
+  g_object_unref (test->database);
+  g_assert (!G_IS_TLS_DATABASE (test->database));
+}
+
+static void
+test_verify_certificate_good (TestVerify      *test,
+                              gconstpointer    data)
+{
+  GTlsCertificateFlags errors;
+
+  errors = g_tls_certificate_verify (test->cert, test->identity, test->anchor);
+  g_assert_cmpuint (errors, ==, 0);
+
+  errors = g_tls_certificate_verify (test->cert, NULL, test->anchor);
+  g_assert_cmpuint (errors, ==, 0);
+}
+
+static void
+test_verify_certificate_bad_identity (TestVerify      *test,
+                                      gconstpointer    data)
+{
+  GSocketConnectable *identity;
+  GTlsCertificateFlags errors;
+
+  identity = g_network_address_new ("other.example.com", 80);
+
+  errors = g_tls_certificate_verify (test->cert, identity, test->anchor);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_BAD_IDENTITY);
+
+  g_object_unref (identity);
+}
+
+static void
+test_verify_certificate_bad_ca (TestVerify      *test,
+                                gconstpointer    data)
+{
+  GTlsCertificateFlags errors;
+  GTlsCertificate *cert;
+  GError *error = NULL;
+  gchar *path;
+
+  /* Use a client certificate as the CA, which is wrong */
+  path = g_build_filename (SRCDIR, "tls-tests", "client.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+  g_free (path);
+
+  errors = g_tls_certificate_verify (test->cert, test->identity, cert);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_UNKNOWN_CA);
+
+  g_object_unref (cert);
+}
+
+static void
+test_verify_certificate_bad_before (TestVerify      *test,
+                                    gconstpointer    data)
+{
+  GTlsCertificateFlags errors;
+  GTlsCertificate *cert;
+  GError *error = NULL;
+  gchar *path;
+
+  /* This is a certificate in the future */
+  path = g_build_filename (SRCDIR, "tls-tests", "client-future.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+  g_free (path);
+
+  errors = g_tls_certificate_verify (cert, NULL, test->anchor);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_NOT_ACTIVATED);
+
+  g_object_unref (cert);
+}
+
+static void
+test_verify_certificate_bad_expired (TestVerify      *test,
+                                     gconstpointer    data)
+{
+  GTlsCertificateFlags errors;
+  GTlsCertificate *cert;
+  GError *error = NULL;
+  gchar *path;
+
+  /* This is a certificate in the future */
+  path = g_build_filename (SRCDIR, "tls-tests", "client-past.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+  g_free (path);
+
+  errors = g_tls_certificate_verify (cert, NULL, test->anchor);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_EXPIRED);
+
+  g_object_unref (cert);
+}
+
+static void
+test_verify_certificate_bad_combo (TestVerify      *test,
+                                   gconstpointer    data)
+{
+  GTlsCertificate *cert;
+  GSocketConnectable *identity;
+  GTlsCertificateFlags errors;
+  GError *error = NULL;
+  gchar *path;
+
+  path = g_build_filename (SRCDIR, "tls-tests", "client-past.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+  g_free (path);
+
+  /*
+   * - Use certificate as its own CA, not selfsigned, so unknown CA
+   * - Use wrong identity.
+   * - Use expired certificate.
+   */
+
+  identity = g_network_address_new ("other.example.com", 80);
+
+  errors = g_tls_certificate_verify (cert, identity, cert);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_UNKNOWN_CA |
+                    G_TLS_CERTIFICATE_BAD_IDENTITY | G_TLS_CERTIFICATE_EXPIRED);
+
+  g_object_unref (cert);
+  g_object_unref (identity);
+}
+
+static void
+test_verify_database_good (TestVerify      *test,
+                           gconstpointer    data)
+{
+  GTlsCertificateFlags errors;
+  GError *error = NULL;
+
+  errors = g_tls_database_verify_chain (test->database, test->cert,
+                                        G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
+                                        test->identity, NULL, 0, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpuint (errors, ==, 0);
+
+  errors = g_tls_database_verify_chain (test->database, test->cert,
+                                        G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
+                                        NULL, NULL, 0, NULL, &error);
+  g_assert_cmpuint (errors, ==, 0);
+}
+
+static void
+test_verify_database_bad_identity (TestVerify      *test,
+                                   gconstpointer    data)
+{
+  GSocketConnectable *identity;
+  GTlsCertificateFlags errors;
+  GError *error = NULL;
+
+  identity = g_network_address_new ("other.example.com", 80);
+
+  errors = g_tls_database_verify_chain (test->database, test->cert,
+                                        G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
+                                        identity, NULL, 0, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_BAD_IDENTITY);
+
+  g_object_unref (identity);
+}
+
+static void
+test_verify_database_bad_ca (TestVerify      *test,
+                             gconstpointer    data)
+{
+  GTlsCertificateFlags errors;
+  GTlsCertificate *cert;
+  GError *error = NULL;
+  gchar *path;
+
+  /* Use another certificate which isn't in our CA list */
+  path = g_build_filename (SRCDIR, "tls-tests", "server-self.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+  g_free (path);
+
+  errors = g_tls_database_verify_chain (test->database, cert,
+                                        G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
+                                        test->identity, NULL, 0, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_UNKNOWN_CA);
+
+  g_object_unref (cert);
+}
+
+static void
+test_verify_database_bad_before (TestVerify      *test,
+                                 gconstpointer    data)
+{
+  GTlsCertificateFlags errors;
+  GTlsCertificate *cert;
+  GError *error = NULL;
+  gchar *path;
+
+  /* This is a certificate in the future */
+  path = g_build_filename (SRCDIR, "tls-tests", "client-future.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+  g_free (path);
+
+  errors = g_tls_database_verify_chain (test->database, cert,
+                                        G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
+                                        NULL, NULL, 0, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_NOT_ACTIVATED);
+
+  g_object_unref (cert);
+}
+
+static void
+test_verify_database_bad_expired (TestVerify      *test,
+                                  gconstpointer    data)
+{
+  GTlsCertificateFlags errors;
+  GTlsCertificate *cert;
+  GError *error = NULL;
+  gchar *path;
+
+  /* This is a certificate in the future */
+  path = g_build_filename (SRCDIR, "tls-tests", "client-past.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+  g_free (path);
+
+  errors = g_tls_database_verify_chain (test->database, cert,
+                                        G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
+                                        NULL, NULL, 0, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_EXPIRED);
+
+  g_object_unref (cert);
+}
+
+static void
+test_verify_database_bad_combo (TestVerify      *test,
+                                gconstpointer    data)
+{
+  GTlsCertificate *cert;
+  GSocketConnectable *identity;
+  GTlsCertificateFlags errors;
+  GError *error = NULL;
+  gchar *path;
+
+  path = g_build_filename (SRCDIR, "tls-tests", "server-self.pem", NULL);
+  cert = g_tls_certificate_new_from_file (path, &error);
+  g_assert_no_error (error);
+  g_assert (G_IS_TLS_CERTIFICATE (cert));
+  g_free (path);
+
+  /*
+   * - Use is self signed
+   * - Use wrong identity.
+   */
+
+  identity = g_network_address_new ("other.example.com", 80);
+
+  errors = g_tls_database_verify_chain (test->database, cert,
+                                        G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
+                                        identity, NULL, 0, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_cmpuint (errors, ==, G_TLS_CERTIFICATE_UNKNOWN_CA |
+                    G_TLS_CERTIFICATE_BAD_IDENTITY);
+
+  g_object_unref (cert);
+  g_object_unref (identity);
+}
+
+/* -----------------------------------------------------------------------------
+ * BACKEND
+ */
+
+static void
+test_default_database_is_singleton (void)
+{
+  GTlsBackend *backend;
+  GTlsDatabase *database;
+  GTlsDatabase *check;
+
+  backend = g_tls_backend_get_default ();
+  g_assert (G_IS_TLS_BACKEND (backend));
+
+  database = g_tls_backend_get_default_database (backend);
+  g_assert (G_IS_TLS_DATABASE (database));
+
+  check = g_tls_backend_get_default_database (backend);
+  g_assert (database == check);
+
+  g_object_unref (database);
+  g_object_unref (check);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  g_type_init ();
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add ("/tls/connection/basic", TestConnection, NULL,
+              setup_connection, test_basic_connection, teardown_connection);
+  g_test_add ("/tls/connection/verified", TestConnection, NULL,
+              setup_connection, test_verified_connection, teardown_connection);
+  g_test_add ("/tls/connection/client-auth", TestConnection, NULL,
+              setup_connection, test_client_auth_connection, teardown_connection);
+  g_test_add ("/tls/connection/no-database", TestConnection, NULL,
+              setup_connection, test_connection_no_database, teardown_connection);
+
+  g_test_add_func ("/tls/backend/default-database-is-singleton",
+                   test_default_database_is_singleton);
+
+  g_test_add ("/tls/certificate/create-destroy-pem", TestCertificate, NULL,
+              setup_certificate, test_create_destroy_certificate_pem, teardown_certificate);
+  g_test_add ("/tls/certificate/create-destroy-der", TestCertificate, NULL,
+              setup_certificate, test_create_destroy_certificate_der, teardown_certificate);
+  g_test_add ("/tls/certificate/create-with-issuer", TestCertificate, NULL,
+              setup_certificate, test_create_certificate_with_issuer, teardown_certificate);
+
+  g_test_add ("/tls/certificate/verify-good", TestVerify, NULL,
+              setup_verify, test_verify_certificate_good, teardown_verify);
+  g_test_add ("/tls/certificate/verify-bad-identity", TestVerify, NULL,
+              setup_verify, test_verify_certificate_bad_identity, teardown_verify);
+  g_test_add ("/tls/certificate/verify-bad-ca", TestVerify, NULL,
+              setup_verify, test_verify_certificate_bad_ca, teardown_verify);
+  g_test_add ("/tls/certificate/verify-bad-before", TestVerify, NULL,
+              setup_verify, test_verify_certificate_bad_before, teardown_verify);
+  g_test_add ("/tls/certificate/verify-bad-expired", TestVerify, NULL,
+              setup_verify, test_verify_certificate_bad_expired, teardown_verify);
+  g_test_add ("/tls/certificate/verify-bad-combo", TestVerify, NULL,
+              setup_verify, test_verify_certificate_bad_combo, teardown_verify);
+  g_test_add ("/tls/database/verify-good", TestVerify, NULL,
+              setup_verify, test_verify_database_good, teardown_verify);
+  g_test_add ("/tls/database/verify-bad-identity", TestVerify, NULL,
+              setup_verify, test_verify_database_bad_identity, teardown_verify);
+  g_test_add ("/tls/database/verify-bad-ca", TestVerify, NULL,
+              setup_verify, test_verify_database_bad_ca, teardown_verify);
+  g_test_add ("/tls/database/verify-bad-before", TestVerify, NULL,
+              setup_verify, test_verify_database_bad_before, teardown_verify);
+  g_test_add ("/tls/database/verify-bad-expired", TestVerify, NULL,
+              setup_verify, test_verify_database_bad_expired, teardown_verify);
+  g_test_add ("/tls/database/verify-bad-combo", TestVerify, NULL,
+              setup_verify, test_verify_database_bad_combo, teardown_verify);
+
+  return g_test_run();
+}
