[glib-networking/nss] nss: the start of an NSS-based GTlsBackend



commit b0231a6a9f8de5e832e895e1e30d865d866b5822
Author: Dan Winship <danw gnome org>
Date:   Thu Sep 29 10:54:00 2011 -0400

    nss: the start of an NSS-based GTlsBackend
    
    At the moment it passes tls/tests/certificate, meaning
    GTlsCertificate, GTlsDatabase, and GTlsFileDatabase are more or less
    working (though without any support for private keys or PKCS#11
    callbacks). GTlsConnection and associated classes are just stubs right
    now though.

 .gitignore                         |    4 +-
 Makefile.am                        |    4 +
 configure.ac                       |   22 ++-
 tls/nss/Makefile.am                |   33 ++
 tls/nss/gtlsbackend-nss.c          |  111 +++++++
 tls/nss/gtlsbackend-nss.h          |   52 +++
 tls/nss/gtlscertificate-nss.c      |  621 ++++++++++++++++++++++++++++++++++++
 tls/nss/gtlscertificate-nss.h      |   61 ++++
 tls/nss/gtlsclientconnection-nss.c |  162 ++++++++++
 tls/nss/gtlsclientconnection-nss.h |   46 +++
 tls/nss/gtlsconnection-nss.c       |  365 +++++++++++++++++++++
 tls/nss/gtlsconnection-nss.h       |   48 +++
 tls/nss/gtlsdatabase-nss.c         |  283 ++++++++++++++++
 tls/nss/gtlsdatabase-nss.h         |   60 ++++
 tls/nss/gtlsfiledatabase-nss.c     |  318 ++++++++++++++++++
 tls/nss/gtlsfiledatabase-nss.h     |   51 +++
 tls/nss/gtlsinputstream-nss.c      |  147 +++++++++
 tls/nss/gtlsinputstream-nss.h      |   48 +++
 tls/nss/gtlsoutputstream-nss.c     |  147 +++++++++
 tls/nss/gtlsoutputstream-nss.h     |   48 +++
 tls/nss/gtlsserverconnection-nss.c |  105 ++++++
 tls/nss/gtlsserverconnection-nss.h |   47 +++
 tls/nss/nss-module.c               |   47 +++
 tls/tests/Makefile.am              |   20 +-
 tls/tests/certificate.c            |   34 ++-
 tls/tests/connection.c             |    5 +-
 26 files changed, 2871 insertions(+), 18 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 8806e90..e71bdbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,5 +34,5 @@ proxy/libproxy/glib-pacrunner
 proxy/libproxy/org.gtk.GLib.PACRunner.service
 proxy/tests/gnome
 
-/tls/tests/certificate
-/tls/tests/connection
+/tls/tests/certificate-*
+/tls/tests/connection-*
diff --git a/Makefile.am b/Makefile.am
index 0a55026..71d5116 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -19,6 +19,10 @@ if HAVE_GNUTLS
 SUBDIRS += tls/gnutls
 endif
 
+if HAVE_NSS
+SUBDIRS += tls/nss
+endif
+
 SUBDIRS += tls/tests
 
 install-exec-hook:
diff --git a/configure.ac b/configure.ac
index b7833d4..02316b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -124,6 +124,25 @@ if test "x$with_gnutls" = "xyes"; then
     fi
 fi
 
+dnl **********************
+dnl *** Checks for NSS ***
+dnl **********************
+
+AC_ARG_WITH(nss,
+    [AC_HELP_STRING([--with-nss],
+                    [support for NSS @<:@default=check@:>@])],
+    [],
+    [with_nss=check])
+AS_IF([test "$with_nss" != "no"],
+      [PKG_CHECK_MODULES(NSS, [nss],
+         [with_nss=yes
+	  tls_support="nss $tls_support"],
+         [AS_IF([test "x$with_nss" = "xyes"],
+	 	[AC_MSG_FAILURE("$NSS_PKG_ERRORS")])])])
+AM_CONDITIONAL(HAVE_NSS, [test "$with_nss" = "yes"])
+AC_SUBST(NSS_CFLAGS)
+AC_SUBST(NSS_LIBS)
+
 dnl *************************************
 dnl *** Warnings to show if using GCC ***
 dnl *************************************
@@ -220,6 +239,7 @@ AC_CONFIG_FILES([Makefile
                  proxy/gnome/Makefile
                  proxy/tests/Makefile
                  tls/gnutls/Makefile
+                 tls/nss/Makefile
                  tls/tests/Makefile
                 ])
 AC_OUTPUT
@@ -227,7 +247,7 @@ AC_OUTPUT
 echo ""
 echo "  Proxy support: ${proxy_support:-no}"
 echo "  TLS support:   ${tls_support:-no}"
-if test "$tls_support" != "no"; then
+if test "$with_gnutls" = "yes"; then
     echo "  TLS CA file:   ${with_ca_certificates:-(none)}"
     if test -n "$with_ca_certificates"; then
 	if ! test -f "$with_ca_certificates"; then
diff --git a/tls/nss/Makefile.am b/tls/nss/Makefile.am
new file mode 100644
index 0000000..26ab41d
--- /dev/null
+++ b/tls/nss/Makefile.am
@@ -0,0 +1,33 @@
+include $(top_srcdir)/Makefile.decl
+
+giomodule_LTLIBRARIES = libgionss.la
+
+libgionss_la_SOURCES =			\
+	nss-module.c			\
+	gtlsbackend-nss.c		\
+	gtlsbackend-nss.h		\
+	gtlscertificate-nss.c		\
+	gtlscertificate-nss.h		\
+	gtlsclientconnection-nss.c	\
+	gtlsclientconnection-nss.h	\
+	gtlsconnection-nss.c		\
+	gtlsconnection-nss.h		\
+	gtlsdatabase-nss.c		\
+	gtlsdatabase-nss.h		\
+	gtlsfiledatabase-nss.c		\
+	gtlsfiledatabase-nss.h		\
+	gtlsinputstream-nss.c		\
+	gtlsinputstream-nss.h		\
+	gtlsoutputstream-nss.c		\
+	gtlsoutputstream-nss.h		\
+	gtlsserverconnection-nss.c	\
+	gtlsserverconnection-nss.h	\
+	$(NULL)
+
+INCLUDES += $(NSS_CFLAGS)
+
+libgionss_la_LDFLAGS = $(module_flags)
+libgionss_la_LIBADD =			\
+	$(GLIB_LIBS)			\
+	$(NSS_LIBS)			\
+	$(NULL)
diff --git a/tls/nss/gtlsbackend-nss.c b/tls/nss/gtlsbackend-nss.c
new file mode 100644
index 0000000..47157fd
--- /dev/null
+++ b/tls/nss/gtlsbackend-nss.c
@@ -0,0 +1,111 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "glib.h"
+
+#include <errno.h>
+
+#include <nss.h>
+
+#include "gtlsbackend-nss.h"
+#include "gtlscertificate-nss.h"
+#include "gtlsclientconnection-nss.h"
+#include "gtlsfiledatabase-nss.h"
+#include "gtlsserverconnection-nss.h"
+
+GTlsDatabaseNss *g_tls_backend_nss_default_database;
+CERTCertDBHandle *g_tls_backend_nss_certdbhandle;
+
+struct _GTlsBackendNssPrivate
+{
+  NSSInitContext *context;
+};
+
+static void g_tls_backend_nss_interface_init (GTlsBackendInterface *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendNss, g_tls_backend_nss, G_TYPE_OBJECT, 0,
+				G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
+							       g_tls_backend_nss_interface_init);)
+
+static void
+g_tls_backend_nss_init (GTlsBackendNss *backend)
+{
+  backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, G_TYPE_TLS_BACKEND_NSS, GTlsBackendNssPrivate);
+
+  backend->priv->context = NSS_InitContext ("sql:/etc/pki/nssdb", "", "",
+					    SECMOD_DB, NULL, 0);
+
+  g_tls_backend_nss_certdbhandle = CERT_GetDefaultCertDB ();
+  if (!g_tls_backend_nss_default_database)
+    g_tls_backend_nss_default_database = g_object_new (G_TYPE_TLS_DATABASE_NSS, NULL);
+}
+
+static void
+g_tls_backend_nss_finalize (GObject *object)
+{
+  GTlsBackendNss *backend = G_TLS_BACKEND_NSS (object);
+
+  if (backend->priv->context)
+    NSS_ShutdownContext (backend->priv->context);
+
+  G_OBJECT_CLASS (g_tls_backend_nss_parent_class)->finalize (object);
+}
+
+static void
+g_tls_backend_nss_class_init (GTlsBackendNssClass *backend_class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
+
+  g_type_class_add_private (backend_class, sizeof (GTlsBackendNssPrivate));
+
+  gobject_class->finalize = g_tls_backend_nss_finalize;
+}
+
+static void
+g_tls_backend_nss_class_finalize (GTlsBackendNssClass *backend_class)
+{
+}
+
+static GTlsDatabase *
+g_tls_backend_nss_get_default_database (GTlsBackend *backend)
+{
+  return g_object_ref (g_tls_backend_nss_default_database);
+}
+
+static void
+g_tls_backend_nss_interface_init (GTlsBackendInterface *iface)
+{
+  iface->get_certificate_type       = g_tls_certificate_nss_get_type;
+  iface->get_client_connection_type = g_tls_client_connection_nss_get_type;
+  iface->get_server_connection_type = g_tls_server_connection_nss_get_type;
+  iface->get_file_database_type     = g_tls_file_database_nss_get_type;
+  iface->get_default_database       = g_tls_backend_nss_get_default_database;
+}
+
+void
+g_tls_backend_nss_register (GIOModule *module)
+{
+  g_tls_backend_nss_register_type (G_TYPE_MODULE (module));
+  g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
+				  g_tls_backend_nss_get_type(),
+				  "nss",
+				  0);
+}
diff --git a/tls/nss/gtlsbackend-nss.h b/tls/nss/gtlsbackend-nss.h
new file mode 100644
index 0000000..450cacf
--- /dev/null
+++ b/tls/nss/gtlsbackend-nss.h
@@ -0,0 +1,52 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_BACKEND_NSS_H__
+#define __G_TLS_BACKEND_NSS_H__
+
+#include <gio/gio.h>
+
+#include "gtlsdatabase-nss.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_BACKEND_NSS            (g_tls_backend_nss_get_type ())
+#define G_TLS_BACKEND_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_BACKEND_NSS, GTlsBackendNss))
+#define G_TLS_BACKEND_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_BACKEND_NSS, GTlsBackendNssClass))
+#define G_IS_TLS_BACKEND_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_BACKEND_NSS))
+#define G_IS_TLS_BACKEND_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_BACKEND_NSS))
+#define G_TLS_BACKEND_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_BACKEND_NSS, GTlsBackendNssClass))
+
+typedef struct _GTlsBackendNss        GTlsBackendNss;
+typedef struct _GTlsBackendNssClass   GTlsBackendNssClass;
+typedef struct _GTlsBackendNssPrivate GTlsBackendNssPrivate;
+
+struct _GTlsBackendNssClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GTlsBackendNss
+{
+  GObject parent_instance;
+  GTlsBackendNssPrivate *priv;
+};
+
+GType g_tls_backend_nss_get_type (void) G_GNUC_CONST;
+void  g_tls_backend_nss_register (GIOModule *module);
+
+extern GTlsDatabaseNss *g_tls_backend_nss_default_database;
+extern CERTCertDBHandle *g_tls_backend_nss_certdbhandle;
+
+G_END_DECLS
+
+#endif /* __G_TLS_BACKEND_NSS_H___ */
diff --git a/tls/nss/gtlscertificate-nss.c b/tls/nss/gtlscertificate-nss.c
new file mode 100644
index 0000000..71c1847
--- /dev/null
+++ b/tls/nss/gtlscertificate-nss.c
@@ -0,0 +1,621 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "glib.h"
+
+#include <nss.h>
+#include <cert.h>
+#include <keyhi.h>
+#include <secerr.h>
+
+#include "gtlscertificate-nss.h"
+#include "gtlsbackend-nss.h"
+#include "gtlsdatabase-nss.h"
+#include "gtlsfiledatabase-nss.h"
+#include <glib/gi18n-lib.h>
+
+static void     g_tls_certificate_nss_initable_iface_init (GInitableIface  *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsCertificateNss, g_tls_certificate_nss, G_TYPE_TLS_CERTIFICATE,
+			 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+						g_tls_certificate_nss_initable_iface_init);)
+
+enum
+{
+  PROP_0,
+
+  PROP_CERTIFICATE,
+  PROP_CERTIFICATE_PEM,
+  PROP_PRIVATE_KEY,
+  PROP_PRIVATE_KEY_PEM,
+  PROP_ISSUER
+};
+
+struct _GTlsCertificateNssPrivate
+{
+  CERTCertificate *cert;
+  SECKEYPrivateKey *key;
+  gboolean need_private_key;
+
+  GTlsCertificateNss *issuer;
+  gboolean expanded;
+
+  GError *construct_error;
+};
+
+static GObject *
+g_tls_certificate_nss_constructor (GType                  type,
+				   guint                  n_construct_properties,
+				   GObjectConstructParam *construct_properties)
+{
+  GObject *obj;
+  GTlsCertificateNss *nss, *existing;
+
+  obj = G_OBJECT_CLASS (g_tls_certificate_nss_parent_class)->constructor (type, n_construct_properties, construct_properties);
+  nss = G_TLS_CERTIFICATE_NSS (obj);
+
+  /* If it's invalid, return it as-is */
+  if (nss->priv->construct_error || !nss->priv->cert)
+    return obj;
+
+  /* If we already have a GTlsCertificate for this CERTCertificate,
+   * return that instead.
+   */
+  existing = g_tls_database_nss_get_gcert (g_tls_backend_nss_default_database,
+					   nss->priv->cert, FALSE);
+  if (existing)
+    {
+      if (nss->priv->cert)
+	{
+	  CERT_DestroyCertificate (nss->priv->cert);
+	  nss->priv->cert = NULL;
+	}
+      if (nss->priv->key && !existing->priv->key)
+	{
+	  existing->priv->key = nss->priv->key;
+	  nss->priv->key = NULL;
+	}
+      if (nss->priv->issuer && !existing->priv->issuer)
+	{
+	  existing->priv->issuer = nss->priv->issuer;
+	  nss->priv->issuer = NULL;
+	}
+
+      g_object_unref (obj);
+      obj = G_OBJECT (existing);
+    }
+  else
+    {
+      g_tls_database_nss_gcert_created (g_tls_backend_nss_default_database,
+					nss->priv->cert, nss);
+    }
+
+  return obj;
+}
+
+static void
+g_tls_certificate_nss_finalize (GObject *object)
+{
+  GTlsCertificateNss *nss = G_TLS_CERTIFICATE_NSS (object);
+
+  if (nss->priv->cert)
+    {
+      g_tls_database_nss_gcert_destroyed (g_tls_backend_nss_default_database,
+					  nss->priv->cert);
+      CERT_DestroyCertificate (nss->priv->cert);
+    }
+  if (nss->priv->key)
+    SECKEY_DestroyPrivateKey (nss->priv->key);
+
+  if (nss->priv->issuer)
+    g_object_unref (nss->priv->issuer);
+
+  g_clear_error (&nss->priv->construct_error);
+
+  G_OBJECT_CLASS (g_tls_certificate_nss_parent_class)->finalize (object);
+}
+
+#define PEM_CERTIFICATE_HEADER "-----BEGIN CERTIFICATE-----"
+#define PEM_CERTIFICATE_FOOTER "-----END CERTIFICATE-----"
+#define PEM_PRIVKEY_HEADER     "-----BEGIN RSA PRIVATE KEY-----"
+#define PEM_PRIVKEY_FOOTER     "-----END RSA PRIVATE KEY-----"
+
+static char *
+encode_pem (const char *header,
+	    const char *footer,
+	    guint8     *data,
+	    gsize       length)
+{
+  GString *pem;
+  char *out;
+  int encoded_len, broken_len, full_len;
+  int state = 0, save = 0;
+
+  encoded_len = (length / 3 + 1) * 4;
+  broken_len = encoded_len + (encoded_len / 72) + 1;
+  full_len = strlen (header) + 1 + broken_len + strlen (footer) + 1;
+
+  pem = g_string_sized_new (full_len + 1);
+  g_string_append (pem, header);
+  g_string_append_c (pem, '\n');
+  out = pem->str + pem->len;
+  out += g_base64_encode_step (data, length, TRUE, out, &state, &save);
+  out += g_base64_encode_close (TRUE, out, &state, &save);
+  pem->len = out - pem->str;
+  g_string_append (pem, footer);
+  g_string_append_c (pem, '\n');
+
+  return g_string_free (pem, FALSE);
+}
+
+static void
+g_tls_certificate_nss_get_property (GObject    *object,
+				    guint       prop_id,
+				    GValue     *value,
+				    GParamSpec *pspec)
+{
+  GTlsCertificateNss *nss = G_TLS_CERTIFICATE_NSS (object);
+  CERTCertificate *nss_cert = nss->priv->cert;
+
+  switch (prop_id)
+    {
+    case PROP_CERTIFICATE:
+      if (nss_cert)
+	{
+	  GByteArray *certificate;
+
+	  certificate = g_byte_array_sized_new (nss_cert->derCert.len);
+	  certificate->len = nss_cert->derCert.len;
+	  memcpy (certificate->data, nss_cert->derCert.data,
+		  nss_cert->derCert.len);
+	  g_value_take_boxed (value, certificate);
+	}
+      else
+	g_value_set_boxed (value, NULL);
+      break;
+
+    case PROP_CERTIFICATE_PEM:
+      if (nss_cert)
+	{
+	  g_value_take_string (value, encode_pem (PEM_CERTIFICATE_HEADER,
+						  PEM_CERTIFICATE_FOOTER,
+						  nss_cert->derCert.data,
+						  nss_cert->derCert.len));
+	}
+      else
+	g_value_set_string (value, NULL);
+      break;
+
+    case PROP_ISSUER:
+      g_value_set_object (value, nss->priv->issuer);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_certificate_nss_set_property (GObject      *object,
+				    guint         prop_id,
+				    const GValue *value,
+				    GParamSpec   *pspec)
+{
+  GTlsCertificateNss *nss = G_TLS_CERTIFICATE_NSS (object);
+  GByteArray *bytes;
+  const gchar *string;
+
+  switch (prop_id)
+    {
+    case PROP_CERTIFICATE:
+      bytes = g_value_get_boxed (value);
+      if (!bytes)
+	break;
+      g_return_if_fail (nss->priv->cert == NULL);
+
+      /* Make sure it's really DER */
+      if (!g_strstr_len ((gchar *)bytes->data, bytes->len, "BEGIN CERTIFICATE"))
+	nss->priv->cert = CERT_DecodeCertFromPackage ((gchar *)bytes->data, bytes->len);
+
+      if (!nss->priv->cert && !nss->priv->construct_error)
+	{
+	  nss->priv->construct_error =
+	    g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+			 _("Could not parse DER certificate"));
+	}
+      break;
+
+    case PROP_CERTIFICATE_PEM:
+      string = g_value_get_string (value);
+      if (!string)
+	break;
+      g_return_if_fail (nss->priv->cert == NULL);
+
+      /* Make sure it's really PEM */
+      if (strstr (string, "BEGIN CERTIFICATE"))
+	nss->priv->cert = CERT_DecodeCertFromPackage ((gchar *)string, strlen (string));
+
+      if (!nss->priv->cert && !nss->priv->construct_error)
+	{
+	  nss->priv->construct_error =
+	    g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+			 _("Could not parse PEM certificate"));
+	}
+      break;
+
+    case PROP_PRIVATE_KEY:
+    case PROP_PRIVATE_KEY_PEM:
+      /* FIXME! */
+      break;
+
+    case PROP_ISSUER:
+      nss->priv->issuer = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_certificate_nss_init (GTlsCertificateNss *nss)
+{
+  nss->priv = G_TYPE_INSTANCE_GET_PRIVATE (nss,
+					   G_TYPE_TLS_CERTIFICATE_NSS,
+					   GTlsCertificateNssPrivate);
+}
+
+static gboolean
+g_tls_certificate_nss_initable_init (GInitable       *initable,
+				     GCancellable    *cancellable,
+				     GError         **error)
+{
+  GTlsCertificateNss *nss = G_TLS_CERTIFICATE_NSS (initable);
+
+  if (nss->priv->construct_error)
+    {
+      g_propagate_error (error, nss->priv->construct_error);
+      nss->priv->construct_error = NULL;
+      return FALSE;
+    }
+  else if (!nss->priv->cert)
+    {
+      g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+			   _("No certificate data provided"));
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+/* FIXME: mostly dup from gnutls */
+static GTlsCertificateFlags
+g_tls_certificate_nss_verify_identity (GTlsCertificateNss *nss,
+				       GSocketConnectable *identity)
+{
+  const char *hostname;
+
+  if (G_IS_NETWORK_ADDRESS (identity))
+    hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
+  else if (G_IS_NETWORK_SERVICE (identity))
+    hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
+  else
+    hostname = NULL;
+
+  if (hostname)
+    {
+      if (CERT_VerifyCertName (nss->priv->cert, hostname) == SECSuccess)
+	return 0;
+    }
+
+  /* FIXME: check sRVName and uniformResourceIdentifier
+   * subjectAltNames, if appropriate for @identity.
+   */
+
+  return G_TLS_CERTIFICATE_BAD_IDENTITY;
+}
+
+static void
+g_tls_certificate_nss_expand_chain (GTlsCertificateNss *nss_cert)
+{
+  GTlsCertificateNss *c, *issuer = NULL;
+  CERTCertificateList *list;
+  CERTCertificate *cert;
+  SECCertUsage usage;
+  int i;
+
+  g_return_if_fail (nss_cert->priv->cert->nsCertType != 0);
+
+  if (nss_cert->priv->expanded)
+    return;
+
+  if (nss_cert->priv->cert->nsCertType & NS_CERT_TYPE_SSL_CLIENT)
+    usage = certUsageSSLClient;
+  else
+    usage = certUsageSSLServer;
+
+  list = CERT_CertChainFromCert (nss_cert->priv->cert, usage, PR_TRUE);
+  /* list->certs[0] is nss_cert itself, so start from index 1 */
+  for (i = 1, c = nss_cert; i < list->len; i++, c = c->priv->issuer)
+    {
+      cert = CERT_FindCertByDERCert (g_tls_backend_nss_certdbhandle,
+				     &list->certs[i]);
+      issuer = g_tls_database_nss_get_gcert (g_tls_backend_nss_default_database, cert, TRUE);
+      CERT_DestroyCertificate (cert);
+
+      if (c->priv->issuer == issuer)
+	{
+	  g_object_unref (issuer);
+	  break;
+	}
+
+      if (c->priv->issuer)
+	g_object_unref (c->priv->issuer);
+      c->priv->issuer = issuer;
+      c->priv->expanded = TRUE;
+    }
+
+  if (i == list->len && issuer)
+    {
+      issuer->priv->expanded = TRUE;
+      g_clear_object (&issuer->priv->issuer);
+    }
+
+  CERT_DestroyCertificateList (list);
+}
+
+/* Our certificate verification routine... called by both
+ * g_tls_certificate_nss_verify() and g_tls_database_nss_verify_chain().
+ *
+ * For our verification purposes, we have to treat the certificates in
+ * @database or @trusted_ca as though they were trusted, but we can't
+ * actually mark them trusted because we don't know why our caller is
+ * currently considering them trusted, so we can't let that trust
+ * "leak" into the rest of the program.
+ *
+ * Fortunately, NSS will tell us in excruciating detail exactly what it
+ * doesn't like about a certificate, and so if the only problem with
+ * the cert is that it's signed by a @database or @trusted_ca cert that
+ * NSS doesn't like, then we can just ignore that error.
+ */
+GTlsCertificateFlags
+g_tls_certificate_nss_verify_full (GTlsCertificate          *chain,
+				   GTlsDatabase             *database,
+				   GTlsCertificate          *trusted_ca,
+				   const gchar              *purpose,
+				   GSocketConnectable       *identity,
+				   GTlsInteraction          *interaction,
+				   GTlsDatabaseVerifyFlags   flags,
+				   GCancellable             *cancellable,
+				   GError                  **error)
+{
+  GTlsCertificateNss *nss_cert = G_TLS_CERTIFICATE_NSS (chain);
+  GTlsCertificateFlags result;
+  SECCertificateUsage usage;
+  PLArenaPool *arena;
+  CERTVerifyLog *log;
+  CERTVerifyLogNode *node;
+  PRTime now = PR_Now ();
+  SECCertTimeValidity time_validity;
+  int trusted_ca_index = -1;
+
+  g_return_val_if_fail (database == NULL || trusted_ca == NULL, G_TLS_CERTIFICATE_GENERIC_ERROR);
+
+  if (database == (GTlsDatabase *)g_tls_backend_nss_default_database)
+    database = NULL;
+
+  if (!strcmp (purpose, G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER))
+    usage = certificateUsageSSLServer;
+  else if (!strcmp (purpose, G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT))
+    usage = certificateUsageSSLClient;
+  else
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+		   _("Unsupported key purpose OID '%s'"), purpose);
+      return G_TLS_CERTIFICATE_GENERIC_ERROR;
+    }
+
+  result = 0;
+
+  /* Verify the certificate and log all errors. As a side effect, this
+   * will ensure that nss_cert->priv->cert->nsCertType is set.
+   */
+  arena = PORT_NewArena (512);
+  log = PORT_ArenaZNew (arena, CERTVerifyLog);
+  log->arena = arena;
+  CERT_VerifyCert (g_tls_backend_nss_certdbhandle, nss_cert->priv->cert,
+		   PR_TRUE, usage, now, interaction, log);
+
+  /* Now expand the gtls-level chain, and see if it contains a cert
+   * from @trusted_ca or @database, and if so, remember where in the
+   * chain it is.
+   */
+  g_tls_certificate_nss_expand_chain (nss_cert);
+  if (database || trusted_ca)
+    {
+      GTlsFileDatabaseNss *db_nss = database ? G_TLS_FILE_DATABASE_NSS (database) : NULL;
+      GTlsCertificateNss *c;
+      int n;
+
+      for (c = nss_cert, n = 0; c; c = c->priv->issuer, n++)
+	{
+	  if (trusted_ca && c == (GTlsCertificateNss *)trusted_ca)
+	    break;
+	  if (db_nss && g_tls_file_database_nss_contains (db_nss, c))
+	    break;
+	}
+
+      if (c)
+	trusted_ca_index = n;
+      else
+	result |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+    }
+
+  /* Now go through the verification log translating the errors */
+  for (node = log->head; node; node = node->next)
+    {
+      if (trusted_ca_index != -1 && node->depth > trusted_ca_index)
+	break;
+
+      switch (node->error)
+	{
+	case SEC_ERROR_INADEQUATE_KEY_USAGE:
+	  /* Cert is not appropriately tagged for signing. For
+	   * historical/compatibility reasons, we ignore this when
+	   * using PEM certificates.
+	   */
+	  if (database || trusted_ca)
+	    break;
+	  /* else fall through */
+
+	case SEC_ERROR_UNKNOWN_ISSUER:
+	  /* Cert was issued by an unknown CA */
+	case SEC_ERROR_UNTRUSTED_ISSUER:
+	  /* Cert is a CA that is not marked trusted */
+	case SEC_ERROR_CA_CERT_INVALID:
+	  /* Cert is not a CA */
+
+	  /* These are all OK if they occur on the trusted CA, but not
+	   * before it.
+	   */
+	  if (node->depth != trusted_ca_index)
+	    result |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+	  break;
+
+	case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
+	  /* Cert is not authorized to sign the cert it signed */
+	  result |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+	  break;
+
+	case SEC_ERROR_EXPIRED_CERTIFICATE:
+	case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+	  /* Cert is either expired or not yet valid;
+	   * CERT_VerifyCert() doesn't distinguish.
+	   */
+	  time_validity =  CERT_CheckCertValidTimes (node->cert, now, PR_FALSE);
+	  if (time_validity == secCertTimeNotValidYet)
+	    result |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
+	  else if (time_validity == secCertTimeExpired)
+	    result |= G_TLS_CERTIFICATE_EXPIRED;
+	  break;
+
+	case SEC_ERROR_REVOKED_CERTIFICATE:
+	  result |= G_TLS_CERTIFICATE_REVOKED;
+	  break;
+
+	default:
+	  result |= G_TLS_CERTIFICATE_GENERIC_ERROR;
+	  break;
+	}
+
+      CERT_DestroyCertificate (node->cert);
+    }
+
+  for (; node; node = node->next)
+    CERT_DestroyCertificate (node->cert);
+  PORT_FreeArena (log->arena, PR_FALSE);
+
+  if (identity)
+    result |= g_tls_certificate_nss_verify_identity (nss_cert, identity);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    result = G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+  return result;
+}
+
+static GTlsCertificateFlags
+g_tls_certificate_nss_verify (GTlsCertificate     *cert,
+			      GSocketConnectable  *identity,
+			      GTlsCertificate     *trusted_ca)
+{
+  GTlsCertificateNss *nss_cert = G_TLS_CERTIFICATE_NSS (cert);
+  GTlsCertificateFlags flags;
+
+  /* nss_cert->priv->cert->nsCertType may not have been set yet, but
+   * it will get set as a side effect of verifying the cert. If we
+   * don't know yet what kind of key it is, we'll try server first.
+   */
+
+  if ((nss_cert->priv->cert->nsCertType & NS_CERT_TYPE_SSL_SERVER) ||
+      (nss_cert->priv->cert->nsCertType == 0))
+    {
+      flags = g_tls_certificate_nss_verify_full (cert, NULL, trusted_ca,
+						 G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER,
+						 identity, NULL, 0, NULL, NULL);
+    }
+
+  if (!(nss_cert->priv->cert->nsCertType & NS_CERT_TYPE_SSL_SERVER))
+    {
+      flags = g_tls_certificate_nss_verify_full (cert, NULL, trusted_ca,
+						 G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
+						 identity, NULL, 0, NULL, NULL);
+    }
+
+  return flags;
+}
+
+static void
+g_tls_certificate_nss_class_init (GTlsCertificateNssClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsCertificateClass *certificate_class = G_TLS_CERTIFICATE_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsCertificateNssPrivate));
+
+  gobject_class->constructor  = g_tls_certificate_nss_constructor;
+  gobject_class->get_property = g_tls_certificate_nss_get_property;
+  gobject_class->set_property = g_tls_certificate_nss_set_property;
+  gobject_class->finalize     = g_tls_certificate_nss_finalize;
+
+  certificate_class->verify = g_tls_certificate_nss_verify;
+
+  g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
+  g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
+  g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
+  g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
+  g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
+}
+
+static void
+g_tls_certificate_nss_initable_iface_init (GInitableIface  *iface)
+{
+  iface->init = g_tls_certificate_nss_initable_init;
+}
+
+GTlsCertificateNss *
+g_tls_certificate_nss_new_for_cert (CERTCertificate *cert)
+{
+  GTlsCertificateNss *nss;
+
+  nss = g_object_new (G_TYPE_TLS_CERTIFICATE_NSS, NULL);
+  nss->priv->cert = CERT_DupCertificate (cert);
+
+  return nss;
+}
+
+CERTCertificate *
+g_tls_certificate_nss_get_cert (GTlsCertificateNss *nss)
+{
+  return nss->priv->cert;
+}
+
+
diff --git a/tls/nss/gtlscertificate-nss.h b/tls/nss/gtlscertificate-nss.h
new file mode 100644
index 0000000..578448d
--- /dev/null
+++ b/tls/nss/gtlscertificate-nss.h
@@ -0,0 +1,61 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_CERTIFICATE_NSS_H__
+#define __G_TLS_CERTIFICATE_NSS_H__
+
+#include <gio/gio.h>
+#include <nss.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_CERTIFICATE_NSS            (g_tls_certificate_nss_get_type ())
+#define G_TLS_CERTIFICATE_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CERTIFICATE_NSS, GTlsCertificateNss))
+#define G_TLS_CERTIFICATE_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_CERTIFICATE_NSS, GTlsCertificateNssClass))
+#define G_IS_TLS_CERTIFICATE_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CERTIFICATE_NSS))
+#define G_IS_TLS_CERTIFICATE_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_CERTIFICATE_NSS))
+#define G_TLS_CERTIFICATE_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_CERTIFICATE_NSS, GTlsCertificateNssClass))
+
+typedef struct _GTlsCertificateNssPrivate                   GTlsCertificateNssPrivate;
+typedef struct _GTlsCertificateNssClass                     GTlsCertificateNssClass;
+typedef struct _GTlsCertificateNss                          GTlsCertificateNss;
+
+struct _GTlsCertificateNssClass
+{
+  GTlsCertificateClass parent_class;
+};
+
+struct _GTlsCertificateNss
+{
+  GTlsCertificate parent_instance;
+  GTlsCertificateNssPrivate *priv;
+};
+
+GType g_tls_certificate_nss_get_type (void) G_GNUC_CONST;
+
+GTlsCertificateNss   *g_tls_certificate_nss_new_for_cert (CERTCertificate          *cert);
+
+CERTCertificate      *g_tls_certificate_nss_get_cert     (GTlsCertificateNss       *nss);
+
+GTlsCertificateFlags  g_tls_certificate_nss_verify_full  (GTlsCertificate          *chain,
+							  GTlsDatabase             *database,
+							  GTlsCertificate          *trusted_ca,
+							  const gchar              *purpose,
+							  GSocketConnectable       *identity,
+							  GTlsInteraction          *interaction,
+							  GTlsDatabaseVerifyFlags   flags,
+							  GCancellable             *cancellable,
+							  GError                  **error);
+
+G_END_DECLS
+
+#endif /* __G_TLS_CERTIFICATE_NSS_H___ */
diff --git a/tls/nss/gtlsclientconnection-nss.c b/tls/nss/gtlsclientconnection-nss.c
new file mode 100644
index 0000000..327cfc1
--- /dev/null
+++ b/tls/nss/gtlsclientconnection-nss.c
@@ -0,0 +1,162 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <glib.h>
+
+#include "gtlsclientconnection-nss.h"
+#include <glib/gi18n-lib.h>
+
+enum
+{
+  PROP_0,
+  PROP_VALIDATION_FLAGS,
+  PROP_SERVER_IDENTITY,
+  PROP_USE_SSL3,
+  PROP_ACCEPTED_CAS
+};
+
+static void g_tls_client_connection_nss_client_connection_interface_init (GTlsClientConnectionInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsClientConnectionNss, g_tls_client_connection_nss, G_TYPE_TLS_CONNECTION_NSS,
+			 G_IMPLEMENT_INTERFACE (G_TYPE_TLS_CLIENT_CONNECTION,
+						g_tls_client_connection_nss_client_connection_interface_init));
+
+struct _GTlsClientConnectionNssPrivate
+{
+  GTlsCertificateFlags validation_flags;
+  GSocketConnectable *server_identity;
+  gboolean use_ssl3;
+  GPtrArray *accepted_cas;
+};
+
+static void
+g_tls_client_connection_nss_init (GTlsClientConnectionNss *nss)
+{
+  nss->priv = G_TYPE_INSTANCE_GET_PRIVATE (nss, G_TYPE_TLS_CLIENT_CONNECTION_NSS, GTlsClientConnectionNssPrivate);
+}
+
+static void
+g_tls_client_connection_nss_finalize (GObject *object)
+{
+  GTlsClientConnectionNss *nss = G_TLS_CLIENT_CONNECTION_NSS (object);
+
+  if (nss->priv->server_identity)
+    g_object_unref (nss->priv->server_identity);
+  if (nss->priv->accepted_cas)
+    g_ptr_array_unref (nss->priv->accepted_cas);
+
+  G_OBJECT_CLASS (g_tls_client_connection_nss_parent_class)->finalize (object);
+}
+
+static void
+g_tls_client_connection_nss_get_property (GObject    *object,
+					  guint       prop_id,
+					  GValue     *value,
+					  GParamSpec *pspec)
+{
+  GTlsClientConnectionNss *nss = G_TLS_CLIENT_CONNECTION_NSS (object);
+  GList *accepted_cas;
+  gint i;
+
+  switch (prop_id)
+    {
+    case PROP_VALIDATION_FLAGS:
+      g_value_set_flags (value, nss->priv->validation_flags);
+      break;
+
+    case PROP_SERVER_IDENTITY:
+      g_value_set_object (value, nss->priv->server_identity);
+      break;
+
+    case PROP_USE_SSL3:
+      g_value_set_boolean (value, nss->priv->use_ssl3);
+      break;
+
+    case PROP_ACCEPTED_CAS:
+      accepted_cas = NULL;
+      if (nss->priv->accepted_cas)
+        {
+          for (i = 0; i < nss->priv->accepted_cas->len; ++i)
+            {
+              accepted_cas = g_list_prepend (accepted_cas, g_byte_array_ref (
+                                             nss->priv->accepted_cas->pdata[i]));
+            }
+          accepted_cas = g_list_reverse (accepted_cas);
+        }
+      g_value_set_pointer (value, accepted_cas);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_client_connection_nss_set_property (GObject      *object,
+					  guint         prop_id,
+					  const GValue *value,
+					  GParamSpec   *pspec)
+{
+  GTlsClientConnectionNss *nss = G_TLS_CLIENT_CONNECTION_NSS (object);
+
+  switch (prop_id)
+    {
+    case PROP_VALIDATION_FLAGS:
+      nss->priv->validation_flags = g_value_get_flags (value);
+      break;
+
+    case PROP_SERVER_IDENTITY:
+      if (nss->priv->server_identity)
+	g_object_unref (nss->priv->server_identity);
+      nss->priv->server_identity = g_value_dup_object (value);
+      break;
+
+    case PROP_USE_SSL3:
+      nss->priv->use_ssl3 = g_value_get_boolean (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_client_connection_nss_class_init (GTlsClientConnectionNssClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsClientConnectionNssPrivate));
+
+  gobject_class->get_property = g_tls_client_connection_nss_get_property;
+  gobject_class->set_property = g_tls_client_connection_nss_set_property;
+  gobject_class->finalize     = g_tls_client_connection_nss_finalize;
+
+  g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
+  g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
+  g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3");
+  g_object_class_override_property (gobject_class, PROP_ACCEPTED_CAS, "accepted-cas");
+}
+
+static void
+g_tls_client_connection_nss_client_connection_interface_init (GTlsClientConnectionInterface *iface)
+{
+}
+
diff --git a/tls/nss/gtlsclientconnection-nss.h b/tls/nss/gtlsclientconnection-nss.h
new file mode 100644
index 0000000..294a8a7
--- /dev/null
+++ b/tls/nss/gtlsclientconnection-nss.h
@@ -0,0 +1,46 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_CLIENT_CONNECTION_NSS_H__
+#define __G_TLS_CLIENT_CONNECTION_NSS_H__
+
+#include "gtlsconnection-nss.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_CLIENT_CONNECTION_NSS            (g_tls_client_connection_nss_get_type ())
+#define G_TLS_CLIENT_CONNECTION_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CLIENT_CONNECTION_NSS, GTlsClientConnectionNss))
+#define G_TLS_CLIENT_CONNECTION_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_CLIENT_CONNECTION_NSS, GTlsClientConnectionNssClass))
+#define G_IS_TLS_CLIENT_CONNECTION_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CLIENT_CONNECTION_NSS))
+#define G_IS_TLS_CLIENT_CONNECTION_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_CLIENT_CONNECTION_NSS))
+#define G_TLS_CLIENT_CONNECTION_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_CLIENT_CONNECTION_NSS, GTlsClientConnectionNssClass))
+
+typedef struct _GTlsClientConnectionNssPrivate GTlsClientConnectionNssPrivate;
+typedef struct _GTlsClientConnectionNssClass   GTlsClientConnectionNssClass;
+typedef struct _GTlsClientConnectionNss        GTlsClientConnectionNss;
+
+struct _GTlsClientConnectionNssClass
+{
+  GTlsConnectionNssClass parent_class;
+};
+
+struct _GTlsClientConnectionNss
+{
+  GTlsConnectionNss parent_instance;
+  GTlsClientConnectionNssPrivate *priv;
+};
+
+GType g_tls_client_connection_nss_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_TLS_CLIENT_CONNECTION_NSS_H___ */
diff --git a/tls/nss/gtlsconnection-nss.c b/tls/nss/gtlsconnection-nss.c
new file mode 100644
index 0000000..c42a77d
--- /dev/null
+++ b/tls/nss/gtlsconnection-nss.c
@@ -0,0 +1,365 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <glib.h>
+
+#include "gtlsconnection-nss.h"
+#include <glib/gi18n-lib.h>
+
+static void     g_tls_connection_nss_initable_iface_init (GInitableIface  *iface);
+
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GTlsConnectionNss, g_tls_connection_nss, G_TYPE_TLS_CONNECTION,
+				  G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+							 g_tls_connection_nss_initable_iface_init););
+
+
+enum
+{
+  PROP_0,
+  PROP_BASE_IO_STREAM,
+  PROP_REQUIRE_CLOSE_NOTIFY,
+  PROP_REHANDSHAKE_MODE,
+  PROP_USE_SYSTEM_CERTDB,
+  PROP_DATABASE,
+  PROP_CERTIFICATE,
+  PROP_INTERACTION,
+  PROP_PEER_CERTIFICATE,
+  PROP_PEER_CERTIFICATE_ERRORS
+};
+
+struct _GTlsConnectionNssPrivate
+{
+  GIOStream *base_io_stream;
+  GPollableInputStream *base_istream;
+  GPollableOutputStream *base_ostream;
+
+  GTlsCertificate *certificate, *peer_certificate;
+  GTlsCertificateFlags peer_certificate_errors;
+  gboolean require_close_notify;
+  GTlsRehandshakeMode rehandshake_mode;
+  gboolean is_system_certdb;
+  GTlsDatabase *database;
+  gboolean database_is_unset;
+
+  GInputStream *tls_istream;
+  GOutputStream *tls_ostream;
+
+  GTlsInteraction *interaction;
+};
+
+static void
+g_tls_connection_nss_init (GTlsConnectionNss *nss)
+{
+  nss->priv = G_TYPE_INSTANCE_GET_PRIVATE (nss, G_TYPE_TLS_CONNECTION_NSS, GTlsConnectionNssPrivate);
+
+  nss->priv->database_is_unset = TRUE;
+  nss->priv->is_system_certdb = TRUE;
+}
+
+static gboolean
+g_tls_connection_nss_initable_init (GInitable     *initable,
+				    GCancellable  *cancellable,
+				    GError       **error)
+{
+  GTlsConnectionNss *nss = G_TLS_CONNECTION_NSS (initable);
+
+  g_return_val_if_fail (nss->priv->base_istream != NULL &&
+			nss->priv->base_ostream != NULL, FALSE);
+
+  return TRUE;
+}
+
+static void
+g_tls_connection_nss_finalize (GObject *object)
+{
+  GTlsConnectionNss *nss = G_TLS_CONNECTION_NSS (object);
+
+  if (nss->priv->base_io_stream)
+    g_object_unref (nss->priv->base_io_stream);
+
+  if (nss->priv->tls_istream)
+    g_object_unref (nss->priv->tls_istream);
+  if (nss->priv->tls_ostream) 
+    g_object_unref (nss->priv->tls_ostream);
+
+  if (nss->priv->database)
+    g_object_unref (nss->priv->database);
+  if (nss->priv->certificate)
+    g_object_unref (nss->priv->certificate);
+  if (nss->priv->peer_certificate)
+    g_object_unref (nss->priv->peer_certificate);
+
+  if (nss->priv->interaction)
+    g_object_unref (nss->priv->interaction);
+
+  G_OBJECT_CLASS (g_tls_connection_nss_parent_class)->finalize (object);
+}
+
+static void
+g_tls_connection_nss_get_property (GObject    *object,
+				   guint       prop_id,
+				   GValue     *value,
+				   GParamSpec *pspec)
+{
+  GTlsConnectionNss *nss = G_TLS_CONNECTION_NSS (object);
+  GTlsBackend *backend;
+
+  switch (prop_id)
+    {
+    case PROP_BASE_IO_STREAM:
+      g_value_set_object (value, nss->priv->base_io_stream);
+      break;
+
+    case PROP_REQUIRE_CLOSE_NOTIFY:
+      g_value_set_boolean (value, nss->priv->require_close_notify);
+      break;
+
+    case PROP_REHANDSHAKE_MODE:
+      g_value_set_enum (value, nss->priv->rehandshake_mode);
+      break;
+
+    case PROP_USE_SYSTEM_CERTDB:
+      g_value_set_boolean (value, nss->priv->is_system_certdb);
+      break;
+
+    case PROP_DATABASE:
+      if (nss->priv->database_is_unset)
+        {
+          backend = g_tls_backend_get_default ();
+          nss->priv->database = g_tls_backend_get_default_database (backend);
+          nss->priv->database_is_unset = FALSE;
+        }
+      g_value_set_object (value, nss->priv->database);
+      break;
+
+    case PROP_CERTIFICATE:
+      g_value_set_object (value, nss->priv->certificate);
+      break;
+
+    case PROP_INTERACTION:
+      g_value_set_object (value, nss->priv->interaction);
+      break;
+
+    case PROP_PEER_CERTIFICATE:
+      g_value_set_object (value, nss->priv->peer_certificate);
+      break;
+
+    case PROP_PEER_CERTIFICATE_ERRORS:
+      g_value_set_flags (value, nss->priv->peer_certificate_errors);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_connection_nss_set_property (GObject      *object,
+				   guint         prop_id,
+				   const GValue *value,
+				   GParamSpec   *pspec)
+{
+  GTlsConnectionNss *nss = G_TLS_CONNECTION_NSS (object);
+  GInputStream *istream;
+  GOutputStream *ostream;
+  gboolean system_certdb;
+  GTlsBackend *backend;
+
+  switch (prop_id)
+    {
+    case PROP_BASE_IO_STREAM:
+      if (nss->priv->base_io_stream)
+	{
+	  g_object_unref (nss->priv->base_io_stream);
+	  nss->priv->base_istream = NULL;
+	  nss->priv->base_ostream = NULL;
+	}
+      nss->priv->base_io_stream = g_value_dup_object (value);
+      if (!nss->priv->base_io_stream)
+	return;
+
+      istream = g_io_stream_get_input_stream (nss->priv->base_io_stream);
+      ostream = g_io_stream_get_output_stream (nss->priv->base_io_stream);
+
+      if (G_IS_POLLABLE_INPUT_STREAM (istream) &&
+	  g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (istream)))
+	nss->priv->base_istream = G_POLLABLE_INPUT_STREAM (istream);
+      if (G_IS_POLLABLE_OUTPUT_STREAM (ostream) &&
+	  g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (ostream)))
+	nss->priv->base_ostream = G_POLLABLE_OUTPUT_STREAM (ostream);
+      break;
+
+    case PROP_REQUIRE_CLOSE_NOTIFY:
+      nss->priv->require_close_notify = g_value_get_boolean (value);
+      break;
+
+    case PROP_REHANDSHAKE_MODE:
+      nss->priv->rehandshake_mode = g_value_get_enum (value);
+      break;
+
+    case PROP_USE_SYSTEM_CERTDB:
+      system_certdb = g_value_get_boolean (value);
+      if (system_certdb != nss->priv->is_system_certdb)
+        {
+          g_clear_object (&nss->priv->database);
+          if (system_certdb)
+            {
+              backend = g_tls_backend_get_default ();
+              nss->priv->database = g_tls_backend_get_default_database (backend);
+            }
+          nss->priv->is_system_certdb = system_certdb;
+        }
+      break;
+
+    case PROP_DATABASE:
+      if (nss->priv->database)
+	g_object_unref (nss->priv->database);
+      nss->priv->database = g_value_dup_object (value);
+      nss->priv->is_system_certdb = FALSE;
+      nss->priv->database_is_unset = FALSE;
+      break;
+
+    case PROP_CERTIFICATE:
+      if (nss->priv->certificate)
+	g_object_unref (nss->priv->certificate);
+      nss->priv->certificate = g_value_dup_object (value);
+      break;
+
+    case PROP_INTERACTION:
+      if (nss->priv->interaction)
+	g_object_unref (nss->priv->interaction);
+      nss->priv->interaction = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static gboolean
+g_tls_connection_nss_handshake (GTlsConnection   *conn,
+				GCancellable     *cancellable,
+				GError          **error)
+{
+  g_return_val_if_reached (FALSE);
+}
+
+static void
+g_tls_connection_nss_handshake_async (GTlsConnection       *conn,
+				      int                   io_priority,
+				      GCancellable         *cancellable,
+				      GAsyncReadyCallback   callback,
+				      gpointer              user_data)
+{
+  g_return_if_reached ();
+}
+
+static gboolean
+g_tls_connection_nss_handshake_finish (GTlsConnection       *conn,
+					  GAsyncResult         *result,
+					  GError              **error)
+{
+  g_return_val_if_reached (FALSE);
+}
+
+static GInputStream  *
+g_tls_connection_nss_get_input_stream (GIOStream *stream)
+{
+  GTlsConnectionNss *nss = G_TLS_CONNECTION_NSS (stream);
+
+  return nss->priv->tls_istream;
+}
+
+static GOutputStream *
+g_tls_connection_nss_get_output_stream (GIOStream *stream)
+{
+  GTlsConnectionNss *nss = G_TLS_CONNECTION_NSS (stream);
+
+  return nss->priv->tls_ostream;
+}
+
+static gboolean
+g_tls_connection_nss_close (GIOStream     *stream,
+			    GCancellable  *cancellable,
+			    GError       **error)
+{
+  g_return_val_if_reached (FALSE);
+}
+
+static void
+g_tls_connection_nss_close_async (GIOStream           *stream,
+				  int                  io_priority,
+				  GCancellable        *cancellable,
+				  GAsyncReadyCallback  callback,
+				  gpointer             user_data)
+{
+  g_return_if_reached ();
+}
+
+static gboolean
+g_tls_connection_nss_close_finish (GIOStream           *stream,
+				      GAsyncResult        *result,
+				      GError             **error)
+{
+  g_return_val_if_reached (FALSE);
+}
+
+static void
+g_tls_connection_nss_class_init (GTlsConnectionNssClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsConnectionClass *connection_class = G_TLS_CONNECTION_CLASS (klass);
+  GIOStreamClass *iostream_class = G_IO_STREAM_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsConnectionNssPrivate));
+
+  gobject_class->get_property = g_tls_connection_nss_get_property;
+  gobject_class->set_property = g_tls_connection_nss_set_property;
+  gobject_class->finalize     = g_tls_connection_nss_finalize;
+
+  connection_class->handshake        = g_tls_connection_nss_handshake;
+  connection_class->handshake_async  = g_tls_connection_nss_handshake_async;
+  connection_class->handshake_finish = g_tls_connection_nss_handshake_finish;
+
+  iostream_class->get_input_stream  = g_tls_connection_nss_get_input_stream;
+  iostream_class->get_output_stream = g_tls_connection_nss_get_output_stream;
+  iostream_class->close_fn          = g_tls_connection_nss_close;
+  iostream_class->close_async       = g_tls_connection_nss_close_async;
+  iostream_class->close_finish      = g_tls_connection_nss_close_finish;
+
+  g_object_class_override_property (gobject_class, PROP_BASE_IO_STREAM, "base-io-stream");
+  g_object_class_override_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, "require-close-notify");
+  g_object_class_override_property (gobject_class, PROP_REHANDSHAKE_MODE, "rehandshake-mode");
+  g_object_class_override_property (gobject_class, PROP_USE_SYSTEM_CERTDB, "use-system-certdb");
+  g_object_class_override_property (gobject_class, PROP_DATABASE, "database");
+  g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
+  g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction");
+  g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE, "peer-certificate");
+  g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE_ERRORS, "peer-certificate-errors");
+}
+
+static void
+g_tls_connection_nss_initable_iface_init (GInitableIface *iface)
+{
+  iface->init = g_tls_connection_nss_initable_init;
+}
+
diff --git a/tls/nss/gtlsconnection-nss.h b/tls/nss/gtlsconnection-nss.h
new file mode 100644
index 0000000..26bcc6c
--- /dev/null
+++ b/tls/nss/gtlsconnection-nss.h
@@ -0,0 +1,48 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_CONNECTION_NSS_H__
+#define __G_TLS_CONNECTION_NSS_H__
+
+#include <gio/gio.h>
+#include <nss.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_CONNECTION_NSS            (g_tls_connection_nss_get_type ())
+#define G_TLS_CONNECTION_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CONNECTION_NSS, GTlsConnectionNss))
+#define G_TLS_CONNECTION_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_CONNECTION_NSS, GTlsConnectionNssClass))
+#define G_IS_TLS_CONNECTION_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CONNECTION_NSS))
+#define G_IS_TLS_CONNECTION_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_CONNECTION_NSS))
+#define G_TLS_CONNECTION_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_CONNECTION_NSS, GTlsConnectionNssClass))
+
+typedef struct _GTlsConnectionNssPrivate                   GTlsConnectionNssPrivate;
+typedef struct _GTlsConnectionNssClass                     GTlsConnectionNssClass;
+typedef struct _GTlsConnectionNss                          GTlsConnectionNss;
+
+struct _GTlsConnectionNssClass
+{
+  GTlsConnectionClass parent_class;
+
+};
+
+struct _GTlsConnectionNss
+{
+  GTlsConnection parent_instance;
+  GTlsConnectionNssPrivate *priv;
+};
+
+GType g_tls_connection_nss_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_TLS_CONNECTION_NSS_H___ */
diff --git a/tls/nss/gtlsdatabase-nss.c b/tls/nss/gtlsdatabase-nss.c
new file mode 100644
index 0000000..53f1156
--- /dev/null
+++ b/tls/nss/gtlsdatabase-nss.c
@@ -0,0 +1,283 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include <nss.h>
+#include <pk11pub.h>
+#include <secerr.h>
+
+#include "gtlsdatabase-nss.h"
+#include "gtlsbackend-nss.h"
+#include "gtlscertificate-nss.h"
+
+#include <glib/gi18n-lib.h>
+
+G_DEFINE_TYPE (GTlsDatabaseNss, g_tls_database_nss, G_TYPE_TLS_DATABASE);
+
+struct _GTlsDatabaseNssPrivate
+{
+  GMutex *mutex;
+  GHashTable *gcerts;
+};
+
+static void
+g_tls_database_nss_init (GTlsDatabaseNss *nss)
+{
+  nss->priv = G_TYPE_INSTANCE_GET_PRIVATE (nss,
+					   G_TYPE_TLS_DATABASE_NSS,
+					   GTlsDatabaseNssPrivate);
+
+  nss->priv->mutex = g_mutex_new ();
+
+  /* gcerts is a cache of CERTCertificate to GTlsCertificateNss
+   * mappings, including every live GTlsCertificateNss. Note that both
+   * types enforce uniqueness, so there should be a one-to-one
+   * mapping.
+   */
+  nss->priv->gcerts = g_hash_table_new (NULL, NULL);
+}
+
+static void
+g_tls_database_nss_finalize (GObject *object)
+{
+  GTlsDatabaseNss *nss = G_TLS_DATABASE_NSS (object);
+  GHashTableIter iter;
+  gpointer cert, gcert;
+
+  g_mutex_free (nss->priv->mutex);
+
+  g_hash_table_iter_init (&iter, nss->priv->gcerts);
+  while (g_hash_table_iter_next (&iter, &cert, &gcert))
+    CERT_DestroyCertificate (cert);
+  g_hash_table_destroy (nss->priv->gcerts);
+
+  G_OBJECT_CLASS (g_tls_database_nss_parent_class)->finalize (object);
+}
+
+GTlsCertificateNss *
+g_tls_database_nss_get_gcert (GTlsDatabaseNss *nss,
+			      CERTCertificate *cert,
+			      gboolean         create)
+{
+  GTlsCertificateNss *gcert;
+
+  g_mutex_lock (nss->priv->mutex);
+
+  gcert = g_hash_table_lookup (nss->priv->gcerts, cert);
+  if (gcert)
+    g_object_ref (gcert);
+  else if (create)
+    {
+      gcert = g_tls_certificate_nss_new_for_cert (cert);
+      /* The GTlsCertificate constructor will call
+       * g_tls_database_nss_gcert_created() to add it to the hash.
+       */
+    }
+
+  g_mutex_unlock (nss->priv->mutex);
+  return gcert;
+}
+
+void
+g_tls_database_nss_gcert_created (GTlsDatabaseNss    *nss,
+				  CERTCertificate    *cert,
+				  GTlsCertificateNss *gcert)
+{
+  g_mutex_lock (nss->priv->mutex);
+  /* We keep a ref on the CERTCertificate, but not the GTlsCertificate */
+  g_hash_table_insert (nss->priv->gcerts, CERT_DupCertificate (cert), gcert);
+  g_mutex_unlock (nss->priv->mutex);
+}
+
+void
+g_tls_database_nss_gcert_destroyed (GTlsDatabaseNss *nss,
+				    CERTCertificate *cert)
+{
+  g_mutex_lock (nss->priv->mutex);
+  g_hash_table_remove (nss->priv->gcerts, cert);
+  CERT_DestroyCertificate (cert);
+  g_mutex_unlock (nss->priv->mutex);
+}
+
+static GTlsCertificateFlags
+g_tls_database_nss_verify_chain (GTlsDatabase             *database,
+				 GTlsCertificate          *chain,
+				 const gchar              *purpose,
+				 GSocketConnectable       *identity,
+				 GTlsInteraction          *interaction,
+				 GTlsDatabaseVerifyFlags   flags,
+				 GCancellable             *cancellable,
+				 GError                  **error)
+{
+  return g_tls_certificate_nss_verify_full (chain, database, NULL,
+					    purpose, identity, interaction,
+					    flags, cancellable, error);
+}
+
+static gchar *
+g_tls_database_nss_create_certificate_handle (GTlsDatabase    *database,
+					      GTlsCertificate *certificate)
+{
+
+  CERTCertificate *cert = g_tls_certificate_nss_get_cert (G_TLS_CERTIFICATE_NSS (certificate));
+  gchar *issuer, *serial, *handle;
+
+  issuer = g_base64_encode ((guchar *)cert->derIssuer.data,
+			    cert->derIssuer.len);
+  serial = g_base64_encode ((guchar *)cert->serialNumber.data,
+			    cert->serialNumber.len);
+
+  handle = g_strdup_printf ("nss:%s#%s", issuer, serial);
+  g_free (issuer);
+  g_free (serial);
+
+  return handle;
+}
+
+static GTlsCertificate *
+g_tls_database_nss_lookup_certificate_for_handle (GTlsDatabase             *database,
+						  const gchar              *handle,
+						  GTlsInteraction          *interaction,
+						  GTlsDatabaseLookupFlags   flags,
+						  GCancellable             *cancellable,
+						  GError                  **error)
+{
+  GTlsDatabaseNss *nss = G_TLS_DATABASE_NSS (database);
+  const gchar *split, *issuer, *serial;
+  CERTIssuerAndSN issuerAndSN;
+  CERTCertificate *cert;
+  GTlsCertificateNss *ret;
+  gsize length;
+
+  if (!g_str_has_prefix (handle, "nss:"))
+    return NULL;
+
+  issuer = handle + 4;
+  split = strchr (issuer, '#');
+  if (!split)
+    return NULL;
+  serial = split + 1;
+
+  issuerAndSN.derIssuer.data = g_base64_decode (issuer, &length);
+  issuerAndSN.derIssuer.len = length;
+
+  issuerAndSN.serialNumber.data = g_base64_decode (serial, &length);
+  issuerAndSN.serialNumber.len = length;
+
+  cert = CERT_FindCertByIssuerAndSN (g_tls_backend_nss_certdbhandle, &issuerAndSN);
+  g_free (issuerAndSN.derIssuer.data);
+  g_free (issuerAndSN.serialNumber.data);
+  if (!cert)
+    return NULL;
+
+  ret = g_tls_database_nss_get_gcert (nss, cert, TRUE);
+  CERT_DestroyCertificate (cert);
+  return G_TLS_CERTIFICATE (ret);
+}
+
+static GTlsCertificate *
+g_tls_database_nss_lookup_certificate_issuer (GTlsDatabase             *database,
+					      GTlsCertificate          *certificate,
+					      GTlsInteraction          *interaction,
+					      GTlsDatabaseLookupFlags   flags,
+					      GCancellable             *cancellable,
+					      GError                  **error)
+{
+  GTlsDatabaseNss *nss = G_TLS_DATABASE_NSS (database);
+  GTlsCertificateNss *cert_nss = G_TLS_CERTIFICATE_NSS (certificate);
+  CERTCertificate *cert, *issuer_cert;
+  GTlsCertificateNss *issuer;
+
+  cert = g_tls_certificate_nss_get_cert (cert_nss);
+  issuer_cert = CERT_FindCertIssuer(cert, PR_Now (),
+				    /* FIXME? Though it seems to not actually
+				     * matter if this is wrong.
+				     */
+				    certUsageSSLServer);
+  if (issuer_cert)
+    {
+      issuer = g_tls_database_nss_get_gcert (nss, issuer_cert, TRUE);
+      CERT_DestroyCertificate (issuer_cert);
+      return G_TLS_CERTIFICATE (issuer);
+    }
+  else
+    return NULL;
+}
+
+static GList *
+g_tls_database_nss_lookup_certificates_issued_by (GTlsDatabase             *database,
+						  GByteArray               *issuer_raw_dn,
+						  GTlsInteraction          *interaction,
+						  GTlsDatabaseLookupFlags   flags,
+						  GCancellable             *cancellable,
+						  GError                  **error)
+{
+  GTlsDatabaseNss *nss = G_TLS_DATABASE_NSS (database);
+  GList *certs;
+  CERTCertNicknames *nicknames;
+  CERTCertificate *cert;
+  SECItem issuerName;
+  int i;
+
+  nicknames = CERT_GetCertNicknames (g_tls_backend_nss_certdbhandle,
+				     SEC_CERT_NICKNAMES_ALL, interaction);
+  if (!nicknames)
+    return NULL;
+
+  certs = NULL;
+  for (i = 0; i < nicknames->numnicknames; i++)
+    {
+      cert = PK11_FindCertFromNickname (nicknames->nicknames[i], interaction);
+      if (!cert)
+	continue;
+
+      if (CERT_IssuerNameFromDERCert (&cert->derCert, &issuerName) == SECSuccess)
+	{
+	  if (issuer_raw_dn->len == issuerName.len &&
+	      memcmp (issuer_raw_dn->data, issuerName.data, issuerName.len) == 0)
+	    certs = g_list_prepend (certs, g_tls_database_nss_get_gcert (nss, cert, TRUE));
+
+	  SECITEM_FreeItem (&issuerName, PR_FALSE);
+	}
+
+      CERT_DestroyCertificate (cert);
+    }
+
+  CERT_FreeNicknames (nicknames);
+  return certs;
+}
+
+static void
+g_tls_database_nss_class_init (GTlsDatabaseNssClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsDatabaseNssPrivate));
+
+  object_class->finalize = g_tls_database_nss_finalize;
+
+  database_class->verify_chain = g_tls_database_nss_verify_chain;
+  database_class->create_certificate_handle = g_tls_database_nss_create_certificate_handle;            
+  database_class->lookup_certificate_for_handle = g_tls_database_nss_lookup_certificate_for_handle;        
+  database_class->lookup_certificate_issuer = g_tls_database_nss_lookup_certificate_issuer;            
+  database_class->lookup_certificates_issued_by = g_tls_database_nss_lookup_certificates_issued_by;        
+}
diff --git a/tls/nss/gtlsdatabase-nss.h b/tls/nss/gtlsdatabase-nss.h
new file mode 100644
index 0000000..ac85e10
--- /dev/null
+++ b/tls/nss/gtlsdatabase-nss.h
@@ -0,0 +1,60 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc..
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_DATABASE_NSS_H__
+#define __G_TLS_DATABASE_NSS_H__
+
+#include <gio/gio.h>
+#include <cert.h>
+
+#include "gtlscertificate-nss.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_DATABASE_NSS            (g_tls_database_nss_get_type ())
+#define G_TLS_DATABASE_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_DATABASE_NSS, GTlsDatabaseNss))
+#define G_TLS_DATABASE_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_DATABASE_NSS, GTlsDatabaseNssClass))
+#define G_IS_TLS_DATABASE_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_DATABASE_NSS))
+#define G_IS_TLS_DATABASE_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_DATABASE_NSS))
+#define G_TLS_DATABASE_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_DATABASE_NSS, GTlsDatabaseNssClass))
+
+typedef struct _GTlsDatabaseNssPrivate                   GTlsDatabaseNssPrivate;
+typedef struct _GTlsDatabaseNssClass                     GTlsDatabaseNssClass;
+typedef struct _GTlsDatabaseNss                          GTlsDatabaseNss;
+
+struct _GTlsDatabaseNssClass
+{
+  GTlsDatabaseClass parent_class;
+
+};
+
+struct _GTlsDatabaseNss
+{
+  GTlsDatabase parent_instance;
+  GTlsDatabaseNssPrivate *priv;
+};
+
+GType g_tls_database_nss_get_type (void) G_GNUC_CONST;
+
+GTlsCertificateNss *g_tls_database_nss_get_gcert       (GTlsDatabaseNss    *nss,
+							CERTCertificate    *cert,
+							gboolean            create);
+void                g_tls_database_nss_gcert_created   (GTlsDatabaseNss    *nss,
+							CERTCertificate    *cert,
+							GTlsCertificateNss *gcert);
+
+void                g_tls_database_nss_gcert_destroyed (GTlsDatabaseNss    *nss,
+							CERTCertificate    *cert);
+
+G_END_DECLS
+
+#endif /* __G_TLS_DATABASE_NSS_H___ */
diff --git a/tls/nss/gtlsfiledatabase-nss.c b/tls/nss/gtlsfiledatabase-nss.c
new file mode 100644
index 0000000..96917cd
--- /dev/null
+++ b/tls/nss/gtlsfiledatabase-nss.c
@@ -0,0 +1,318 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include "gtlsfiledatabase-nss.h"
+#include "gtlsbackend-nss.h"
+
+#include <gio/gio.h>
+#include <glib/gi18n-lib.h>
+#include <nss.h>
+
+/* NSS only has a single global database. The strategy here then is to
+ * remember which certificates we read out of this file, and then when
+ * asked to do some operation, we have the default database do it, and
+ * then filter the results to only the certs in this database.
+ */
+
+/* The handle format is the same as the GNUTLS backend, for no real
+ * reason other than "that's what the regression tests test for". We
+ * could just as easily chain up.
+ */
+
+static void g_tls_file_database_nss_file_database_interface_init (GTlsFileDatabaseInterface *iface);
+
+static void g_tls_file_database_nss_initable_interface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsFileDatabaseNss, g_tls_file_database_nss, G_TYPE_TLS_DATABASE_NSS,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_TLS_FILE_DATABASE,
+                                                g_tls_file_database_nss_file_database_interface_init);
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                g_tls_file_database_nss_initable_interface_init);
+);
+
+enum
+{
+  PROP_0,
+  PROP_ANCHORS,
+};
+
+struct _GTlsFileDatabaseNssPrivate
+{
+  /* read-only after construct */
+  gchar *anchor_filename;
+  GHashTable *certs;
+  GTlsDatabase *default_db;
+
+  GHashTable *hashes, *certs_by_hash;
+};
+
+static void
+g_tls_file_database_nss_init (GTlsFileDatabaseNss *nss)
+{
+  nss->priv = G_TYPE_INSTANCE_GET_PRIVATE (nss,
+					   G_TYPE_TLS_FILE_DATABASE_NSS,
+					   GTlsFileDatabaseNssPrivate);
+  nss->priv->certs = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
+  nss->priv->default_db = G_TLS_DATABASE (g_tls_backend_nss_default_database);
+
+  nss->priv->hashes = g_hash_table_new (NULL, NULL);
+  nss->priv->certs_by_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+						    g_free, NULL);
+}
+
+static void
+g_tls_file_database_nss_finalize (GObject *object)
+{
+  GTlsFileDatabaseNss *nss = G_TLS_FILE_DATABASE_NSS (object);
+
+  if (nss->priv->certs)
+    g_hash_table_destroy (nss->priv->certs);
+  if (nss->priv->hashes)
+    g_hash_table_destroy (nss->priv->hashes);
+  if (nss->priv->certs_by_hash)
+    g_hash_table_destroy (nss->priv->certs_by_hash);
+  g_free (nss->priv->anchor_filename);
+
+  G_OBJECT_CLASS (g_tls_file_database_nss_parent_class)->finalize (object);
+}
+
+static void
+g_tls_file_database_nss_get_property (GObject    *object,
+				      guint       prop_id,
+				      GValue     *value,
+				      GParamSpec *pspec)
+{
+  GTlsFileDatabaseNss *nss = G_TLS_FILE_DATABASE_NSS (object);
+
+  switch (prop_id)
+    {
+    case PROP_ANCHORS:
+      g_value_set_string (value, nss->priv->anchor_filename);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_file_database_nss_set_property (GObject      *object,
+				      guint         prop_id,
+				      const GValue *value,
+				      GParamSpec   *pspec)
+{
+  GTlsFileDatabaseNss *nss = G_TLS_FILE_DATABASE_NSS (object);
+  const gchar *anchor_path;
+
+  switch (prop_id)
+    {
+    case PROP_ANCHORS:
+      anchor_path = g_value_get_string (value);
+      if (anchor_path && !g_path_is_absolute (anchor_path))
+        {
+          g_warning ("The anchor file name for used with a GTlsFileDatabase "
+                     "must be an absolute path, and not relative: %s", anchor_path);
+        }
+      else
+        {
+          nss->priv->anchor_filename = g_strdup (anchor_path);
+        }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static gchar *
+g_tls_file_database_nss_create_certificate_handle (GTlsDatabase    *database,
+						   GTlsCertificate *certificate)
+{
+  GTlsFileDatabaseNss *nss = G_TLS_FILE_DATABASE_NSS (database);
+  const gchar *hash;
+
+  hash = g_strdup (g_hash_table_lookup (nss->priv->hashes, certificate));
+  if (!hash)
+    return NULL;
+
+  return g_strdup_printf ("file://%s#%s", nss->priv->anchor_filename, hash);
+}
+
+static GTlsCertificate *
+g_tls_file_database_nss_lookup_certificate_for_handle (GTlsDatabase            *database,
+						       const gchar             *handle,
+						       GTlsInteraction         *interaction,
+						       GTlsDatabaseLookupFlags  flags,
+						       GCancellable            *cancellable,
+						       GError                 **error)
+{
+  GTlsFileDatabaseNss *nss = G_TLS_FILE_DATABASE_NSS (database);
+  GTlsCertificate *cert;
+
+  if (!g_str_has_prefix (handle, "file://"))
+    return NULL;
+  handle += 7;
+  if (!g_str_has_prefix (handle, nss->priv->anchor_filename))
+    return NULL;
+  handle += strlen (nss->priv->anchor_filename);
+  if (*handle != '#')
+    return NULL;
+  handle++;
+
+  cert = g_hash_table_lookup (nss->priv->certs_by_hash, handle);
+  if (cert)
+    g_object_ref (cert);
+  return cert;
+}
+
+static GTlsCertificate *
+g_tls_file_database_nss_lookup_certificate_issuer (GTlsDatabase             *database,
+						   GTlsCertificate          *certificate,
+						   GTlsInteraction          *interaction,
+						   GTlsDatabaseLookupFlags   flags,
+						   GCancellable             *cancellable,
+						   GError                  **error)
+{
+  GTlsFileDatabaseNss *nss = G_TLS_FILE_DATABASE_NSS (database);
+  GTlsCertificate *issuer;
+
+  issuer = g_tls_database_lookup_certificate_issuer (nss->priv->default_db,
+						     certificate, interaction,
+						     flags, cancellable,
+						     error);
+  if (issuer && g_hash_table_lookup (nss->priv->certs, issuer))
+    return issuer;
+  else if (issuer)
+    g_object_unref (issuer);
+  return NULL;
+}
+
+static GList*
+g_tls_file_database_nss_lookup_certificates_issued_by (GTlsDatabase           *database,
+						       GByteArray             *issuer_raw_dn,
+						       GTlsInteraction        *interaction,
+						       GTlsDatabaseLookupFlags flags,
+						       GCancellable           *cancellable,
+						       GError                **error)
+{
+  GTlsFileDatabaseNss *nss = G_TLS_FILE_DATABASE_NSS (database);
+  GList *certs, *l, *next;
+  GTlsCertificate *cert;
+
+  certs = g_tls_database_lookup_certificates_issued_by (nss->priv->default_db,
+							issuer_raw_dn,
+							interaction, flags,
+							cancellable, error);
+  if (!certs)
+    return NULL;
+
+  for (l = certs; l; l = next)
+    {
+      cert = l->data;
+      next = l->next;
+      if (!g_hash_table_lookup (nss->priv->certs, cert))
+	{
+	  g_object_unref (cert);
+	  certs = g_list_delete_link (certs, l);
+	}
+    }
+
+  return certs;
+}
+
+static void
+g_tls_file_database_nss_class_init (GTlsFileDatabaseNssClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsFileDatabaseNssPrivate));
+
+  gobject_class->get_property = g_tls_file_database_nss_get_property;
+  gobject_class->set_property = g_tls_file_database_nss_set_property;
+  gobject_class->finalize     = g_tls_file_database_nss_finalize;
+
+  database_class->create_certificate_handle = g_tls_file_database_nss_create_certificate_handle;
+  database_class->lookup_certificate_for_handle = g_tls_file_database_nss_lookup_certificate_for_handle;
+  database_class->lookup_certificate_issuer = g_tls_file_database_nss_lookup_certificate_issuer;
+  database_class->lookup_certificates_issued_by = g_tls_file_database_nss_lookup_certificates_issued_by;
+
+  g_object_class_override_property (gobject_class, PROP_ANCHORS, "anchors");
+}
+
+static void
+g_tls_file_database_nss_file_database_interface_init (GTlsFileDatabaseInterface *iface)
+{
+
+}
+
+static gboolean
+g_tls_file_database_nss_initable_init (GInitable     *initable,
+				       GCancellable  *cancellable,
+				       GError       **error)
+{
+  GTlsFileDatabaseNss *nss = G_TLS_FILE_DATABASE_NSS (initable);
+  GError *my_error = NULL;
+  GList *certs, *c;
+
+  if (!nss->priv->anchor_filename)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+		   _("No certificate database filename specified"));
+      return FALSE;
+    }
+
+  certs = g_tls_certificate_list_new_from_file (nss->priv->anchor_filename,
+						&my_error);
+  if (my_error)
+    {
+      g_propagate_error (error, my_error);
+      return FALSE;
+    }
+
+  for (c = certs; c; c = c->next)
+    {
+      GTlsCertificateNss *nss_cert = c->data;
+      CERTCertificate *cert = g_tls_certificate_nss_get_cert (nss_cert);
+      gchar *hash = g_compute_checksum_for_data (G_CHECKSUM_SHA256,
+						 cert->derCert.data,
+						 cert->derCert.len);
+
+      g_hash_table_insert (nss->priv->certs, nss_cert, nss_cert);
+      g_hash_table_insert (nss->priv->certs_by_hash, hash, nss_cert);
+      g_hash_table_insert (nss->priv->hashes, nss_cert, hash);
+    }
+  g_list_free (certs);
+
+  return TRUE;
+}
+
+static void
+g_tls_file_database_nss_initable_interface_init (GInitableIface *iface)
+{
+  iface->init = g_tls_file_database_nss_initable_init;
+}
+
+gboolean
+g_tls_file_database_nss_contains (GTlsFileDatabaseNss *nss,
+				  GTlsCertificateNss  *nss_cert)
+{
+  return g_hash_table_lookup (nss->priv->certs, nss_cert) == nss_cert;
+}
diff --git a/tls/nss/gtlsfiledatabase-nss.h b/tls/nss/gtlsfiledatabase-nss.h
new file mode 100644
index 0000000..8139864
--- /dev/null
+++ b/tls/nss/gtlsfiledatabase-nss.h
@@ -0,0 +1,51 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_FILE_DATABASE_NSS_H__
+#define __G_TLS_FILE_DATABASE_NSS_H__
+
+#include <gio/gio.h>
+
+#include "gtlsdatabase-nss.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_FILE_DATABASE_NSS            (g_tls_file_database_nss_get_type ())
+#define G_TLS_FILE_DATABASE_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_FILE_DATABASE_NSS, GTlsFileDatabaseNss))
+#define G_TLS_FILE_DATABASE_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_FILE_DATABASE_NSS, GTlsFileDatabaseNssClass))
+#define G_IS_TLS_FILE_DATABASE_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_FILE_DATABASE_NSS))
+#define G_IS_TLS_FILE_DATABASE_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_FILE_DATABASE_NSS))
+#define G_TLS_FILE_DATABASE_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_FILE_DATABASE_NSS, GTlsFileDatabaseNssClass))
+
+typedef struct _GTlsFileDatabaseNssPrivate                   GTlsFileDatabaseNssPrivate;
+typedef struct _GTlsFileDatabaseNssClass                     GTlsFileDatabaseNssClass;
+typedef struct _GTlsFileDatabaseNss                          GTlsFileDatabaseNss;
+
+struct _GTlsFileDatabaseNssClass
+{
+  GTlsDatabaseNssClass parent_class;
+};
+
+struct _GTlsFileDatabaseNss
+{
+  GTlsDatabaseNss parent_instance;
+  GTlsFileDatabaseNssPrivate *priv;
+};
+
+GType g_tls_file_database_nss_get_type (void) G_GNUC_CONST;
+
+gboolean g_tls_file_database_nss_contains (GTlsFileDatabaseNss *nss,
+					   GTlsCertificateNss  *nss_cert);
+
+G_END_DECLS
+
+#endif /* __G_TLS_FILE_DATABASE_NSS_H___ */
diff --git a/tls/nss/gtlsinputstream-nss.c b/tls/nss/gtlsinputstream-nss.c
new file mode 100644
index 0000000..75ce952
--- /dev/null
+++ b/tls/nss/gtlsinputstream-nss.c
@@ -0,0 +1,147 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "gtlsinputstream-nss.h"
+
+static void g_tls_input_stream_nss_pollable_iface_init (GPollableInputStreamInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsInputStreamNss, g_tls_input_stream_nss, G_TYPE_INPUT_STREAM,
+			 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, g_tls_input_stream_nss_pollable_iface_init)
+			 )
+
+struct _GTlsInputStreamNssPrivate
+{
+  GTlsConnectionNss *conn;
+
+  /* pending operation metadata */
+  GCancellable *cancellable;
+  gpointer buffer;
+  gsize count;
+};
+
+static void
+g_tls_input_stream_nss_dispose (GObject *object)
+{
+  GTlsInputStreamNss *stream = G_TLS_INPUT_STREAM_NSS (object);
+
+  if (stream->priv->conn)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (stream->priv->conn),
+				    (gpointer *)&stream->priv->conn);
+      stream->priv->conn = NULL;
+    }
+
+  G_OBJECT_CLASS (g_tls_input_stream_nss_parent_class)->dispose (object);
+}
+
+static gssize
+g_tls_input_stream_nss_read (GInputStream  *stream,
+			     void          *buffer,
+			     gsize          count,
+			     GCancellable  *cancellable,
+			     GError       **error)
+{
+  g_return_val_if_reached (-1);
+}
+
+static void
+g_tls_input_stream_nss_read_async (GInputStream        *stream,
+				   void                *buffer,
+				   gsize                count,
+				   gint                 io_priority,
+				   GCancellable        *cancellable,
+				   GAsyncReadyCallback  callback,
+				   gpointer             user_data)
+{
+  g_return_if_reached ();
+}
+
+static gssize
+g_tls_input_stream_nss_read_finish (GInputStream  *stream,
+				       GAsyncResult  *result,
+				       GError       **error)
+{
+  g_return_val_if_reached (-1);
+}
+
+static gboolean
+g_tls_input_stream_nss_pollable_is_readable (GPollableInputStream *pollable)
+{
+  g_return_val_if_reached (FALSE);
+}
+
+static GSource *
+g_tls_input_stream_nss_pollable_create_source (GPollableInputStream *pollable,
+					       GCancellable         *cancellable)
+{
+  g_return_val_if_reached (NULL);
+}
+
+static gssize
+g_tls_input_stream_nss_pollable_read_nonblocking (GPollableInputStream  *pollable,
+						  void                  *buffer,
+						  gsize                  size,
+						  GError               **error)
+{
+  g_return_val_if_reached (-1);
+}
+
+static void
+g_tls_input_stream_nss_class_init (GTlsInputStreamNssClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsInputStreamNssPrivate));
+
+  gobject_class->dispose = g_tls_input_stream_nss_dispose;
+
+  input_stream_class->read_fn = g_tls_input_stream_nss_read;
+  input_stream_class->read_async = g_tls_input_stream_nss_read_async;
+  input_stream_class->read_finish = g_tls_input_stream_nss_read_finish;
+}
+
+static void
+g_tls_input_stream_nss_pollable_iface_init (GPollableInputStreamInterface *iface)
+{
+  iface->is_readable = g_tls_input_stream_nss_pollable_is_readable;
+  iface->create_source = g_tls_input_stream_nss_pollable_create_source;
+  iface->read_nonblocking = g_tls_input_stream_nss_pollable_read_nonblocking;
+}
+
+static void
+g_tls_input_stream_nss_init (GTlsInputStreamNss *stream)
+{
+  stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_TLS_INPUT_STREAM_NSS, GTlsInputStreamNssPrivate);
+}
+
+GInputStream *
+g_tls_input_stream_nss_new (GTlsConnectionNss *conn)
+{
+  GTlsInputStreamNss *tls_stream;
+
+  tls_stream = g_object_new (G_TYPE_TLS_INPUT_STREAM_NSS, NULL);
+  tls_stream->priv->conn = conn;
+  g_object_add_weak_pointer (G_OBJECT (conn),
+			     (gpointer *)&tls_stream->priv->conn);
+
+  return G_INPUT_STREAM (tls_stream);
+}
diff --git a/tls/nss/gtlsinputstream-nss.h b/tls/nss/gtlsinputstream-nss.h
new file mode 100644
index 0000000..a1edb5d
--- /dev/null
+++ b/tls/nss/gtlsinputstream-nss.h
@@ -0,0 +1,48 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_INPUT_STREAM_NSS_H__
+#define __G_TLS_INPUT_STREAM_NSS_H__
+
+#include <gio/gio.h>
+#include "gtlsconnection-nss.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_INPUT_STREAM_NSS            (g_tls_input_stream_nss_get_type ())
+#define G_TLS_INPUT_STREAM_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_INPUT_STREAM_NSS, GTlsInputStreamNss))
+#define G_TLS_INPUT_STREAM_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_INPUT_STREAM_NSS, GTlsInputStreamNssClass))
+#define G_IS_TLS_INPUT_STREAM_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_INPUT_STREAM_NSS))
+#define G_IS_TLS_INPUT_STREAM_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_INPUT_STREAM_NSS))
+#define G_TLS_INPUT_STREAM_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_INPUT_STREAM_NSS, GTlsInputStreamNssClass))
+
+typedef struct _GTlsInputStreamNssPrivate GTlsInputStreamNssPrivate;
+typedef struct _GTlsInputStreamNssClass   GTlsInputStreamNssClass;
+typedef struct _GTlsInputStreamNss        GTlsInputStreamNss;
+
+struct _GTlsInputStreamNssClass
+{
+  GInputStreamClass parent_class;
+};
+
+struct _GTlsInputStreamNss
+{
+  GInputStream parent_instance;
+  GTlsInputStreamNssPrivate *priv;
+};
+
+GType         g_tls_input_stream_nss_get_type (void) G_GNUC_CONST;
+GInputStream *g_tls_input_stream_nss_new      (GTlsConnectionNss *conn);
+
+G_END_DECLS
+
+#endif /* __G_TLS_INPUT_STREAM_NSS_H___ */
diff --git a/tls/nss/gtlsoutputstream-nss.c b/tls/nss/gtlsoutputstream-nss.c
new file mode 100644
index 0000000..8c1b7aa
--- /dev/null
+++ b/tls/nss/gtlsoutputstream-nss.c
@@ -0,0 +1,147 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "gtlsoutputstream-nss.h"
+
+static void g_tls_output_stream_nss_pollable_iface_init (GPollableOutputStreamInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsOutputStreamNss, g_tls_output_stream_nss, G_TYPE_OUTPUT_STREAM,
+			 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, g_tls_output_stream_nss_pollable_iface_init)
+			 )
+
+struct _GTlsOutputStreamNssPrivate
+{
+  GTlsConnectionNss *conn;
+
+  /* pending operation metadata */
+  GCancellable *cancellable;
+  gconstpointer buffer;
+  gsize count;
+};
+
+static void
+g_tls_output_stream_nss_dispose (GObject *object)
+{
+  GTlsOutputStreamNss *stream = G_TLS_OUTPUT_STREAM_NSS (object);
+
+  if (stream->priv->conn)
+    {
+      g_object_remove_weak_pointer (G_OBJECT (stream->priv->conn),
+				    (gpointer *)&stream->priv->conn);
+      stream->priv->conn = NULL;
+    }
+
+  G_OBJECT_CLASS (g_tls_output_stream_nss_parent_class)->dispose (object);
+}
+
+static gssize
+g_tls_output_stream_nss_write (GOutputStream  *stream,
+			       const void     *buffer,
+			       gsize           count,
+			       GCancellable   *cancellable,
+			       GError        **error)
+{
+  g_return_val_if_reached (-1);
+}
+
+static void
+g_tls_output_stream_nss_write_async (GOutputStream        *stream,
+				     const void           *buffer,
+				     gsize                 count,
+				     gint                  io_priority,
+				     GCancellable         *cancellable,
+				     GAsyncReadyCallback   callback,
+				     gpointer              user_data)
+{
+  g_return_if_reached ();
+}
+
+static gssize
+g_tls_output_stream_nss_write_finish (GOutputStream  *stream,
+				      GAsyncResult   *result,
+				      GError        **error)
+{
+  g_return_val_if_reached (-1);
+}
+
+static gboolean
+g_tls_output_stream_nss_pollable_is_writable (GPollableOutputStream *pollable)
+{
+  g_return_val_if_reached (FALSE);
+}
+
+static GSource *
+g_tls_output_stream_nss_pollable_create_source (GPollableOutputStream *pollable,
+						GCancellable         *cancellable)
+{
+  g_return_val_if_reached (NULL);
+}
+
+static gssize
+g_tls_output_stream_nss_pollable_write_nonblocking (GPollableOutputStream  *pollable,
+						    const void             *buffer,
+						    gsize                   size,
+						    GError                **error)
+{
+  g_return_val_if_reached (-1);
+}
+
+static void
+g_tls_output_stream_nss_class_init (GTlsOutputStreamNssClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsOutputStreamNssPrivate));
+
+  gobject_class->dispose = g_tls_output_stream_nss_dispose;
+
+  output_stream_class->write_fn = g_tls_output_stream_nss_write;
+  output_stream_class->write_async = g_tls_output_stream_nss_write_async;
+  output_stream_class->write_finish = g_tls_output_stream_nss_write_finish;
+}
+
+static void
+g_tls_output_stream_nss_pollable_iface_init (GPollableOutputStreamInterface *iface)
+{
+  iface->is_writable = g_tls_output_stream_nss_pollable_is_writable;
+  iface->create_source = g_tls_output_stream_nss_pollable_create_source;
+  iface->write_nonblocking = g_tls_output_stream_nss_pollable_write_nonblocking;
+}
+
+static void
+g_tls_output_stream_nss_init (GTlsOutputStreamNss *stream)
+{
+  stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_TLS_OUTPUT_STREAM_NSS, GTlsOutputStreamNssPrivate);
+}
+
+GOutputStream *
+g_tls_output_stream_nss_new (GTlsConnectionNss *conn)
+{
+  GTlsOutputStreamNss *tls_stream;
+
+  tls_stream = g_object_new (G_TYPE_TLS_OUTPUT_STREAM_NSS, NULL);
+  tls_stream->priv->conn = conn;
+  g_object_add_weak_pointer (G_OBJECT (conn),
+			     (gpointer *)&tls_stream->priv->conn);
+
+  return G_OUTPUT_STREAM (tls_stream);
+}
diff --git a/tls/nss/gtlsoutputstream-nss.h b/tls/nss/gtlsoutputstream-nss.h
new file mode 100644
index 0000000..9f56e0f
--- /dev/null
+++ b/tls/nss/gtlsoutputstream-nss.h
@@ -0,0 +1,48 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_OUTPUT_STREAM_NSS_H__
+#define __G_TLS_OUTPUT_STREAM_NSS_H__
+
+#include <gio/gio.h>
+#include "gtlsconnection-nss.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_OUTPUT_STREAM_NSS            (g_tls_output_stream_nss_get_type ())
+#define G_TLS_OUTPUT_STREAM_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_OUTPUT_STREAM_NSS, GTlsOutputStreamNss))
+#define G_TLS_OUTPUT_STREAM_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_OUTPUT_STREAM_NSS, GTlsOutputStreamNssClass))
+#define G_IS_TLS_OUTPUT_STREAM_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_OUTPUT_STREAM_NSS))
+#define G_IS_TLS_OUTPUT_STREAM_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_OUTPUT_STREAM_NSS))
+#define G_TLS_OUTPUT_STREAM_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_OUTPUT_STREAM_NSS, GTlsOutputStreamNssClass))
+
+typedef struct _GTlsOutputStreamNssPrivate GTlsOutputStreamNssPrivate;
+typedef struct _GTlsOutputStreamNssClass   GTlsOutputStreamNssClass;
+typedef struct _GTlsOutputStreamNss        GTlsOutputStreamNss;
+
+struct _GTlsOutputStreamNssClass
+{
+  GOutputStreamClass parent_class;
+};
+
+struct _GTlsOutputStreamNss
+{
+  GOutputStream parent_instance;
+  GTlsOutputStreamNssPrivate *priv;
+};
+
+GType          g_tls_output_stream_nss_get_type (void) G_GNUC_CONST;
+GOutputStream *g_tls_output_stream_nss_new      (GTlsConnectionNss *conn);
+
+G_END_DECLS
+
+#endif /* __G_TLS_OUTPUT_STREAM_NSS_H___ */
diff --git a/tls/nss/gtlsserverconnection-nss.c b/tls/nss/gtlsserverconnection-nss.c
new file mode 100644
index 0000000..db7417c
--- /dev/null
+++ b/tls/nss/gtlsserverconnection-nss.c
@@ -0,0 +1,105 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include <glib.h>
+
+#include "gtlsserverconnection-nss.h"
+#include <glib/gi18n-lib.h>
+
+enum
+{
+  PROP_0,
+  PROP_AUTHENTICATION_MODE
+};
+
+static void g_tls_server_connection_nss_server_connection_interface_init (GTlsServerConnectionInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsServerConnectionNss, g_tls_server_connection_nss, G_TYPE_TLS_CONNECTION_NSS,
+			 G_IMPLEMENT_INTERFACE (G_TYPE_TLS_SERVER_CONNECTION,
+						g_tls_server_connection_nss_server_connection_interface_init))
+
+struct _GTlsServerConnectionNssPrivate
+{
+  GTlsAuthenticationMode authentication_mode;
+};
+
+static void
+g_tls_server_connection_nss_init (GTlsServerConnectionNss *nss)
+{
+  nss->priv = G_TYPE_INSTANCE_GET_PRIVATE (nss, G_TYPE_TLS_SERVER_CONNECTION_NSS, GTlsServerConnectionNssPrivate);
+}
+
+static void
+g_tls_server_connection_nss_get_property (GObject    *object,
+					  guint       prop_id,
+					  GValue     *value,
+					  GParamSpec *pspec)
+{
+  GTlsServerConnectionNss *nss = G_TLS_SERVER_CONNECTION_NSS (object);
+
+  switch (prop_id)
+    {
+    case PROP_AUTHENTICATION_MODE:
+      g_value_set_enum (value, nss->priv->authentication_mode);
+      break;
+      
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_server_connection_nss_set_property (GObject      *object,
+					  guint         prop_id,
+					  const GValue *value,
+					  GParamSpec   *pspec)
+{
+  GTlsServerConnectionNss *nss = G_TLS_SERVER_CONNECTION_NSS (object);
+
+  switch (prop_id)
+    {
+    case PROP_AUTHENTICATION_MODE:
+      nss->priv->authentication_mode = g_value_get_enum (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_server_connection_nss_class_init (GTlsServerConnectionNssClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GTlsServerConnectionNssPrivate));
+
+  gobject_class->get_property = g_tls_server_connection_nss_get_property;
+  gobject_class->set_property = g_tls_server_connection_nss_set_property;
+
+  g_object_class_override_property (gobject_class, PROP_AUTHENTICATION_MODE, "authentication-mode");
+}
+
+static void
+g_tls_server_connection_nss_server_connection_interface_init (GTlsServerConnectionInterface *iface)
+{
+}
+
diff --git a/tls/nss/gtlsserverconnection-nss.h b/tls/nss/gtlsserverconnection-nss.h
new file mode 100644
index 0000000..6da6a86
--- /dev/null
+++ b/tls/nss/gtlsserverconnection-nss.h
@@ -0,0 +1,47 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __G_TLS_SERVER_CONNECTION_NSS_H__
+#define __G_TLS_SERVER_CONNECTION_NSS_H__
+
+#include <gio/gio.h> 
+#include "gtlsconnection-nss.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_SERVER_CONNECTION_NSS            (g_tls_server_connection_nss_get_type ())
+#define G_TLS_SERVER_CONNECTION_NSS(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_SERVER_CONNECTION_NSS, GTlsServerConnectionNss))
+#define G_TLS_SERVER_CONNECTION_NSS_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_SERVER_CONNECTION_NSS, GTlsServerConnectionNssClass))
+#define G_IS_TLS_SERVER_CONNECTION_NSS(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_SERVER_CONNECTION_NSS))
+#define G_IS_TLS_SERVER_CONNECTION_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_SERVER_CONNECTION_NSS))
+#define G_TLS_SERVER_CONNECTION_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_SERVER_CONNECTION_NSS, GTlsServerConnectionNssClass))
+
+typedef struct _GTlsServerConnectionNssPrivate                   GTlsServerConnectionNssPrivate;
+typedef struct _GTlsServerConnectionNssClass                     GTlsServerConnectionNssClass;
+typedef struct _GTlsServerConnectionNss                          GTlsServerConnectionNss;
+
+struct _GTlsServerConnectionNssClass
+{
+  GTlsConnectionNssClass parent_class;
+};
+
+struct _GTlsServerConnectionNss
+{
+  GTlsConnectionNss parent_instance;
+  GTlsServerConnectionNssPrivate *priv;
+};
+
+GType g_tls_server_connection_nss_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_TLS_SERVER_CONNECTION_NSS_H___ */
diff --git a/tls/nss/nss-module.c b/tls/nss/nss-module.c
new file mode 100644
index 0000000..a1c36d2
--- /dev/null
+++ b/tls/nss/nss-module.c
@@ -0,0 +1,47 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+
+#include "gtlsbackend-nss.h"
+
+
+void
+g_io_module_load (GIOModule *module)
+{
+  g_tls_backend_nss_register (module);
+}
+
+void
+g_io_module_unload (GIOModule *module)
+{
+}
+
+gchar **
+g_io_module_query (void)
+{
+  gchar *eps[] = {
+    G_TLS_BACKEND_EXTENSION_POINT_NAME,
+    NULL
+  };
+  return g_strdupv (eps);
+}
diff --git a/tls/tests/Makefile.am b/tls/tests/Makefile.am
index eff0570..daa95de 100644
--- a/tls/tests/Makefile.am
+++ b/tls/tests/Makefile.am
@@ -10,11 +10,25 @@ noinst_PROGRAMS = $(TEST_PROGS)
 LDADD  = \
 	$(GLIB_LIBS)
 
-TEST_PROGS +=		\
-	certificate	\
-	connection	\
+TEST_PROGS +=			\
+	certificate-gnutls	\
+	certificate-nss		\
+	connection-gnutls	\
+	connection-nss		\
 	$(NULL)
 
+certificate_gnutls_SOURCES = certificate.c
+certificate_gnutls_CPPFLAGS = -DBACKEND=\""gnutls"\"
+
+connection_gnutls_SOURCES = connection.c
+connection_gnutls_CPPFLAGS = -DBACKEND=\""gnutls"\"
+
+certificate_nss_SOURCES = certificate.c
+certificate_nss_CPPFLAGS = -DBACKEND=\""nss"\"
+
+connection_nss_SOURCES = connection.c
+connection_nss_CPPFLAGS = -DBACKEND=\""nss"\"
+
 EXTRA_DIST += \
 	files \
 	$(NULL)
diff --git a/tls/tests/certificate.c b/tls/tests/certificate.c
index 79e65e9..a082cac 100644
--- a/tls/tests/certificate.c
+++ b/tls/tests/certificate.c
@@ -63,15 +63,28 @@ static void
 test_create_destroy_certificate_pem (TestCertificate *test, gconstpointer data)
 {
   GTlsCertificate *cert;
-  gchar *pem = NULL;
+  gchar *pem = NULL, *test_pem_clean, *cert_pem_clean;
   GError *error = NULL;
+  GRegex *re;
 
   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_assert (pem != NULL);
+
+  /* It's OK if they differ in the placement of newlines */
+  re = g_regex_new ("\n", 0, 0, &error);
+  g_assert_no_error (error);
+  test_pem_clean = g_regex_replace_literal (re, test->pem, -1, 0, "", 0, &error);
+  g_assert_no_error (error);
+  cert_pem_clean = g_regex_replace_literal (re, pem, -1, 0, "", 0, &error);
+  g_assert_no_error (error);
+
+  g_assert_cmpstr (cert_pem_clean, ==, test_pem_clean);
+  g_free (test_pem_clean);
+  g_free (cert_pem_clean);
   g_free (pem);
 
   g_object_add_weak_pointer (G_OBJECT (cert), (gpointer *)&cert);
@@ -175,6 +188,12 @@ static void
 teardown_verify (TestVerify      *test,
                  gconstpointer    data)
 {
+  g_assert (G_IS_TLS_DATABASE (test->database));
+  g_object_add_weak_pointer (G_OBJECT (test->database),
+			     (gpointer *)&test->database);
+  g_object_unref (test->database);
+  g_assert (test->database == NULL);
+
   g_assert (G_IS_TLS_CERTIFICATE (test->cert));
   g_object_add_weak_pointer (G_OBJECT (test->cert),
 			     (gpointer *)&test->cert);
@@ -187,12 +206,6 @@ teardown_verify (TestVerify      *test,
   g_object_unref (test->anchor);
   g_assert (test->anchor == NULL);
 
-  g_assert (G_IS_TLS_DATABASE (test->database));
-  g_object_add_weak_pointer (G_OBJECT (test->database),
-			     (gpointer *)&test->database);
-  g_object_unref (test->database);
-  g_assert (test->database == NULL);
-
   g_object_add_weak_pointer (G_OBJECT (test->identity),
 			     (gpointer *)&test->identity);
   g_object_unref (test->identity);
@@ -566,8 +579,9 @@ main (int   argc,
   g_type_init ();
   g_test_init (&argc, &argv, NULL);
 
-  g_setenv ("GIO_EXTRA_MODULES", TOP_BUILDDIR "/tls/gnutls/.libs", TRUE);
-  g_setenv ("GIO_USE_TLS", "gnutls", TRUE);
+  g_setenv ("GIO_EXTRA_MODULES", TOP_BUILDDIR "/tls/" BACKEND "/.libs", TRUE);
+  g_setenv ("GIO_USE_TLS", BACKEND, TRUE);
+  g_assert (g_ascii_strcasecmp (G_OBJECT_TYPE_NAME (g_tls_backend_get_default ()), "GTlsBackend" BACKEND) == 0);
 
   g_test_add_func ("/tls/backend/default-database-is-singleton",
                    test_default_database_is_singleton);
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index 1edc7ad..ede441a 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -492,8 +492,9 @@ main (int   argc,
   g_type_init ();
   g_test_init (&argc, &argv, NULL);
 
-  g_setenv ("GIO_EXTRA_MODULES", TOP_BUILDDIR "/tls/gnutls/.libs", TRUE);
-  g_setenv ("GIO_USE_TLS", "gnutls", TRUE);
+  g_setenv ("GIO_EXTRA_MODULES", TOP_BUILDDIR "/tls/" BACKEND "/.libs", TRUE);
+  g_setenv ("GIO_USE_TLS", BACKEND, TRUE);
+  g_assert (g_ascii_strcasecmp (G_OBJECT_TYPE_NAME (g_tls_backend_get_default ()), "GTlsBackend" BACKEND) == 0);
 
   g_test_add ("/tls/connection/basic", TestConnection, NULL,
               setup_connection, test_basic_connection, teardown_connection);



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