[glib-networking/wip/openssl: 4/8] Add openssl module



commit bece294c4163e73edf8c09173414bba56c843dc8
Author: Ignacio Casal Quinteiro <icq gnome org>
Date:   Thu Aug 13 08:57:55 2015 +0200

    Add openssl module
    
    This patch also contains fixes from Fan Chun-wei.

 Makefile.am                                |    4 +
 configure.ac                               |   24 +-
 po/POTFILES.in                             |    4 +
 tls/openssl/Makefile.am                    |   37 ++
 tls/openssl/gtlsbackend-openssl.c          |  264 ++++++++
 tls/openssl/gtlsbackend-openssl.h          |   48 ++
 tls/openssl/gtlsbio.c                      |  296 +++++++++
 tls/openssl/gtlsbio.h                      |   55 ++
 tls/openssl/gtlscertificate-openssl.c      |  701 +++++++++++++++++++++
 tls/openssl/gtlscertificate-openssl.h      |   69 +++
 tls/openssl/gtlsclientconnection-openssl.c |  491 +++++++++++++++
 tls/openssl/gtlsclientconnection-openssl.h |   56 ++
 tls/openssl/gtlsconnection-openssl.c       |  581 ++++++++++++++++++
 tls/openssl/gtlsconnection-openssl.h       |   68 ++
 tls/openssl/gtlsdatabase-openssl.c         |   39 ++
 tls/openssl/gtlsdatabase-openssl.h         |   63 ++
 tls/openssl/gtlsfiledatabase-openssl.c     |  916 ++++++++++++++++++++++++++++
 tls/openssl/gtlsfiledatabase-openssl.h     |   64 ++
 tls/openssl/gtlsserverconnection-openssl.c |  316 ++++++++++
 tls/openssl/gtlsserverconnection-openssl.h |   57 ++
 tls/openssl/openssl-module.c               |   69 +++
 tls/openssl/openssl-util.c                 |  487 +++++++++++++++
 tls/openssl/openssl-util.h                 |   99 +++
 tls/tests/Makefile.am                      |   21 +
 tls/tests/connection.c                     |   12 +
 25 files changed, 4839 insertions(+), 2 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index d5ec8c8..0ac5673 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,6 +25,10 @@ if HAVE_GNUTLS
 SUBDIRS += tls/gnutls
 endif
 
+if HAVE_OPENSSL
+SUBDIRS += tls/openssl
+endif
+
 if HAVE_TLS
 SUBDIRS += tls/tests
 endif
diff --git a/configure.ac b/configure.ac
index 0d031df..48e5376 100644
--- a/configure.ac
+++ b/configure.ac
@@ -157,10 +157,29 @@ AM_CONDITIONAL(HAVE_PKCS11, [test "$with_pkcs11" = "yes"])
 AC_SUBST(PKCS11_CFLAGS)
 AC_SUBST(PKCS11_LIBS)
 
+dnl **************************
+dnl *** Checks for OpenSSL ***
+dnl **************************
+
+AC_ARG_WITH(openssl,
+    [AC_HELP_STRING([--with-openssl],
+                    [support for OpenSSL @<:@default=check@:>@])],
+                    [],
+                    [with_openssl=check])
+AS_IF([test "$with_openssl" != "no"],
+      [PKG_CHECK_MODULES(OPENSSL, [openssl],
+                         [with_openssl=yes
+                          tls_support="openssl $tls_support"],
+                         [AS_IF([test "x$with_openssl" = "xyes"],
+                                [AC_MSG_FAILURE("$OPENSSL_PKG_ERRORS")])])])
+AM_CONDITIONAL(HAVE_OPENSSL, [test "$with_openssl" = "yes"])
+AC_SUBST(OPENSSL_CFLAGS)
+AC_SUBST(OPENSSL_LIBS)
+
 dnl ***********************************
 dnl *** Do we have any TLS backend? ***
 dnl ***********************************
-AM_CONDITIONAL(HAVE_TLS, [test "$with_gnutls" = "yes"])
+AM_CONDITIONAL(HAVE_TLS, [test "$with_gnutls" = "yes" -o "$with_openssl" = "yes"])
 
 dnl ************************************
 dnl *** Enable lcov coverage reports ***
@@ -248,6 +267,7 @@ AC_CONFIG_FILES([Makefile
                  proxy/tests/Makefile
                  tls/base/Makefile
                  tls/gnutls/Makefile
+                 tls/openssl/Makefile
                  tls/pkcs11/Makefile
                  tls/tests/Makefile
                 ])
@@ -256,7 +276,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" != "no"; then
     echo "  PKCS#11 Support:   $pkcs11_support"
     echo "  TLS CA file:       ${with_ca_certificates:-(none)}"
     if test "x$with_ca_certificates" != xno -a -n "$with_ca_certificates"; then
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5608e05..aded13c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -4,5 +4,9 @@ tls/gnutls/gtlscertificate-gnutls.c
 tls/gnutls/gtlsclientconnection-gnutls.c
 tls/gnutls/gtlsconnection-gnutls.c
 tls/gnutls/gtlsserverconnection-gnutls.c
+tls/openssl/gtlscertificate-openssl.c
+tls/openssl/gtlsclientconnection-openssl.c
+tls/openssl/gtlsconnection-openssl.c
+tls/openssl/gtlsserverconnection-openssl.c
 tls/pkcs11/gpkcs11pin.c
 tls/pkcs11/gpkcs11slot.c
diff --git a/tls/openssl/Makefile.am b/tls/openssl/Makefile.am
new file mode 100644
index 0000000..2636029
--- /dev/null
+++ b/tls/openssl/Makefile.am
@@ -0,0 +1,37 @@
+include $(top_srcdir)/glib-networking.mk
+
+giomodule_LTLIBRARIES = libgioopenssl.la
+
+libgioopenssl_la_SOURCES =             \
+       openssl-module.c                \
+       gtlsbackend-openssl.h           \
+       gtlsbackend-openssl.c           \
+       gtlscertificate-openssl.h       \
+       gtlscertificate-openssl.c       \
+       gtlsconnection-openssl.h        \
+       gtlsconnection-openssl.c        \
+       gtlsserverconnection-openssl.h  \
+       gtlsserverconnection-openssl.c  \
+       gtlsclientconnection-openssl.h  \
+       gtlsclientconnection-openssl.c  \
+       gtlsdatabase-openssl.h          \
+       gtlsdatabase-openssl.c          \
+       gtlsfiledatabase-openssl.h      \
+       gtlsfiledatabase-openssl.c      \
+       gtlsbio.h                       \
+       gtlsbio.c                       \
+       openssl-util.h                  \
+       openssl-util.c                  \
+       $(NULL)
+
+AM_CPPFLAGS +=                         \
+       -I$(top_srcdir)/tls/base        \
+       $(OPENSSL_CFLAGS)               \
+       $(NULL)
+
+libgioopenssl_la_LDFLAGS = $(module_flags)
+libgioopenssl_la_LIBADD =              \
+       ../base/libtlsbase.la           \
+       $(GLIB_LIBS)                    \
+       $(OPENSSL_LIBS)                 \
+       $(NULL)
diff --git a/tls/openssl/gtlsbackend-openssl.c b/tls/openssl/gtlsbackend-openssl.c
new file mode 100644
index 0000000..79a6d47
--- /dev/null
+++ b/tls/openssl/gtlsbackend-openssl.c
@@ -0,0 +1,264 @@
+/*
+ * gtlsbackend-openssl.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "config.h"
+#include "glib.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <openssl/ssl.h>
+#include <openssl/crypto.h>
+
+#include "gtlsbackend-openssl.h"
+#include "gtlscertificate-openssl.h"
+#include "gtlsserverconnection-openssl.h"
+#include "gtlsclientconnection-openssl.h"
+#include "gtlsfiledatabase-openssl.h"
+
+typedef struct _GTlsBackendOpensslPrivate
+{
+  GMutex mutex;
+  GTlsDatabase *default_database;
+} GTlsBackendOpensslPrivate;
+
+static void g_tls_backend_openssl_interface_init (GTlsBackendInterface *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendOpenssl, g_tls_backend_openssl, G_TYPE_OBJECT, 0,
+                                G_ADD_PRIVATE_DYNAMIC (GTlsBackendOpenssl)
+                                G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
+                                                               g_tls_backend_openssl_interface_init))
+
+static GMutex *mutex_array = NULL;
+
+struct CRYPTO_dynlock_value {
+  GMutex mutex;
+};
+
+static unsigned long
+id_cb (void)
+{
+  return (unsigned long) g_thread_self ();
+}
+
+static void
+locking_cb (int         mode,
+            int         n,
+            const char *file,
+            int         line)
+{
+  if (mode & CRYPTO_LOCK)
+    g_mutex_lock (&mutex_array[n]);
+  else
+    g_mutex_unlock (&mutex_array[n]);
+}
+
+static struct CRYPTO_dynlock_value *
+dyn_create_cb (const char *file,
+               int         line)
+{
+  struct CRYPTO_dynlock_value *value = g_try_new (struct CRYPTO_dynlock_value, 1);
+
+  if (value)
+    g_mutex_init (&value->mutex);
+
+  return value;
+}
+
+static void
+dyn_lock_cb (int                          mode,
+             struct CRYPTO_dynlock_value *l,
+             const char                  *file,
+             int                          line)
+{
+  if (mode & CRYPTO_LOCK)
+    g_mutex_lock (&l->mutex);
+  else
+    g_mutex_unlock (&l->mutex);
+}
+
+static void
+dyn_destroy_cb (struct CRYPTO_dynlock_value *l,
+                const char                  *file,
+                int                          line)
+{
+  g_mutex_clear (&l->mutex);
+  g_free (l);
+}
+
+static gpointer
+gtls_openssl_init (gpointer data)
+{
+  int i;
+
+  /* Initialize openssl threading */
+  mutex_array = g_malloc_n (CRYPTO_num_locks(), sizeof (GMutex));
+  for (i = 0; i < CRYPTO_num_locks (); ++i)
+    g_mutex_init(&mutex_array[i]);
+
+  CRYPTO_set_id_callback (id_cb);
+  CRYPTO_set_locking_callback (locking_cb);
+  CRYPTO_set_dynlock_create_callback (dyn_create_cb);
+  CRYPTO_set_dynlock_lock_callback (dyn_lock_cb);
+  CRYPTO_set_dynlock_destroy_callback (dyn_destroy_cb);
+
+  SSL_library_init ();
+  SSL_load_error_strings ();
+  OpenSSL_add_all_algorithms ();
+
+  /* Leak the module to keep it from being unloaded. */
+  g_type_plugin_use (g_type_get_plugin (G_TYPE_TLS_BACKEND_OPENSSL));
+
+  return NULL;
+}
+
+static GOnce openssl_inited = G_ONCE_INIT;
+
+static void
+g_tls_backend_openssl_init (GTlsBackendOpenssl *backend)
+{
+  GTlsBackendOpensslPrivate *priv;
+
+  priv = g_tls_backend_openssl_get_instance_private (backend);
+
+  /* Once we call gtls_openssl_init(), we can't allow the module to be
+   * unloaded (since if openssl gets unloaded but gcrypt doesn't, then
+   * gcrypt will have dangling pointers to openssl's mutex functions).
+   * So we initialize it from here rather than at class init time so
+   * that it doesn't happen unless the app is actually using TLS (as
+   * opposed to just calling g_io_modules_scan_all_in_directory()).
+   */
+  g_once (&openssl_inited, gtls_openssl_init, NULL);
+
+  g_mutex_init (&priv->mutex);
+}
+
+static void
+g_tls_backend_openssl_finalize (GObject *object)
+{
+  int i;
+
+  GTlsBackendOpenssl *backend = G_TLS_BACKEND_OPENSSL (object);
+  GTlsBackendOpensslPrivate *priv;
+
+  priv = g_tls_backend_openssl_get_instance_private (backend);
+
+  g_clear_object (&priv->default_database);
+  g_mutex_clear (&priv->mutex);
+
+  CRYPTO_set_id_callback (NULL);
+  CRYPTO_set_locking_callback (NULL);
+  CRYPTO_set_dynlock_create_callback (NULL);
+  CRYPTO_set_dynlock_lock_callback (NULL);
+  CRYPTO_set_dynlock_destroy_callback (NULL);
+  for (i = 0; i < CRYPTO_num_locks(); ++i)
+    g_mutex_clear (&mutex_array[i]);
+  g_free (mutex_array);
+
+  G_OBJECT_CLASS (g_tls_backend_openssl_parent_class)->finalize (object);
+}
+
+static GTlsDatabase *
+g_tls_backend_openssl_real_create_database (GTlsBackendOpenssl  *self,
+                                           GError            **error)
+{
+  const gchar *anchor_file = NULL;
+#ifdef GTLS_SYSTEM_CA_FILE
+  anchor_file = GTLS_SYSTEM_CA_FILE;
+#endif
+  return g_tls_file_database_new (anchor_file, error);
+}
+
+static void
+g_tls_backend_openssl_class_init (GTlsBackendOpensslClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = g_tls_backend_openssl_finalize;
+
+  klass->create_database = g_tls_backend_openssl_real_create_database;
+}
+
+static void
+g_tls_backend_openssl_class_finalize (GTlsBackendOpensslClass *backend_class)
+{
+}
+
+static GTlsDatabase*
+g_tls_backend_openssl_get_default_database (GTlsBackend *backend)
+{
+  GTlsBackendOpenssl *openssl_backend = G_TLS_BACKEND_OPENSSL (backend);
+  GTlsBackendOpensslPrivate *priv;
+  GTlsDatabase *result;
+  GError *error = NULL;
+
+  priv = g_tls_backend_openssl_get_instance_private (openssl_backend);
+
+  g_mutex_lock (&priv->mutex);
+
+  if (priv->default_database)
+    {
+      result = g_object_ref (priv->default_database);
+    }
+  else
+    {
+      g_assert (G_TLS_BACKEND_OPENSSL_GET_CLASS (openssl_backend)->create_database);
+      result = G_TLS_BACKEND_OPENSSL_GET_CLASS (openssl_backend)->create_database (openssl_backend, &error);
+      if (error)
+        {
+          g_warning ("Couldn't load TLS file database: %s",
+                     error->message);
+          g_clear_error (&error);
+        }
+      else
+        {
+          g_assert (result);
+          priv->default_database = g_object_ref (result);
+        }
+    }
+
+  g_mutex_unlock (&priv->mutex);
+
+  return result;
+}
+
+static void
+g_tls_backend_openssl_interface_init (GTlsBackendInterface *iface)
+{
+  iface->get_certificate_type = g_tls_certificate_openssl_get_type;
+  iface->get_client_connection_type = g_tls_client_connection_openssl_get_type;
+  iface->get_server_connection_type = g_tls_server_connection_openssl_get_type;
+  iface->get_file_database_type = g_tls_file_database_openssl_get_type;
+  iface->get_default_database = g_tls_backend_openssl_get_default_database;
+}
+
+void
+g_tls_backend_openssl_register (GIOModule *module)
+{
+  g_tls_backend_openssl_register_type (G_TYPE_MODULE (module));
+  g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
+                                  g_tls_backend_openssl_get_type(),
+                                  "openssl",
+                                  0);
+}
diff --git a/tls/openssl/gtlsbackend-openssl.h b/tls/openssl/gtlsbackend-openssl.h
new file mode 100644
index 0000000..410b0fb
--- /dev/null
+++ b/tls/openssl/gtlsbackend-openssl.h
@@ -0,0 +1,48 @@
+/*
+ * gtlsbackend-openssl.h
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#ifndef __G_TLS_BACKEND_OPENSSL_H__
+#define __G_TLS_BACKEND_OPENSSL_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_BACKEND_OPENSSL (g_tls_backend_openssl_get_type ())
+G_DECLARE_DERIVABLE_TYPE (GTlsBackendOpenssl, g_tls_backend_openssl,
+                          G, TLS_BACKEND_OPENSSL, GObject)
+
+struct _GTlsBackendOpensslClass
+{
+  GObjectClass parent_class;
+
+  GTlsDatabase*   (*create_database)      (GTlsBackendOpenssl         *backend,
+                                           GError                    **error);
+};
+
+void    g_tls_backend_openssl_register       (GIOModule *module);
+
+G_END_DECLS
+
+#endif /* __G_TLS_BACKEND_OPENSSL_H___ */
diff --git a/tls/openssl/gtlsbio.c b/tls/openssl/gtlsbio.c
new file mode 100644
index 0000000..17d10a0
--- /dev/null
+++ b/tls/openssl/gtlsbio.c
@@ -0,0 +1,296 @@
+/*
+ * gtlsbio.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "gtlsbio.h"
+
+#include <string.h>
+
+typedef struct {
+  GIOStream *io_stream;
+  GCancellable *read_cancellable;
+  GCancellable *write_cancellable;
+  gboolean read_blocking;
+  gboolean write_blocking;
+  GError **read_error;
+  GError **write_error;
+} GTlsBio;
+
+static void
+free_gbio (gpointer user_data)
+{
+  GTlsBio *bio = (GTlsBio *)user_data;
+
+  g_object_unref (bio->io_stream);
+  g_free (bio);
+}
+
+static int
+gtls_bio_create (BIO *bio)
+{
+  bio->init = 0;
+  bio->num = 0;
+  bio->ptr = NULL;
+  bio->flags = 0;
+  return 1;
+}
+
+static int
+gtls_bio_destroy (BIO *bio)
+{
+  if (bio == NULL)
+    return 0;
+
+  if (bio->shutdown)
+    {
+      if (bio->ptr != NULL)
+        {
+          free_gbio (bio->ptr);
+          bio->ptr = NULL;
+        }
+      bio->init = 0;
+    }
+
+    return 1;
+}
+
+static long
+gtls_bio_ctrl (BIO  *b,
+               int   cmd,
+               long  num,
+               void *ptr)
+{
+  long ret = 1;
+
+  switch (cmd)
+    {
+    case BIO_CTRL_GET_CLOSE:
+      ret = b->shutdown;
+      break;
+    case BIO_CTRL_SET_CLOSE:
+      b->shutdown = (int)num;
+      break;
+    case BIO_CTRL_DUP:
+    case BIO_CTRL_FLUSH:
+      ret = 1;
+      break;
+    case BIO_CTRL_PUSH:
+    case BIO_CTRL_POP:
+      ret = 0;
+      break;
+    default:
+      g_debug ("Got unsupported command: %d", cmd);
+      ret = 0;
+      break;
+    }
+
+  return ret;
+}
+
+static int
+gtls_bio_write (BIO        *bio,
+                const char *in,
+                int         inl)
+{
+  GTlsBio *gbio;
+  gssize written;
+  GError *error = NULL;
+
+  if (!bio->init || in == NULL || inl == 0)
+    return 0;
+
+  gbio = (GTlsBio *)bio->ptr;
+
+  BIO_clear_retry_flags (bio);
+  written = g_pollable_stream_write (g_io_stream_get_output_stream (gbio->io_stream),
+                                     in, inl,
+                                     gbio->write_blocking,
+                                     gbio->write_cancellable,
+                                     &error);
+
+  if (written == -1)
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+        BIO_set_retry_write (bio);
+
+      g_propagate_error (gbio->write_error, error);
+    }
+
+  return written;
+}
+
+static int
+gtls_bio_read (BIO  *bio,
+               char *out,
+               int   outl)
+{
+  GTlsBio *gbio;
+  gssize read;
+  GError *error = NULL;
+
+  if (!bio->init || out == NULL || outl == 0)
+    return 0;
+
+  gbio = (GTlsBio *)bio->ptr;
+
+  BIO_clear_retry_flags (bio);
+  read = g_pollable_stream_read (g_io_stream_get_input_stream (gbio->io_stream),
+                                 out, outl,
+                                 gbio->read_blocking,
+                                 gbio->read_cancellable,
+                                 &error);
+
+  if (read == -1)
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+        BIO_set_retry_read (bio);
+
+      g_propagate_error (gbio->read_error, error);
+    }
+
+  return read;
+}
+
+static int
+gtls_bio_puts(BIO        *bio,
+              const char *str)
+{
+  return gtls_bio_write (bio, str, (int)strlen (str));
+}
+
+static int
+gtls_bio_gets(BIO  *bio,
+              char *buf,
+              int   len)
+{
+  return -1;
+}
+
+static BIO_METHOD methods_gtls = {
+  BIO_TYPE_SOURCE_SINK,
+  "gtls",
+  gtls_bio_write,
+  gtls_bio_read,
+  gtls_bio_puts,
+  gtls_bio_gets,
+  gtls_bio_ctrl,
+  gtls_bio_create,
+  gtls_bio_destroy
+};
+
+static BIO_METHOD *
+BIO_s_gtls (void)
+{
+  return &methods_gtls;
+}
+
+BIO *
+g_tls_bio_new (GIOStream *io_stream)
+{
+  BIO *ret;
+  GTlsBio *gbio;
+
+  ret = BIO_new(BIO_s_gtls ());
+  if (ret == NULL)
+    return NULL;
+
+  gbio = g_new0 (GTlsBio, 1);
+  gbio->io_stream = g_object_ref (io_stream);
+
+  ret->ptr = gbio;
+  ret->init = 1;
+
+  return ret;
+}
+
+void
+g_tls_bio_set_read_cancellable (BIO          *bio,
+                                GCancellable *cancellable)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+  gbio = (GTlsBio *)bio->ptr;
+  gbio->read_cancellable = cancellable;
+}
+
+void
+g_tls_bio_set_read_blocking (BIO      *bio,
+                             gboolean  blocking)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+  gbio = (GTlsBio *)bio->ptr;
+  gbio->read_blocking = blocking;
+}
+
+void
+g_tls_bio_set_read_error (BIO     *bio,
+                          GError **error)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+  gbio = (GTlsBio *)bio->ptr;
+  gbio->read_error = error;
+}
+
+void
+g_tls_bio_set_write_cancellable (BIO          *bio,
+                                 GCancellable *cancellable)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+  gbio = (GTlsBio *)bio->ptr;
+  gbio->write_cancellable = cancellable;
+}
+
+void
+g_tls_bio_set_write_blocking (BIO          *bio,
+                              gboolean      blocking)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+  gbio = (GTlsBio *)bio->ptr;
+  gbio->write_blocking = blocking;
+}
+
+void
+g_tls_bio_set_write_error (BIO     *bio,
+                           GError **error)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+  gbio = (GTlsBio *)bio->ptr;
+  gbio->write_error = error;
+}
diff --git a/tls/openssl/gtlsbio.h b/tls/openssl/gtlsbio.h
new file mode 100644
index 0000000..701f5d1
--- /dev/null
+++ b/tls/openssl/gtlsbio.h
@@ -0,0 +1,55 @@
+/*
+ * gtlsbio.h
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#ifndef __G_TLS_BIO_H__
+#define __G_TLS_BIO_H__
+
+#include <gio/gio.h>
+#include <openssl/bio.h>
+
+G_BEGIN_DECLS
+
+BIO       *g_tls_bio_new                   (GIOStream    *io_stream);
+
+void       g_tls_bio_set_read_cancellable  (BIO          *bio,
+                                            GCancellable *cancellable);
+
+void       g_tls_bio_set_read_blocking     (BIO          *bio,
+                                            gboolean      blocking);
+
+void       g_tls_bio_set_read_error        (BIO          *bio,
+                                            GError      **error);
+
+void       g_tls_bio_set_write_cancellable (BIO          *bio,
+                                            GCancellable *cancellable);
+
+void       g_tls_bio_set_write_blocking    (BIO          *bio,
+                                            gboolean      blocking);
+
+void       g_tls_bio_set_write_error       (BIO          *bio,
+                                            GError      **error);
+
+G_END_DECLS
+
+#endif /* __G_TLS_BIO_H__ */
diff --git a/tls/openssl/gtlscertificate-openssl.c b/tls/openssl/gtlscertificate-openssl.c
new file mode 100644
index 0000000..d51c9f5
--- /dev/null
+++ b/tls/openssl/gtlscertificate-openssl.c
@@ -0,0 +1,701 @@
+/*
+ * gtlscertificate-openssl.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+
+#include "gtlscertificate-openssl.h"
+#include "openssl-util.h"
+#include <glib/gi18n-lib.h>
+
+typedef struct _GTlsCertificateOpensslPrivate
+{
+  X509 *cert;
+  EVP_PKEY *key;
+
+  GTlsCertificateOpenssl *issuer;
+
+  GError *construct_error;
+
+  guint have_cert : 1;
+  guint have_key  : 1;
+} GTlsCertificateOpensslPrivate;
+
+enum
+{
+  PROP_0,
+
+  PROP_CERTIFICATE,
+  PROP_CERTIFICATE_PEM,
+  PROP_PRIVATE_KEY,
+  PROP_PRIVATE_KEY_PEM,
+  PROP_ISSUER
+};
+
+static void     g_tls_certificate_openssl_initable_iface_init (GInitableIface  *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsCertificateOpenssl, g_tls_certificate_openssl, G_TYPE_TLS_CERTIFICATE,
+                         G_ADD_PRIVATE (GTlsCertificateOpenssl)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                g_tls_certificate_openssl_initable_iface_init))
+
+static void
+g_tls_certificate_openssl_finalize (GObject *object)
+{
+  GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
+  GTlsCertificateOpensslPrivate *priv;
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  if (priv->cert)
+    X509_free (priv->cert);
+  if (priv->key)
+    EVP_PKEY_free (priv->key);
+
+  g_clear_object (&priv->issuer);
+
+  g_clear_error (&priv->construct_error);
+
+  G_OBJECT_CLASS (g_tls_certificate_openssl_parent_class)->finalize (object);
+}
+
+static void
+g_tls_certificate_openssl_get_property (GObject    *object,
+                                        guint       prop_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+  GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
+  GTlsCertificateOpensslPrivate *priv;
+  GByteArray *certificate;
+  guint8 *data;
+  BIO *bio;
+  char *certificate_pem;
+  int size;
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  switch (prop_id)
+    {
+    case PROP_CERTIFICATE:
+      /* NOTE: we do the two calls to avoid openssl allocating the buffer for us */
+      size = i2d_X509 (priv->cert, NULL);
+      if (size < 0)
+        certificate = NULL;
+      else
+        {
+          certificate = g_byte_array_sized_new (size);
+          certificate->len = size;
+          data = certificate->data;
+          size = i2d_X509 (priv->cert, &data);
+          if (size < 0)
+            {
+              g_byte_array_free (certificate, TRUE);
+              certificate = NULL;
+            }
+        }
+      g_value_take_boxed (value, certificate);
+      break;
+
+    case PROP_CERTIFICATE_PEM:
+      bio = BIO_new (BIO_s_mem ());
+
+      if (!PEM_write_bio_X509 (bio, priv->cert) || !BIO_write (bio, "\0", 1))
+        certificate_pem = NULL;
+      else
+        {
+          BIO_get_mem_data (bio, &certificate_pem);
+          g_value_set_string (value, certificate_pem);
+
+          BIO_free_all (bio);
+        }
+      break;
+
+    case PROP_ISSUER:
+      g_value_set_object (value, priv->issuer);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_certificate_openssl_set_property (GObject      *object,
+                                       guint         prop_id,
+                                       const GValue *value,
+                                       GParamSpec   *pspec)
+{
+  GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
+  GTlsCertificateOpensslPrivate *priv;
+  GByteArray *bytes;
+  guint8 *data;
+  BIO *bio;
+  const char *string;
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  switch (prop_id)
+    {
+    case PROP_CERTIFICATE:
+      bytes = g_value_get_boxed (value);
+      if (!bytes)
+        break;
+      g_return_if_fail (priv->have_cert == FALSE);
+      /* see that we cannot use bytes->data directly since it will move the pointer */
+      data = bytes->data;
+      priv->cert = d2i_X509 (NULL, (const unsigned char **)&data, bytes->len);
+      if (priv->cert != NULL)
+        priv->have_cert = TRUE;
+      else if (!priv->construct_error)
+        {
+          priv->construct_error =
+            g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                         _("Could not parse DER certificate: %s"),
+                         ERR_error_string (ERR_get_error (), NULL));
+        }
+
+      break;
+
+    case PROP_CERTIFICATE_PEM:
+      string = g_value_get_string (value);
+      if (!string)
+        break;
+      g_return_if_fail (priv->have_cert == FALSE);
+      bio = BIO_new_mem_buf ((gpointer)string, -1);
+      priv->cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
+      BIO_free (bio);
+      if (priv->cert != NULL)
+        priv->have_cert = TRUE;
+      else if (!priv->construct_error)
+        {
+          priv->construct_error =
+            g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                         _("Could not parse PEM certificate: %s"),
+                         ERR_error_string (ERR_get_error (), NULL));
+        }
+      break;
+
+    case PROP_PRIVATE_KEY:
+      bytes = g_value_get_boxed (value);
+      if (!bytes)
+        break;
+      g_return_if_fail (priv->have_key == FALSE);
+      bio = BIO_new_mem_buf (bytes->data, bytes->len);
+      priv->key = d2i_PrivateKey_bio (bio, NULL);
+      BIO_free (bio);
+      if (priv->key != NULL)
+        priv->have_key = TRUE;
+      else if (!priv->construct_error)
+        {
+          priv->construct_error =
+            g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                         _("Could not parse DER private key: %s"),
+                         ERR_error_string (ERR_get_error (), NULL));
+        }
+      break;
+
+    case PROP_PRIVATE_KEY_PEM:
+      string = g_value_get_string (value);
+      if (!string)
+        break;
+      g_return_if_fail (priv->have_key == FALSE);
+      bio = BIO_new_mem_buf ((gpointer)string, -1);
+      priv->key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
+      BIO_free (bio);
+      if (priv->key != NULL)
+        priv->have_key = TRUE;
+      else if (!priv->construct_error)
+        {
+          priv->construct_error =
+            g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                         _("Could not parse PEM private key: %s"),
+                         ERR_error_string (ERR_get_error (), NULL));
+        }
+      break;
+
+    case PROP_ISSUER:
+      priv->issuer = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_certificate_openssl_init (GTlsCertificateOpenssl *openssl)
+{
+}
+
+static gboolean
+g_tls_certificate_openssl_initable_init (GInitable       *initable,
+                                         GCancellable    *cancellable,
+                                         GError         **error)
+{
+  GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (initable);
+  GTlsCertificateOpensslPrivate *priv;
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  if (priv->construct_error)
+    {
+      g_propagate_error (error, priv->construct_error);
+      priv->construct_error = NULL;
+      return FALSE;
+    }
+  else if (!priv->have_cert)
+    {
+      g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                           _("No certificate data provided"));
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+static GTlsCertificateFlags
+g_tls_certificate_openssl_verify (GTlsCertificate     *cert,
+                                  GSocketConnectable  *identity,
+                                  GTlsCertificate     *trusted_ca)
+{
+  GTlsCertificateOpenssl *cert_openssl;
+  GTlsCertificateOpensslPrivate *priv;
+  GTlsCertificateFlags gtls_flags;
+  X509 *x;
+  STACK_OF(X509) *untrusted;
+  gint i;
+
+  cert_openssl = G_TLS_CERTIFICATE_OPENSSL (cert);
+  priv = g_tls_certificate_openssl_get_instance_private (cert_openssl);
+  x = priv->cert;
+
+  untrusted = sk_X509_new_null ();
+  for (; cert_openssl; cert_openssl = priv->issuer)
+    {
+      priv = g_tls_certificate_openssl_get_instance_private (cert_openssl);
+      sk_X509_push (untrusted, priv->cert);
+    }
+
+  gtls_flags = 0;
+
+  if (trusted_ca)
+    {
+      X509_STORE *store;
+      X509_STORE_CTX csc;
+      STACK_OF(X509) *trusted;
+
+      store = X509_STORE_new ();
+
+      if (!X509_STORE_CTX_init (&csc, store, x, untrusted))
+        {
+          sk_X509_free (untrusted);
+          X509_STORE_CTX_cleanup (&csc);
+          X509_STORE_free (store);
+          return G_TLS_CERTIFICATE_GENERIC_ERROR;
+        }
+
+      trusted = sk_X509_new_null ();
+      cert_openssl = G_TLS_CERTIFICATE_OPENSSL (trusted_ca);
+      for (; cert_openssl; cert_openssl = priv->issuer)
+        {
+          priv = g_tls_certificate_openssl_get_instance_private (cert_openssl);
+          sk_X509_push (trusted, priv->cert);
+        }
+
+      X509_STORE_CTX_trusted_stack (&csc, trusted);
+      if (X509_verify_cert (&csc) <= 0)
+        gtls_flags |= g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (&csc));
+
+      sk_X509_free (trusted);
+      X509_STORE_CTX_cleanup (&csc);
+      X509_STORE_free (store);
+    }
+
+  /* We have to check these ourselves since openssl
+   * does not give us flags and UNKNOWN_CA will take priority.
+   */
+  for (i = 0; i < sk_X509_num (untrusted); i++)
+    {
+      X509 *c = sk_X509_value (untrusted, i);
+      ASN1_TIME *not_before = X509_get_notBefore (c);
+      ASN1_TIME *not_after = X509_get_notAfter (c);
+
+      if (X509_cmp_current_time (not_before) > 0)
+        gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
+
+      if (X509_cmp_current_time (not_after) < 0)
+        gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
+    }
+
+  sk_X509_free (untrusted);
+
+  if (identity)
+    gtls_flags |= g_tls_certificate_openssl_verify_identity (G_TLS_CERTIFICATE_OPENSSL (cert), identity);
+
+  return gtls_flags;
+}
+
+static void
+g_tls_certificate_openssl_class_init (GTlsCertificateOpensslClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsCertificateClass *certificate_class = G_TLS_CERTIFICATE_CLASS (klass);
+
+  gobject_class->get_property = g_tls_certificate_openssl_get_property;
+  gobject_class->set_property = g_tls_certificate_openssl_set_property;
+  gobject_class->finalize     = g_tls_certificate_openssl_finalize;
+
+  certificate_class->verify = g_tls_certificate_openssl_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_openssl_initable_iface_init (GInitableIface  *iface)
+{
+  iface->init = g_tls_certificate_openssl_initable_init;
+}
+
+GTlsCertificate *
+g_tls_certificate_openssl_new (GBytes          *bytes,
+                               GTlsCertificate *issuer)
+{
+  GTlsCertificateOpenssl *openssl;
+
+  openssl = g_object_new (G_TYPE_TLS_CERTIFICATE_OPENSSL,
+                          "issuer", issuer,
+                          NULL);
+  g_tls_certificate_openssl_set_data (openssl, bytes);
+
+  return G_TLS_CERTIFICATE (openssl);
+}
+
+GTlsCertificate *
+g_tls_certificate_openssl_new_from_x509 (X509            *x,
+                                         GTlsCertificate *issuer)
+{
+  GTlsCertificateOpenssl *openssl;
+  GTlsCertificateOpensslPrivate *priv;
+
+  openssl = g_object_new (G_TYPE_TLS_CERTIFICATE_OPENSSL,
+                          "issuer", issuer,
+                          NULL);
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  priv->cert = X509_dup (x);
+  priv->have_cert = TRUE;
+
+  return G_TLS_CERTIFICATE (openssl);
+}
+
+void
+g_tls_certificate_openssl_set_data (GTlsCertificateOpenssl *openssl,
+                                    GBytes                 *bytes)
+{
+  GTlsCertificateOpensslPrivate *priv;
+  const unsigned char *data;
+
+  g_return_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl));
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  g_return_if_fail (!priv->have_cert);
+
+  data = (const unsigned char *)g_bytes_get_data (bytes, NULL);
+  priv->cert = d2i_X509 (NULL, &data, g_bytes_get_size (bytes));
+
+  if (priv->cert != NULL)
+    priv->have_cert = TRUE;
+}
+
+GBytes *
+g_tls_certificate_openssl_get_bytes (GTlsCertificateOpenssl *openssl)
+{
+  GByteArray *array;
+
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl), NULL);
+
+  g_object_get (openssl, "certificate", &array, NULL);
+  return g_byte_array_free_to_bytes (array);
+}
+
+X509 *
+g_tls_certificate_openssl_get_cert (GTlsCertificateOpenssl *openssl)
+{
+  GTlsCertificateOpensslPrivate *priv;
+
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl), FALSE);
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  return priv->cert;
+}
+
+EVP_PKEY *
+g_tls_certificate_openssl_get_key (GTlsCertificateOpenssl *openssl)
+{
+  GTlsCertificateOpensslPrivate *priv;
+
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl), FALSE);
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  return priv->key;
+}
+
+void
+g_tls_certificate_openssl_set_issuer (GTlsCertificateOpenssl *openssl,
+                                      GTlsCertificateOpenssl *issuer)
+{
+  GTlsCertificateOpensslPrivate *priv;
+
+  g_return_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl));
+  g_return_if_fail (!issuer || G_IS_TLS_CERTIFICATE_OPENSSL (issuer));
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  if (g_set_object (&priv->issuer, issuer))
+    g_object_notify (G_OBJECT (openssl), "issuer");
+}
+
+static gboolean
+verify_identity_hostname (GTlsCertificateOpenssl *openssl,
+                          GSocketConnectable     *identity)
+{
+  GTlsCertificateOpensslPrivate *priv;
+  const char *hostname;
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  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
+    return FALSE;
+
+  return g_tls_X509_check_host (priv->cert, hostname, strlen (hostname), 0, NULL) == 1;
+}
+
+static gboolean
+verify_identity_ip (GTlsCertificateOpenssl *openssl,
+                    GSocketConnectable     *identity)
+{
+  GTlsCertificateOpensslPrivate *priv;
+  GInetAddress *addr;
+  gsize addr_size;
+  const guint8 *addr_bytes;
+  gboolean ret;
+
+  priv = g_tls_certificate_openssl_get_instance_private (openssl);
+
+  if (G_IS_INET_SOCKET_ADDRESS (identity))
+    addr = g_object_ref (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (identity)));
+  else {
+    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
+      return FALSE;
+
+    addr = g_inet_address_new_from_string (hostname);
+    if (!addr)
+      return FALSE;
+  }
+
+  addr_bytes = g_inet_address_to_bytes (addr);
+  addr_size = g_inet_address_get_native_size (addr);
+
+  ret = g_tls_X509_check_ip (priv->cert, addr_bytes, addr_size, 0) == 1;
+
+  g_object_unref (addr);
+  return ret;
+}
+
+GTlsCertificateFlags
+g_tls_certificate_openssl_verify_identity (GTlsCertificateOpenssl *openssl,
+                                           GSocketConnectable     *identity)
+{
+  if (verify_identity_hostname (openssl, identity))
+    return 0;
+  else if (verify_identity_ip (openssl, identity))
+    return 0;
+
+  /* FIXME: check sRVName and uniformResourceIdentifier
+   * subjectAltNames, if appropriate for @identity.
+   */
+
+  return G_TLS_CERTIFICATE_BAD_IDENTITY;
+}
+
+GTlsCertificateFlags
+g_tls_certificate_openssl_convert_error (guint openssl_error)
+{
+  GTlsCertificateFlags gtls_flags;
+
+  gtls_flags = 0;
+
+  /* FIXME: should we add more ? */
+  switch (openssl_error)
+    {
+    case X509_V_OK:
+      break;
+    case X509_V_ERR_CERT_NOT_YET_VALID:
+      gtls_flags = G_TLS_CERTIFICATE_NOT_ACTIVATED;
+      break;
+    case X509_V_ERR_CERT_HAS_EXPIRED:
+      gtls_flags = G_TLS_CERTIFICATE_EXPIRED;
+      break;
+    case X509_V_ERR_CERT_REVOKED:
+      gtls_flags = G_TLS_CERTIFICATE_REVOKED;
+      break;
+    case X509_V_ERR_AKID_SKID_MISMATCH:
+      gtls_flags = G_TLS_CERTIFICATE_BAD_IDENTITY;
+      break;
+    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+      gtls_flags = G_TLS_CERTIFICATE_UNKNOWN_CA;
+      break;
+    default:
+      g_message ("certificate error: %s", X509_verify_cert_error_string (openssl_error));
+      gtls_flags = G_TLS_CERTIFICATE_GENERIC_ERROR;
+    }
+
+  return gtls_flags;
+}
+
+static gboolean
+is_issuer (GTlsCertificateOpenssl *cert,
+           GTlsCertificateOpenssl *issuer)
+{
+  X509 *x;
+  X509 *issuer_x;
+  X509_STORE *store;
+  X509_STORE_CTX csc;
+  STACK_OF(X509) *trusted;
+  gboolean ret = FALSE;
+  gint err;
+
+  x = g_tls_certificate_openssl_get_cert (cert);
+  issuer_x = g_tls_certificate_openssl_get_cert (issuer);
+
+  store = X509_STORE_new ();
+
+  if (!X509_STORE_CTX_init (&csc, store, x, NULL))
+    goto end;
+
+  trusted = sk_X509_new_null ();
+  sk_X509_push (trusted, issuer_x);
+
+  X509_STORE_CTX_trusted_stack (&csc, trusted);
+  X509_STORE_CTX_set_flags (&csc, X509_V_FLAG_CB_ISSUER_CHECK);
+
+  /* FIXME: is this the right way to do it? */
+  if (X509_verify_cert (&csc) <= 0)
+    {
+      err = X509_STORE_CTX_get_error (&csc);
+      if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)
+        ret = TRUE;
+    }
+  else
+    ret = TRUE;
+
+  sk_X509_free (trusted);
+
+end:
+  X509_STORE_CTX_cleanup (&csc);
+  X509_STORE_free (store);
+
+  return ret;
+}
+
+GTlsCertificateOpenssl *
+g_tls_certificate_openssl_build_chain (X509            *x,
+                                       STACK_OF (X509) *chain)
+{
+  GPtrArray *glib_certs;
+  GTlsCertificateOpenssl *issuer;
+  GTlsCertificateOpenssl *result;
+  guint i, j;
+
+  g_return_val_if_fail (x != NULL, NULL);
+  g_return_val_if_fail (chain, NULL);
+
+  glib_certs = g_ptr_array_new_full (sk_X509_num (chain), g_object_unref);
+  g_ptr_array_add (glib_certs, g_tls_certificate_openssl_new_from_x509 (x, NULL));
+  for (i = 1; i < sk_X509_num (chain); i++)
+    g_ptr_array_add (glib_certs, g_tls_certificate_openssl_new_from_x509 (sk_X509_value (chain, i), NULL));
+
+  /* Some servers send certs out of order, or will send duplicate
+   * certs, so we need to be careful when assigning the issuer of
+   * our new GTlsCertificateOpenssl.
+   */
+  for (i = 0; i < glib_certs->len; i++)
+    {
+      issuer = NULL;
+
+      /* Check if the cert issued itself */
+      if (is_issuer (glib_certs->pdata[i], glib_certs->pdata[i]))
+        continue;
+
+      if (i < glib_certs->len - 1 &&
+          is_issuer (glib_certs->pdata[i], glib_certs->pdata[i + 1]))
+        {
+          issuer = glib_certs->pdata[i + 1];
+        }
+      else
+        {
+          for (j = 0; j < glib_certs->len; j++)
+            {
+              if (j != i &&
+                  is_issuer (glib_certs->pdata[i], glib_certs->pdata[j]))
+                {
+                  issuer = glib_certs->pdata[j];
+                  break;
+                }
+            }
+        }
+
+      if (issuer)
+        g_tls_certificate_openssl_set_issuer (glib_certs->pdata[i], issuer);
+    }
+
+  result = g_object_ref (glib_certs->pdata[0]);
+  g_ptr_array_unref (glib_certs);
+
+  return result;
+}
diff --git a/tls/openssl/gtlscertificate-openssl.h b/tls/openssl/gtlscertificate-openssl.h
new file mode 100644
index 0000000..6b40502
--- /dev/null
+++ b/tls/openssl/gtlscertificate-openssl.h
@@ -0,0 +1,69 @@
+/*
+ * gtlscertificate-openssl.h
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#ifndef __G_TLS_CERTIFICATE_OPENSSL_H__
+#define __G_TLS_CERTIFICATE_OPENSSL_H__
+
+#include <gio/gio.h>
+#include <openssl/ssl.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_CERTIFICATE_OPENSSL (g_tls_certificate_openssl_get_type ())
+G_DECLARE_DERIVABLE_TYPE (GTlsCertificateOpenssl, g_tls_certificate_openssl,
+                          G, TLS_CERTIFICATE_OPENSSL, GTlsCertificate)
+
+struct _GTlsCertificateOpensslClass
+{
+  GTlsCertificateClass parent_class;
+};
+
+GTlsCertificate             *g_tls_certificate_openssl_new             (GBytes                 *bytes,
+                                                                        GTlsCertificate        *issuer);
+
+GTlsCertificate             *g_tls_certificate_openssl_new_from_x509   (X509                   *x,
+                                                                        GTlsCertificate        *issuer);
+
+void                         g_tls_certificate_openssl_set_data        (GTlsCertificateOpenssl *openssl,
+                                                                        GBytes                 *bytes);
+
+GBytes *                     g_tls_certificate_openssl_get_bytes       (GTlsCertificateOpenssl *openssl);
+
+X509                        *g_tls_certificate_openssl_get_cert        (GTlsCertificateOpenssl *openssl);
+EVP_PKEY                    *g_tls_certificate_openssl_get_key         (GTlsCertificateOpenssl *openssl);
+
+void                         g_tls_certificate_openssl_set_issuer      (GTlsCertificateOpenssl *openssl,
+                                                                        GTlsCertificateOpenssl *issuer);
+
+GTlsCertificateFlags         g_tls_certificate_openssl_verify_identity (GTlsCertificateOpenssl *openssl,
+                                                                        GSocketConnectable     *identity);
+
+GTlsCertificateFlags         g_tls_certificate_openssl_convert_error   (guint                   
openssl_error);
+
+GTlsCertificateOpenssl      *g_tls_certificate_openssl_build_chain     (X509                   *x,
+                                                                        STACK_OF (X509)        *chain);
+
+G_END_DECLS
+
+#endif /* __G_TLS_CERTIFICATE_OPENSSL_H___ */
diff --git a/tls/openssl/gtlsclientconnection-openssl.c b/tls/openssl/gtlsclientconnection-openssl.c
new file mode 100644
index 0000000..4608f7e
--- /dev/null
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -0,0 +1,491 @@
+/*
+ * gtlsclientconnection-openssl.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "config.h"
+#include "glib.h"
+
+#ifdef G_OS_WIN32
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <errno.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509_vfy.h>
+#include <string.h>
+
+#include "gtlsconnection-base.h"
+#include "gtlsclientconnection-openssl.h"
+#include "gtlsbackend-openssl.h"
+#include "gtlscertificate-openssl.h"
+#include <glib/gi18n-lib.h>
+
+typedef struct _GTlsClientConnectionOpensslPrivate
+{
+  GTlsCertificateFlags validation_flags;
+  GSocketConnectable *server_identity;
+  gboolean use_ssl3;
+  gboolean session_data_override;
+
+  GBytes *session_id;
+  GBytes *session_data;
+
+  STACK_OF (X509_NAME) *ca_list;
+
+  SSL_SESSION *session;
+  SSL *ssl;
+  SSL_CTX *ssl_ctx;
+} GTlsClientConnectionOpensslPrivate;
+
+enum
+{
+  PROP_0,
+  PROP_VALIDATION_FLAGS,
+  PROP_SERVER_IDENTITY,
+  PROP_USE_SSL3,
+  PROP_ACCEPTED_CAS
+};
+
+static void g_tls_client_connection_openssl_initable_interface_init (GInitableIface  *iface);
+
+static void g_tls_client_connection_openssl_client_connection_interface_init (GTlsClientConnectionInterface 
*iface);
+
+static GInitableIface *g_tls_client_connection_openssl_parent_initable_iface;
+
+G_DEFINE_TYPE_WITH_CODE (GTlsClientConnectionOpenssl, g_tls_client_connection_openssl, 
G_TYPE_TLS_CONNECTION_OPENSSL,
+                         G_ADD_PRIVATE (GTlsClientConnectionOpenssl)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                g_tls_client_connection_openssl_initable_interface_init)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_TLS_CLIENT_CONNECTION,
+                                                
g_tls_client_connection_openssl_client_connection_interface_init))
+
+static void
+g_tls_client_connection_openssl_finalize (GObject *object)
+{
+  GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
+  GTlsClientConnectionOpensslPrivate *priv;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (openssl);
+
+  g_clear_object (&priv->server_identity);
+  g_clear_pointer (&priv->session_id, g_bytes_unref);
+  g_clear_pointer (&priv->session_data, g_bytes_unref);
+
+  SSL_free (priv->ssl);
+  SSL_CTX_free (priv->ssl_ctx);
+  SSL_SESSION_free (priv->session);
+
+  G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->finalize (object);
+}
+
+static const gchar *
+get_server_identity (GTlsClientConnectionOpenssl *openssl)
+{
+  GTlsClientConnectionOpensslPrivate *priv;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (openssl);
+
+  if (G_IS_NETWORK_ADDRESS (priv->server_identity))
+    return g_network_address_get_hostname (G_NETWORK_ADDRESS (priv->server_identity));
+  else if (G_IS_NETWORK_SERVICE (priv->server_identity))
+    return g_network_service_get_domain (G_NETWORK_SERVICE (priv->server_identity));
+  else
+    return NULL;
+}
+
+static void
+g_tls_client_connection_openssl_get_property (GObject    *object,
+                                             guint       prop_id,
+                                             GValue     *value,
+                                             GParamSpec *pspec)
+{
+  GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
+  GTlsClientConnectionOpensslPrivate *priv;
+  GList *accepted_cas;
+  gint i;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (openssl);
+
+  switch (prop_id)
+    {
+    case PROP_VALIDATION_FLAGS:
+      g_value_set_flags (value, priv->validation_flags);
+      break;
+
+    case PROP_SERVER_IDENTITY:
+      g_value_set_object (value, priv->server_identity);
+      break;
+
+    case PROP_USE_SSL3:
+      g_value_set_boolean (value, priv->use_ssl3);
+      break;
+
+    case PROP_ACCEPTED_CAS:
+      accepted_cas = NULL;
+      if (priv->ca_list)
+        {
+          for (i = 0; i < sk_X509_NAME_num (priv->ca_list); ++i)
+            {
+              int size;
+
+              size = i2d_X509_NAME (sk_X509_NAME_value (priv->ca_list, i), NULL);
+              if (size > 0)
+                {
+                  unsigned char *ca;
+
+                  ca = g_malloc (size);
+                  size = i2d_X509_NAME (sk_X509_NAME_value (priv->ca_list, i), &ca);
+                  if (size > 0)
+                    accepted_cas = g_list_prepend (accepted_cas, g_byte_array_new_take (
+                                                   ca, size));
+                  else
+                    g_free (ca);
+                }
+            }
+          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_openssl_set_property (GObject      *object,
+                                             guint         prop_id,
+                                             const GValue *value,
+                                             GParamSpec   *pspec)
+{
+  GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
+  GTlsClientConnectionOpensslPrivate *priv;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (openssl);
+
+  switch (prop_id)
+    {
+    case PROP_VALIDATION_FLAGS:
+      priv->validation_flags = g_value_get_flags (value);
+      break;
+
+    case PROP_SERVER_IDENTITY:
+      if (priv->server_identity)
+        g_object_unref (priv->server_identity);
+      priv->server_identity = g_value_dup_object (value);
+      break;
+
+    case PROP_USE_SSL3:
+      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_openssl_constructed (GObject *object)
+{
+  GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
+  GTlsClientConnectionOpensslPrivate *priv;
+  GSocketConnection *base_conn;
+  GSocketAddress *remote_addr;
+  GInetAddress *iaddr;
+  guint port;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (openssl);
+
+  /* Create a TLS session ID. We base it on the IP address since
+   * different hosts serving the same hostname/service will probably
+   * not share the same session cache. We base it on the
+   * server-identity because at least some servers will fail (rather
+   * than just failing to resume the session) if we don't.
+   * (https://bugs.launchpad.net/bugs/823325)
+   */
+  g_object_get (G_OBJECT (openssl), "base-io-stream", &base_conn, NULL);
+  if (G_IS_SOCKET_CONNECTION (base_conn))
+    {
+      remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
+      if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
+        {
+          GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
+          const gchar *server_hostname;
+          gchar *addrstr, *session_id;
+
+          iaddr = g_inet_socket_address_get_address (isaddr);
+          port = g_inet_socket_address_get_port (isaddr);
+
+          addrstr = g_inet_address_to_string (iaddr);
+          server_hostname = get_server_identity (openssl);
+          session_id = g_strdup_printf ("%s/%s/%d", addrstr,
+                                        server_hostname ? server_hostname : "",
+                                        port);
+          priv->session_id = g_bytes_new_take (session_id, strlen (session_id));
+          g_free (addrstr);
+        }
+      g_object_unref (remote_addr);
+    }
+  g_object_unref (base_conn);
+
+  G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->constructed (object);
+}
+
+static GTlsConnectionBaseStatus
+g_tls_client_connection_openssl_handshake (GTlsConnectionBase  *tls,
+                                           GCancellable        *cancellable,
+                                           GError             **error)
+{
+  return G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->
+    handshake (tls, cancellable, error);
+}
+
+static GTlsConnectionBaseStatus
+g_tls_client_connection_openssl_complete_handshake (GTlsConnectionBase  *tls,
+                                                    GError             **error)
+{
+  GTlsConnectionBaseStatus status;
+
+  status = G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->
+    complete_handshake (tls, error);
+
+  return status;
+}
+
+static SSL *
+g_tls_client_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection)
+{
+  GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (connection);
+  GTlsClientConnectionOpensslPrivate *priv;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (client);
+
+  return priv->ssl;
+}
+
+static SSL_CTX *
+g_tls_client_connection_openssl_get_ssl_ctx (GTlsConnectionOpenssl *connection)
+{
+  GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (connection);
+  GTlsClientConnectionOpensslPrivate *priv;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (client);
+
+  return priv->ssl_ctx;
+}
+
+static void
+g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
+  GTlsConnectionOpensslClass *connection_class = G_TLS_CONNECTION_OPENSSL_CLASS (klass);
+
+  gobject_class->finalize     = g_tls_client_connection_openssl_finalize;
+  gobject_class->get_property = g_tls_client_connection_openssl_get_property;
+  gobject_class->set_property = g_tls_client_connection_openssl_set_property;
+  gobject_class->constructed  = g_tls_client_connection_openssl_constructed;
+
+  base_class->handshake          = g_tls_client_connection_openssl_handshake;
+  base_class->complete_handshake = g_tls_client_connection_openssl_complete_handshake;
+
+  connection_class->get_ssl = g_tls_client_connection_openssl_get_ssl;
+  connection_class->get_ssl_ctx = g_tls_client_connection_openssl_get_ssl_ctx;
+
+  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_openssl_init (GTlsClientConnectionOpenssl *openssl)
+{
+}
+
+
+static void
+g_tls_client_connection_openssl_copy_session_state (GTlsClientConnection *conn,
+                                                    GTlsClientConnection *source)
+{
+}
+
+static void
+g_tls_client_connection_openssl_client_connection_interface_init (GTlsClientConnectionInterface *iface)
+{
+  iface->copy_session_state = g_tls_client_connection_openssl_copy_session_state;
+}
+
+static int data_index;
+
+static int
+retrieve_certificate (SSL       *ssl,
+                      X509     **x509,
+                      EVP_PKEY **pkey)
+{
+  GTlsClientConnectionOpenssl *client;
+  GTlsClientConnectionOpensslPrivate *priv;
+  GTlsConnectionBase *tls;
+  GTlsConnectionOpenssl *openssl;
+  GTlsCertificate *cert;
+  gboolean set_certificate = FALSE;
+
+  client = SSL_get_ex_data (ssl, data_index);
+  tls = G_TLS_CONNECTION_BASE (client);
+  openssl = G_TLS_CONNECTION_OPENSSL (client);
+
+  priv = g_tls_client_connection_openssl_get_instance_private (client);
+
+  tls->certificate_requested = TRUE;
+
+  priv->ca_list = SSL_get_client_CA_list (priv->ssl);
+  g_object_notify (G_OBJECT (client), "accepted-cas");
+
+  cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
+  if (cert != NULL)
+    set_certificate = TRUE;
+  else
+    {
+      g_clear_error (&tls->certificate_error);
+      if (g_tls_connection_openssl_request_certificate (openssl, &tls->certificate_error))
+        {
+          cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
+          set_certificate = (cert != NULL);
+        }
+    }
+
+  if (set_certificate)
+    {
+      EVP_PKEY *key;
+
+      key = g_tls_certificate_openssl_get_key (G_TLS_CERTIFICATE_OPENSSL (cert));
+      /* increase ref count */
+      CRYPTO_add (&key->references, 1, CRYPTO_LOCK_EVP_PKEY);
+      *pkey = key;
+
+      *x509 = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
+
+      return 1;
+    }
+
+  return 0;
+}
+
+static int
+generate_session_id (const SSL     *ssl,
+                     unsigned char *id,
+                     unsigned int  *id_len)
+{
+  GTlsClientConnectionOpenssl *client;
+  GTlsClientConnectionOpensslPrivate *priv;
+  int len;
+
+  client = SSL_get_ex_data (ssl, data_index);
+  priv = g_tls_client_connection_openssl_get_instance_private (client);
+
+  len = MIN (*id_len, g_bytes_get_size (priv->session_id));
+  memcpy (id, g_bytes_get_data (priv->session_id, NULL), len);
+
+  return 1;
+}
+
+static gboolean
+g_tls_client_connection_openssl_initable_init (GInitable       *initable,
+                                               GCancellable    *cancellable,
+                                               GError         **error)
+{
+  GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (initable);
+  GTlsClientConnectionOpensslPrivate *priv;
+  long options;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (client);
+
+  priv->session = SSL_SESSION_new ();
+
+  priv->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
+  if (priv->ssl_ctx == NULL)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   _("Could not create TLS context: %s"),
+                   ERR_error_string (ERR_get_error (), NULL));
+      return FALSE;
+    }
+
+  options = SSL_OP_NO_TICKET;
+
+  /* Only TLS 1.2 or higher */
+  SSL_CTX_set_options (priv->ssl_ctx, options);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10200000L
+  {
+    const char *hostname;
+
+    hostname = get_server_identity (client);
+    if (hostname)
+      {
+        X509_VERIFY_PARAM *param;
+
+        param = X509_VERIFY_PARAM_new ();
+        X509_VERIFY_PARAM_set1_host (param, hostname);
+        SSL_CTX_set1_param (priv->ssl_ctx, param);
+        X509_VERIFY_PARAM_free (param);
+      }
+  }
+#endif
+
+  SSL_CTX_set_generate_session_id (priv->ssl_ctx, generate_session_id);
+  SSL_CTX_add_session (priv->ssl_ctx, priv->session);
+
+  SSL_CTX_set_client_cert_cb (priv->ssl_ctx, retrieve_certificate);
+
+  SSL_CTX_set_cipher_list (priv->ssl_ctx, "HIGH:!DSS:!aNULL STRENGTH");
+
+  priv->ssl = SSL_new (priv->ssl_ctx);
+  if (priv->ssl == NULL)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   _("Could not create TLS connection: %s"),
+                   ERR_error_string (ERR_get_error (), NULL));
+      return FALSE;
+    }
+
+  data_index = SSL_get_ex_new_index (0, "gtlsclientconnection", NULL, NULL, NULL);
+  SSL_set_ex_data (priv->ssl, data_index, client);
+
+  SSL_set_connect_state (priv->ssl);
+
+  if (!g_tls_client_connection_openssl_parent_initable_iface->
+      init (initable, cancellable, error))
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+g_tls_client_connection_openssl_initable_interface_init (GInitableIface  *iface)
+{
+  g_tls_client_connection_openssl_parent_initable_iface = g_type_interface_peek_parent (iface);
+
+  iface->init = g_tls_client_connection_openssl_initable_init;
+}
diff --git a/tls/openssl/gtlsclientconnection-openssl.h b/tls/openssl/gtlsclientconnection-openssl.h
new file mode 100644
index 0000000..e686fc1
--- /dev/null
+++ b/tls/openssl/gtlsclientconnection-openssl.h
@@ -0,0 +1,56 @@
+/*
+ * gtlsclientconnection-openssl.h
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#ifndef __G_TLS_CLIENT_CONNECTION_OPENSSL_H__
+#define __G_TLS_CLIENT_CONNECTION_OPENSSL_H__
+
+#include "gtlsconnection-openssl.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_CLIENT_CONNECTION_OPENSSL            (g_tls_client_connection_openssl_get_type ())
+#define G_TLS_CLIENT_CONNECTION_OPENSSL(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), 
G_TYPE_TLS_CLIENT_CONNECTION_OPENSSL, GTlsClientConnectionOpenssl))
+#define G_TLS_CLIENT_CONNECTION_OPENSSL_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), 
G_TYPE_TLS_CLIENT_CONNECTION_OPENSSL, GTlsClientConnectionOpensslClass))
+#define G_IS_TLS_CLIENT_CONNECTION_OPENSSL(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), 
G_TYPE_TLS_CLIENT_CONNECTION_OPENSSL))
+#define G_IS_TLS_CLIENT_CONNECTION_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), 
G_TYPE_TLS_CLIENT_CONNECTION_OPENSSL))
+#define G_TLS_CLIENT_CONNECTION_OPENSSL_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), 
G_TYPE_TLS_CLIENT_CONNECTION_OPENSSL, GTlsClientConnectionOpensslClass))
+
+typedef struct _GTlsClientConnectionOpensslClass   GTlsClientConnectionOpensslClass;
+typedef struct _GTlsClientConnectionOpenssl        GTlsClientConnectionOpenssl;
+
+struct _GTlsClientConnectionOpensslClass
+{
+  GTlsConnectionOpensslClass parent_class;
+};
+
+struct _GTlsClientConnectionOpenssl
+{
+  GTlsConnectionOpenssl parent_instance;
+};
+
+GType g_tls_client_connection_openssl_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_TLS_CLIENT_CONNECTION_OPENSSL_H___ */
diff --git a/tls/openssl/gtlsconnection-openssl.c b/tls/openssl/gtlsconnection-openssl.c
new file mode 100644
index 0000000..7c97fc9
--- /dev/null
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -0,0 +1,581 @@
+/*
+ * gtlsconnection-openssl.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "config.h"
+#include "glib.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "gtlsconnection-openssl.h"
+#include "gtlsbackend-openssl.h"
+#include "gtlscertificate-openssl.h"
+#include "gtlsbio.h"
+
+#include <glib/gi18n-lib.h>
+
+typedef struct _GTlsConnectionOpensslPrivate
+{
+  BIO *bio;
+
+  GTlsCertificate *peer_certificate_tmp;
+  GTlsCertificateFlags peer_certificate_errors_tmp;
+
+  gboolean shutting_down;
+} GTlsConnectionOpensslPrivate;
+
+static void g_tls_connection_openssl_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GTlsConnectionOpenssl, g_tls_connection_openssl, 
G_TYPE_TLS_CONNECTION_BASE,
+                                  G_ADD_PRIVATE (GTlsConnectionOpenssl)
+                                  G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                         g_tls_connection_openssl_initable_iface_init))
+
+static void
+g_tls_connection_openssl_finalize (GObject *object)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (object);
+  GTlsConnectionOpensslPrivate *priv;
+
+  priv = g_tls_connection_openssl_get_instance_private (openssl);
+
+  g_clear_object (&priv->peer_certificate_tmp);
+
+  G_OBJECT_CLASS (g_tls_connection_openssl_parent_class)->finalize (object);
+}
+
+static GTlsConnectionBaseStatus
+end_openssl_io (GTlsConnectionOpenssl  *openssl,
+                GIOCondition           direction,
+                int                    ret,
+                GError               **error,
+                const char            *err_fmt,
+                ...) G_GNUC_PRINTF(5, 6);
+
+static GTlsConnectionBaseStatus
+end_openssl_io (GTlsConnectionOpenssl  *openssl,
+                GIOCondition            direction,
+                int                     ret,
+                GError                **error,
+                const char             *err_fmt,
+                ...)
+{
+  GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (openssl);
+  GTlsConnectionOpensslPrivate *priv;
+  int err_code, err, reason;
+  GError *my_error = NULL;
+  GTlsConnectionBaseStatus status;
+  SSL *ssl;
+
+  priv = g_tls_connection_openssl_get_instance_private (openssl);
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+
+  err_code = SSL_get_error (ssl, ret);
+
+  status = g_tls_connection_base_pop_io (tls, direction, ret > 0, &my_error);
+
+  /* NOTE: this is tricky! The tls bio will set to retry if the operation
+   * would block, and we would get an error code with WANT_READ or WANT_WRITE,
+   * though if in that case we try again we would end up in an infinite loop
+   * since we will not let the glib main loop to do its stuff and we would
+   * be getting a would block forever. Instead we need to also check the error
+   * we get from the socket operation to understand whether to try again. See
+   * that we propagate the WOULD_BLOCK error a bit more down.
+   */
+  if ((err_code == SSL_ERROR_WANT_READ ||
+       err_code == SSL_ERROR_WANT_WRITE) &&
+      status != G_TLS_CONNECTION_BASE_WOULD_BLOCK)
+    {
+      if (my_error)
+        g_error_free (my_error);
+      return G_TLS_CONNECTION_BASE_TRY_AGAIN;
+    }
+
+  if (err_code == SSL_ERROR_ZERO_RETURN)
+    return G_TLS_CONNECTION_BASE_OK;
+
+  if (status == G_TLS_CONNECTION_BASE_OK ||
+      status == G_TLS_CONNECTION_BASE_WOULD_BLOCK ||
+      status == G_TLS_CONNECTION_BASE_TIMED_OUT)
+    {
+      if (my_error)
+        g_propagate_error (error, my_error);
+      return status;
+    }
+
+  /* This case is documented that it may happen and that is perfectly fine */
+  if (err_code == SSL_ERROR_SYSCALL && priv->shutting_down && !my_error)
+    return G_TLS_CONNECTION_BASE_OK;
+
+  err = ERR_get_error ();
+  reason = ERR_GET_REASON (err);
+
+  if (tls->handshaking && !tls->ever_handshaked)
+    {
+      if (reason == SSL_R_BAD_PACKET_LENGTH ||
+          reason == SSL_R_UNKNOWN_ALERT_TYPE ||
+          reason == SSL_R_DECRYPTION_FAILED ||
+          reason == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC ||
+          reason == SSL_R_BAD_PROTOCOL_VERSION_NUMBER ||
+          reason == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE ||
+          reason == SSL_R_UNKNOWN_PROTOCOL)
+        {
+          g_clear_error (&my_error);
+          g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
+                               _("Peer failed to perform TLS handshake"));
+          return G_TLS_CONNECTION_BASE_ERROR;
+        }
+    }
+
+  if (reason == SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE ||
+      reason == SSL_R_NO_CERTIFICATE_RETURNED)
+    {
+      g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED,
+                           _("TLS connection peer did not send a certificate"));
+      return status;
+    }
+
+  if (my_error != NULL)
+    g_propagate_error (error, my_error);
+  else
+    /* FIXME: this is just for debug */
+    g_message ("end_openssl_io %s: %d, %d", G_IS_TLS_CLIENT_CONNECTION (openssl) ? "client" : "server", 
err_code, reason);
+
+  if (error && !*error)
+    {
+      va_list ap;
+
+      va_start (ap, err_fmt);
+      *error = g_error_new_valist (G_TLS_ERROR, G_TLS_ERROR_MISC, err_fmt, ap);
+      va_end (ap);
+    }
+
+  return G_TLS_CONNECTION_BASE_ERROR;
+}
+
+#define BEGIN_OPENSSL_IO(openssl, direction, blocking, cancellable)        \
+  g_tls_connection_base_push_io (G_TLS_CONNECTION_BASE (openssl),        \
+                                 direction, blocking, cancellable);        \
+  do {
+
+#define END_OPENSSL_IO(openssl, direction, ret, status, errmsg, err)        \
+    status = end_openssl_io (openssl, direction, ret, err, errmsg, ERR_error_string (SSL_get_error (ssl, 
ret), NULL)); \
+  } while (status == G_TLS_CONNECTION_BASE_TRY_AGAIN);
+
+static GTlsConnectionBaseStatus
+g_tls_connection_openssl_request_rehandshake (GTlsConnectionBase  *tls,
+                                              GCancellable        *cancellable,
+                                              GError             **error)
+{
+  GTlsConnectionOpenssl *openssl;
+  GTlsConnectionBaseStatus status;
+  SSL *ssl;
+  int ret;
+
+  /* On a client-side connection, SSL_renegotiate() itself will start
+   * a rehandshake, so we only need to do something special here for
+   * server-side connections.
+   */
+  if (!G_IS_TLS_SERVER_CONNECTION (tls))
+    return G_TLS_CONNECTION_BASE_OK;
+
+  openssl = G_TLS_CONNECTION_OPENSSL (tls);
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+
+  BEGIN_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, TRUE, cancellable);
+  ret = SSL_renegotiate (ssl);
+  END_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, ret, status,
+                  _("Error performing TLS handshake: %s"), error);
+
+  return status;
+}
+
+static GTlsCertificate *
+get_peer_certificate (GTlsConnectionOpenssl *openssl)
+{
+  X509 *peer;
+  STACK_OF (X509) *certs;
+  GTlsCertificateOpenssl *chain;
+  SSL *ssl;
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+
+  peer = SSL_get_peer_certificate (ssl);
+  if (peer == NULL)
+    return NULL;
+
+  certs = SSL_get_peer_cert_chain (ssl);
+  if (certs == NULL)
+    return NULL;
+
+  chain = g_tls_certificate_openssl_build_chain (peer, certs);
+  if (!chain)
+    return NULL;
+
+  return G_TLS_CERTIFICATE (chain);
+}
+
+static GTlsCertificateFlags
+verify_peer_certificate (GTlsConnectionOpenssl *openssl,
+                         GTlsCertificate       *peer_certificate)
+{
+  GTlsConnection *conn = G_TLS_CONNECTION (openssl);
+  GSocketConnectable *peer_identity;
+  GTlsDatabase *database;
+  GTlsCertificateFlags errors;
+  gboolean is_client;
+
+  is_client = G_IS_TLS_CLIENT_CONNECTION (openssl);
+  if (is_client)
+    peer_identity = g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION (openssl));
+  else
+    peer_identity = NULL;
+
+  errors = 0;
+
+  database = g_tls_connection_get_database (conn);
+  if (database == NULL)
+    {
+      errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+      errors |= g_tls_certificate_verify (peer_certificate, peer_identity, NULL);
+    }
+  else
+    {
+      GError *error = NULL;
+
+      errors |= g_tls_database_verify_chain (database, peer_certificate,
+                                             is_client ?
+                                             G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER :
+                                             G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
+                                             peer_identity,
+                                             g_tls_connection_get_interaction (conn),
+                                             G_TLS_DATABASE_VERIFY_NONE,
+                                             NULL, &error);
+      if (error)
+        {
+          g_warning ("failure verifying certificate chain: %s",
+                     error->message);
+          g_assert (errors != 0);
+          g_clear_error (&error);
+        }
+    }
+
+  return errors;
+}
+
+static GTlsConnectionBaseStatus
+g_tls_connection_openssl_handshake (GTlsConnectionBase  *tls,
+                                    GCancellable        *cancellable,
+                                    GError             **error)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
+  GTlsConnectionOpensslPrivate *priv;
+  GTlsConnectionBaseStatus status;
+  SSL *ssl;
+  int ret;
+
+  priv = g_tls_connection_openssl_get_instance_private (openssl);
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+
+  BEGIN_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, TRUE, cancellable);
+  ret = SSL_do_handshake (ssl);
+  END_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, ret, status,
+                  _("Error performing TLS handshake: %s"), error);
+
+  if (ret > 0)
+    {
+      priv->peer_certificate_tmp = get_peer_certificate (openssl);
+      if (priv->peer_certificate_tmp)
+        priv->peer_certificate_errors_tmp = verify_peer_certificate (openssl, priv->peer_certificate_tmp);
+      else if (G_IS_TLS_CLIENT_CONNECTION (openssl))
+        {
+          g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                               _("Server did not return a valid TLS certificate"));
+        }
+    }
+
+  return status;
+}
+
+static GTlsConnectionBaseStatus
+g_tls_connection_openssl_complete_handshake (GTlsConnectionBase  *tls,
+                                             GError             **error)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
+  GTlsConnectionOpensslPrivate *priv;
+  GTlsCertificate *peer_certificate;
+  GTlsCertificateFlags peer_certificate_errors = 0;
+  GTlsConnectionBaseStatus status = G_TLS_CONNECTION_BASE_OK;
+
+  priv = g_tls_connection_openssl_get_instance_private (openssl);
+
+  peer_certificate = priv->peer_certificate_tmp;
+  priv->peer_certificate_tmp = NULL;
+  peer_certificate_errors = priv->peer_certificate_errors_tmp;
+  priv->peer_certificate_errors_tmp = 0;
+
+  if (peer_certificate)
+    {
+      if (!g_tls_connection_base_accept_peer_certificate (tls, peer_certificate,
+                                                          peer_certificate_errors))
+        {
+          g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                               _("Unacceptable TLS certificate"));
+          status = G_TLS_CONNECTION_BASE_ERROR;
+        }
+
+      g_tls_connection_base_set_peer_certificate (G_TLS_CONNECTION_BASE (openssl),
+                                                  peer_certificate,
+                                                  peer_certificate_errors);
+      g_clear_object (&peer_certificate);
+    }
+
+  return status;
+}
+
+static void
+g_tls_connection_openssl_push_io (GTlsConnectionBase *tls,
+                                  GIOCondition        direction,
+                                  gboolean            blocking,
+                                  GCancellable       *cancellable)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
+  GTlsConnectionOpensslPrivate *priv;
+
+  priv = g_tls_connection_openssl_get_instance_private (openssl);
+
+  G_TLS_CONNECTION_BASE_CLASS (g_tls_connection_openssl_parent_class)->push_io (tls, direction,
+                                                                                blocking, cancellable);
+
+  if (direction & G_IO_IN)
+    {
+      g_tls_bio_set_read_cancellable (priv->bio, cancellable);
+      g_tls_bio_set_read_blocking (priv->bio, blocking);
+      g_clear_error (&tls->read_error);
+      g_tls_bio_set_read_error (priv->bio, &tls->read_error);
+    }
+
+  if (direction & G_IO_OUT)
+    {
+      g_tls_bio_set_write_cancellable (priv->bio, cancellable);
+      g_tls_bio_set_write_blocking (priv->bio, blocking);
+      g_clear_error (&tls->write_error);
+      g_tls_bio_set_write_error (priv->bio, &tls->write_error);
+    }
+}
+
+static GTlsConnectionBaseStatus
+g_tls_connection_openssl_pop_io (GTlsConnectionBase  *tls,
+                                 GIOCondition         direction,
+                                 gboolean             success,
+                                 GError             **error)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
+  GTlsConnectionOpensslPrivate *priv;
+
+  priv = g_tls_connection_openssl_get_instance_private (openssl);
+
+  if (direction & G_IO_IN)
+    g_tls_bio_set_read_cancellable (priv->bio, NULL);
+
+  if (direction & G_IO_OUT)
+    g_tls_bio_set_write_cancellable (priv->bio, NULL);
+
+  return G_TLS_CONNECTION_BASE_CLASS (g_tls_connection_openssl_parent_class)->pop_io (tls, direction,
+                                                                                      success, error);
+}
+
+static GTlsConnectionBaseStatus
+g_tls_connection_openssl_read (GTlsConnectionBase    *tls,
+                               void                  *buffer,
+                               gsize                  count,
+                               gboolean               blocking,
+                               gssize                *nread,
+                               GCancellable          *cancellable,
+                               GError               **error)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
+  GTlsConnectionBaseStatus status;
+  SSL *ssl;
+  gssize ret;
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+
+  BEGIN_OPENSSL_IO (openssl, G_IO_IN, blocking, cancellable);
+  ret = SSL_read (ssl, buffer, count);
+  END_OPENSSL_IO (openssl, G_IO_IN, ret, status,
+                  _("Error reading data from TLS socket: %s"), error);
+
+  if (ret >= 0)
+    *nread = ret;
+  return status;
+}
+
+static GTlsConnectionBaseStatus
+g_tls_connection_openssl_write (GTlsConnectionBase    *tls,
+                                const void            *buffer,
+                                gsize                  count,
+                                gboolean               blocking,
+                                gssize                *nwrote,
+                                GCancellable          *cancellable,
+                                GError               **error)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
+  GTlsConnectionBaseStatus status;
+  SSL *ssl;
+  gssize ret;
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+
+  BEGIN_OPENSSL_IO (openssl, G_IO_OUT, blocking, cancellable);
+  ret = SSL_write (ssl, buffer, count);
+  END_OPENSSL_IO (openssl, G_IO_OUT, ret, status,
+                  _("Error writing data to TLS socket: %s"), error);
+
+  if (ret >= 0)
+    *nwrote = ret;
+  return status;
+}
+
+static GTlsConnectionBaseStatus
+g_tls_connection_openssl_close (GTlsConnectionBase  *tls,
+                                GCancellable        *cancellable,
+                                GError             **error)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
+  GTlsConnectionOpensslPrivate *priv;
+  GTlsConnectionBaseStatus status;
+  SSL *ssl;
+  int ret;
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+  priv = g_tls_connection_openssl_get_instance_private (openssl);
+
+  priv->shutting_down = TRUE;
+
+  BEGIN_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, TRUE, cancellable);
+  ret = SSL_shutdown (ssl);
+  END_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, ret, status,
+                  _("Error performing TLS close: %s"), error);
+
+  return status;
+}
+
+static void
+g_tls_connection_openssl_class_init (GTlsConnectionOpensslClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
+
+  gobject_class->finalize     = g_tls_connection_openssl_finalize;
+
+  base_class->request_rehandshake = g_tls_connection_openssl_request_rehandshake;
+  base_class->handshake           = g_tls_connection_openssl_handshake;
+  base_class->complete_handshake  = g_tls_connection_openssl_complete_handshake;
+  base_class->push_io             = g_tls_connection_openssl_push_io;
+  base_class->pop_io              = g_tls_connection_openssl_pop_io;
+  base_class->read_fn             = g_tls_connection_openssl_read;
+  base_class->write_fn            = g_tls_connection_openssl_write;
+  base_class->close_fn            = g_tls_connection_openssl_close;
+}
+
+static gboolean
+g_tls_connection_openssl_initable_init (GInitable     *initable,
+                                        GCancellable  *cancellable,
+                                        GError       **error)
+{
+  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (initable);
+  GTlsConnectionOpensslPrivate *priv;
+  GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (initable);
+  SSL *ssl;
+
+  g_return_val_if_fail (tls->base_istream != NULL &&
+                        tls->base_ostream != NULL, FALSE);
+
+  priv = g_tls_connection_openssl_get_instance_private (openssl);
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+  g_assert (ssl != NULL);
+
+  priv->bio = g_tls_bio_new (tls->base_io_stream);
+
+  SSL_set_bio (ssl, priv->bio, priv->bio);
+
+  return TRUE;
+}
+
+static void
+g_tls_connection_openssl_initable_iface_init (GInitableIface *iface)
+{
+  iface->init = g_tls_connection_openssl_initable_init;
+}
+
+static void
+g_tls_connection_openssl_init (GTlsConnectionOpenssl *openssl)
+{
+}
+
+SSL *
+g_tls_connection_openssl_get_ssl (GTlsConnectionOpenssl *openssl)
+{
+  g_return_val_if_fail (G_IS_TLS_CONNECTION_OPENSSL (openssl), NULL);
+
+  return G_TLS_CONNECTION_OPENSSL_GET_CLASS (openssl)->get_ssl (openssl);
+}
+
+SSL_CTX *
+g_tls_connection_openssl_get_ssl_ctx (GTlsConnectionOpenssl *openssl)
+{
+  g_return_val_if_fail (G_IS_TLS_CONNECTION_OPENSSL (openssl), NULL);
+
+  return G_TLS_CONNECTION_OPENSSL_GET_CLASS (openssl)->get_ssl_ctx (openssl);
+}
+
+gboolean
+g_tls_connection_openssl_request_certificate (GTlsConnectionOpenssl  *openssl,
+                                              GError                **error)
+{
+  GTlsInteractionResult res = G_TLS_INTERACTION_UNHANDLED;
+  GTlsInteraction *interaction;
+  GTlsConnection *conn;
+  GTlsConnectionBase *tls;
+
+  g_return_val_if_fail (G_IS_TLS_CONNECTION_OPENSSL (openssl), FALSE);
+
+  conn = G_TLS_CONNECTION (openssl);
+  tls = G_TLS_CONNECTION_BASE (openssl);
+
+  interaction = g_tls_connection_get_interaction (conn);
+  if (!interaction)
+    return FALSE;
+
+  res = g_tls_interaction_invoke_request_certificate (interaction, conn, 0,
+                                                     tls->read_cancellable, error);
+  return res != G_TLS_INTERACTION_FAILED;
+}
diff --git a/tls/openssl/gtlsconnection-openssl.h b/tls/openssl/gtlsconnection-openssl.h
new file mode 100644
index 0000000..0689189
--- /dev/null
+++ b/tls/openssl/gtlsconnection-openssl.h
@@ -0,0 +1,68 @@
+/*
+ * gtlsconnection-openssl.h
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#ifndef __G_TLS_CONNECTION_OPENSSL_H__
+#define __G_TLS_CONNECTION_OPENSSL_H__
+
+#include <gio/gio.h>
+
+#include "gtlsconnection-base.h"
+#include <openssl/ssl.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_CONNECTION_OPENSSL            (g_tls_connection_openssl_get_type ())
+#define G_TLS_CONNECTION_OPENSSL(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), 
G_TYPE_TLS_CONNECTION_OPENSSL, GTlsConnectionOpenssl))
+#define G_TLS_CONNECTION_OPENSSL_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), 
G_TYPE_TLS_CONNECTION_OPENSSL, GTlsConnectionOpensslClass))
+#define G_IS_TLS_CONNECTION_OPENSSL(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), 
G_TYPE_TLS_CONNECTION_OPENSSL))
+#define G_IS_TLS_CONNECTION_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), 
G_TYPE_TLS_CONNECTION_OPENSSL))
+#define G_TLS_CONNECTION_OPENSSL_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), 
G_TYPE_TLS_CONNECTION_OPENSSL, GTlsConnectionOpensslClass))
+
+typedef struct _GTlsConnectionOpensslClass GTlsConnectionOpensslClass;
+typedef struct _GTlsConnectionOpenssl      GTlsConnectionOpenssl;
+
+struct _GTlsConnectionOpensslClass
+{
+  GTlsConnectionBaseClass parent_class;
+
+  SSL     *(*get_ssl)     (GTlsConnectionOpenssl *connection);
+  SSL_CTX *(*get_ssl_ctx) (GTlsConnectionOpenssl *connection);
+};
+
+struct _GTlsConnectionOpenssl
+{
+  GTlsConnectionBase parent_instance;
+};
+
+GType g_tls_connection_openssl_get_type (void) G_GNUC_CONST;
+
+SSL     *g_tls_connection_openssl_get_ssl     (GTlsConnectionOpenssl *connection);
+SSL_CTX *g_tls_connection_openssl_get_ssl_ctx (GTlsConnectionOpenssl *connection);
+
+gboolean g_tls_connection_openssl_request_certificate (GTlsConnectionOpenssl  *openssl,
+                                                       GError                **error);
+
+G_END_DECLS
+
+#endif /* __G_TLS_CONNECTION_OPENSSL_H___ */
diff --git a/tls/openssl/gtlsdatabase-openssl.c b/tls/openssl/gtlsdatabase-openssl.c
new file mode 100644
index 0000000..93461a2
--- /dev/null
+++ b/tls/openssl/gtlsdatabase-openssl.c
@@ -0,0 +1,39 @@
+/*
+ * gtlsdatabase-openssl.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "config.h"
+
+#include "gtlsdatabase-openssl.h"
+
+G_DEFINE_ABSTRACT_TYPE (GTlsDatabaseOpenssl, g_tls_database_openssl, G_TYPE_TLS_DATABASE)
+
+static void
+g_tls_database_openssl_class_init (GTlsDatabaseOpensslClass *klass)
+{
+}
+
+static void
+g_tls_database_openssl_init (GTlsDatabaseOpenssl *openssl)
+{
+}
diff --git a/tls/openssl/gtlsdatabase-openssl.h b/tls/openssl/gtlsdatabase-openssl.h
new file mode 100644
index 0000000..fd31352
--- /dev/null
+++ b/tls/openssl/gtlsdatabase-openssl.h
@@ -0,0 +1,63 @@
+/*
+ * gtlsdatabase-openssl.h
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#ifndef __G_TLS_DATABASE_OPENSSL_H__
+#define __G_TLS_DATABASE_OPENSSL_H__
+
+#include <gio/gio.h>
+
+#include "gtlscertificate-openssl.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+  G_TLS_DATABASE_OPENSSL_PINNED_CERTIFICATE = 1,
+  G_TLS_DATABASE_OPENSSL_ANCHORED_CERTIFICATE = 2,
+} GTlsDatabaseOpensslAssertion;
+
+#define G_TYPE_TLS_DATABASE_OPENSSL            (g_tls_database_openssl_get_type ())
+#define G_TLS_DATABASE_OPENSSL(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), 
G_TYPE_TLS_DATABASE_OPENSSL, GTlsDatabaseOpenssl))
+#define G_TLS_DATABASE_OPENSSL_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), 
G_TYPE_TLS_DATABASE_OPENSSL, GTlsDatabaseOpensslClass))
+#define G_IS_TLS_DATABASE_OPENSSL(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), 
G_TYPE_TLS_DATABASE_OPENSSL))
+#define G_IS_TLS_DATABASE_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), 
G_TYPE_TLS_DATABASE_OPENSSL))
+#define G_TLS_DATABASE_OPENSSL_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), 
G_TYPE_TLS_DATABASE_OPENSSL, GTlsDatabaseOpensslClass))
+
+typedef struct _GTlsDatabaseOpensslClass GTlsDatabaseOpensslClass;
+typedef struct _GTlsDatabaseOpenssl      GTlsDatabaseOpenssl;
+
+struct _GTlsDatabaseOpensslClass
+{
+  GTlsDatabaseClass parent_class;
+};
+
+struct _GTlsDatabaseOpenssl
+{
+  GTlsDatabase parent_instance;
+};
+
+GType          g_tls_database_openssl_get_type              (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_TLS_DATABASE_OPENSSL_H___ */
diff --git a/tls/openssl/gtlsfiledatabase-openssl.c b/tls/openssl/gtlsfiledatabase-openssl.c
new file mode 100644
index 0000000..8f906b4
--- /dev/null
+++ b/tls/openssl/gtlsfiledatabase-openssl.c
@@ -0,0 +1,916 @@
+/*
+ * gtlsfiledatabase-openssl.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "config.h"
+
+#include "gtlsfiledatabase-openssl.h"
+
+#include <gio/gio.h>
+#include <glib/gi18n-lib.h>
+#include <openssl/ssl.h>
+
+typedef struct _GTlsFileDatabaseOpensslPrivate
+{
+  /* read-only after construct */
+  gchar *anchor_filename;
+
+  /* protected by mutex */
+  GMutex mutex;
+
+  /*
+   * These are hash tables of gulong -> GPtrArray<GBytes>. The values of
+   * the ptr array are full DER encoded certificate values. The keys are byte
+   * arrays containing either subject DNs, issuer DNs, or full DER encoded certs
+   */
+  GHashTable *subjects;
+  GHashTable *issuers;
+
+  /*
+   * This is a table of GBytes -> GBytes. The values and keys are
+   * DER encoded certificate values.
+   */
+  GHashTable *complete;
+
+  /*
+   * This is a table of gchar * -> GTlsCertificate.
+   */
+  GHashTable *certs_by_handle;
+} GTlsFileDatabaseOpensslPrivate;
+
+enum {
+  STATUS_FAILURE,
+  STATUS_INCOMPLETE,
+  STATUS_SELFSIGNED,
+  STATUS_PINNED,
+  STATUS_ANCHORED,
+};
+
+enum
+{
+  PROP_0,
+  PROP_ANCHORS,
+};
+
+static void g_tls_file_database_openssl_file_database_interface_init (GTlsFileDatabaseInterface *iface);
+
+static void g_tls_file_database_openssl_initable_interface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTlsFileDatabaseOpenssl, g_tls_file_database_openssl, G_TYPE_TLS_DATABASE_OPENSSL,
+                         G_ADD_PRIVATE (GTlsFileDatabaseOpenssl)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_TLS_FILE_DATABASE,
+                                                g_tls_file_database_openssl_file_database_interface_init)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                g_tls_file_database_openssl_initable_interface_init))
+
+static GHashTable *
+bytes_multi_table_new (void)
+{
+  return g_hash_table_new_full (g_int_hash, g_int_equal,
+                                (GDestroyNotify)g_free,
+                                (GDestroyNotify)g_ptr_array_unref);
+}
+
+static void
+bytes_multi_table_insert (GHashTable *table,
+                          gulong      key,
+                          GBytes     *value)
+{
+  GPtrArray *multi;
+
+  multi = g_hash_table_lookup (table, &key);
+  if (multi == NULL)
+    {
+      int *key_ptr;
+
+      key_ptr = g_new (int, 1);
+      *key_ptr = (int)key;
+      multi = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
+      g_hash_table_insert (table, key_ptr, multi);
+    }
+  g_ptr_array_add (multi, g_bytes_ref (value));
+}
+
+static GBytes *
+bytes_multi_table_lookup_ref_one (GHashTable *table,
+                                  gulong      key)
+{
+  GPtrArray *multi;
+
+  multi = g_hash_table_lookup (table, &key);
+  if (multi == NULL)
+    return NULL;
+
+  g_assert (multi->len > 0);
+  return g_bytes_ref (multi->pdata[0]);
+}
+
+static GList *
+bytes_multi_table_lookup_ref_all (GHashTable *table,
+                                  gulong      key)
+{
+  GPtrArray *multi;
+  GList *list = NULL;
+  guint i;
+
+  multi = g_hash_table_lookup (table, &key);
+  if (multi == NULL)
+    return NULL;
+
+  for (i = 0; i < multi->len; i++)
+    list = g_list_prepend (list, g_bytes_ref (multi->pdata[i]));
+
+  return g_list_reverse (list);
+}
+
+static gchar *
+create_handle_for_certificate (const gchar *filename,
+                               GBytes      *der)
+{
+  gchar *bookmark;
+  gchar *uri_part;
+  gchar *uri;
+
+  /*
+   * Here we create a URI that looks like:
+   * 
file:///etc/ssl/certs/ca-certificates.crt#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f
+   */
+
+  uri_part = g_filename_to_uri (filename, NULL, NULL);
+  if (!uri_part)
+    return NULL;
+
+  bookmark = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, der);
+  uri = g_strconcat (uri_part, "#", bookmark, NULL);
+
+  g_free (bookmark);
+  g_free (uri_part);
+
+  return uri;
+}
+
+static gboolean
+load_anchor_file (GTlsFileDatabaseOpenssl  *file_database,
+                  const gchar              *filename,
+                  GHashTable               *subjects,
+                  GHashTable               *issuers,
+                  GHashTable               *complete,
+                  GHashTable               *certs_by_handle,
+                  GError                  **error)
+{
+  GTlsFileDatabaseOpensslPrivate *priv;
+  GList *list;
+  GList *l;
+  GBytes *der;
+  gchar *handle;
+  GError *my_error = NULL;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  list = g_tls_certificate_list_new_from_file (filename, &my_error);
+  if (my_error)
+    {
+      g_propagate_error (error, my_error);
+      return FALSE;
+    }
+
+  for (l = list; l; l = l->next)
+    {
+      X509 *x;
+      unsigned long subject;
+      unsigned long issuer;
+
+      x = g_tls_certificate_openssl_get_cert (l->data);
+      subject = X509_subject_name_hash (x);
+      issuer = X509_issuer_name_hash (x);
+
+      der = g_tls_certificate_openssl_get_bytes (l->data);
+      g_return_val_if_fail (der != NULL, FALSE);
+
+      g_hash_table_insert (complete, g_bytes_ref (der),
+                           g_bytes_ref (der));
+
+      bytes_multi_table_insert (subjects, subject, der);
+      bytes_multi_table_insert (issuers, issuer, der);
+
+      handle = create_handle_for_certificate (priv->anchor_filename, der);
+      g_hash_table_insert (certs_by_handle, handle, g_object_ref (l->data));
+
+      g_bytes_unref (der);
+
+      g_object_unref (l->data);
+    }
+  g_list_free (list);
+
+  return TRUE;
+}
+
+static void
+g_tls_file_database_openssl_finalize (GObject *object)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
+  GTlsFileDatabaseOpensslPrivate *priv;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  g_clear_pointer (&priv->subjects, g_hash_table_destroy);
+  g_clear_pointer (&priv->issuers, g_hash_table_destroy);
+  g_clear_pointer (&priv->complete, g_hash_table_destroy);
+  g_clear_pointer (&priv->certs_by_handle, g_hash_table_destroy);
+
+  g_free (priv->anchor_filename);
+  priv->anchor_filename = NULL;
+
+  g_mutex_clear (&priv->mutex);
+
+  G_OBJECT_CLASS (g_tls_file_database_openssl_parent_class)->finalize (object);
+}
+
+static void
+g_tls_file_database_openssl_get_property (GObject    *object,
+                                          guint       prop_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
+  GTlsFileDatabaseOpensslPrivate *priv;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  switch (prop_id)
+    {
+    case PROP_ANCHORS:
+      g_value_set_string (value, priv->anchor_filename);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_file_database_openssl_set_property (GObject      *object,
+                                          guint         prop_id,
+                                          const GValue *value,
+                                          GParamSpec   *pspec)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
+  GTlsFileDatabaseOpensslPrivate *priv;
+  gchar *anchor_path;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  switch (prop_id)
+    {
+    case PROP_ANCHORS:
+      anchor_path = g_value_dup_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
+        {
+          priv->anchor_filename = anchor_path;
+        }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_file_database_openssl_init (GTlsFileDatabaseOpenssl *file_database)
+{
+  GTlsFileDatabaseOpensslPrivate *priv;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  g_mutex_init (&priv->mutex);
+}
+
+static gchar *
+g_tls_file_database_openssl_create_certificate_handle (GTlsDatabase    *database,
+                                                       GTlsCertificate *certificate)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
+  GTlsFileDatabaseOpensslPrivate *priv;
+  GBytes *der;
+  gboolean contains;
+  gchar *handle = NULL;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  der = g_tls_certificate_openssl_get_bytes (G_TLS_CERTIFICATE_OPENSSL (certificate));
+  g_return_val_if_fail (der != NULL, FALSE);
+
+  g_mutex_lock (&priv->mutex);
+
+  /* At the same time look up whether this certificate is in list */
+  contains = g_hash_table_lookup (priv->complete, der) ? TRUE : FALSE;
+
+  g_mutex_unlock (&priv->mutex);
+
+  /* Certificate is in the database */
+  if (contains)
+    handle = create_handle_for_certificate (priv->anchor_filename, der);
+
+  g_bytes_unref (der);
+  return handle;
+}
+
+static GTlsCertificate *
+g_tls_file_database_openssl_lookup_certificate_for_handle (GTlsDatabase            *database,
+                                                           const gchar             *handle,
+                                                           GTlsInteraction         *interaction,
+                                                           GTlsDatabaseLookupFlags  flags,
+                                                           GCancellable            *cancellable,
+                                                           GError                 **error)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
+  GTlsFileDatabaseOpensslPrivate *priv;
+  GTlsCertificate *cert;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return NULL;
+
+  if (!handle)
+    return NULL;
+
+  g_mutex_lock (&priv->mutex);
+
+  cert = g_hash_table_lookup (priv->certs_by_handle, handle);
+
+  g_mutex_unlock (&priv->mutex);
+
+  return cert ? g_object_ref (cert) : NULL;
+}
+
+static GTlsCertificate *
+g_tls_file_database_openssl_lookup_certificate_issuer (GTlsDatabase             *database,
+                                                       GTlsCertificate          *certificate,
+                                                       GTlsInteraction          *interaction,
+                                                       GTlsDatabaseLookupFlags   flags,
+                                                       GCancellable             *cancellable,
+                                                       GError                  **error)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
+  GTlsFileDatabaseOpensslPrivate *priv;
+  X509 *x;
+  unsigned long issuer_hash;
+  GBytes *der;
+  GTlsCertificate *issuer = NULL;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (certificate), NULL);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return NULL;
+
+  if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
+    return NULL;
+
+  /* Dig out the issuer of this certificate */
+  x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (certificate));
+  issuer_hash = X509_issuer_name_hash (x);
+
+  g_mutex_lock (&priv->mutex);
+  der = bytes_multi_table_lookup_ref_one (priv->subjects, issuer_hash);
+  g_mutex_unlock (&priv->mutex);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    issuer = NULL;
+  else if (der != NULL)
+    issuer = g_tls_certificate_openssl_new (der, NULL);
+
+  if (der != NULL)
+    g_bytes_unref (der);
+  return issuer;
+
+  return NULL;
+}
+
+static GList *
+g_tls_file_database_openssl_lookup_certificates_issued_by (GTlsDatabase             *database,
+                                                           GByteArray               *issuer_raw_dn,
+                                                           GTlsInteraction          *interaction,
+                                                           GTlsDatabaseLookupFlags   flags,
+                                                           GCancellable             *cancellable,
+                                                           GError                  **error)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
+  GTlsFileDatabaseOpensslPrivate *priv;
+  X509_NAME *x_name;
+  const unsigned char *in;
+  GList *issued = NULL;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return NULL;
+
+  /* We don't have any private keys here */
+  if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
+    return NULL;
+
+  in = issuer_raw_dn->data;
+  x_name = d2i_X509_NAME (NULL, &in, issuer_raw_dn->len);
+  if (x_name != NULL)
+    {
+      unsigned long issuer_hash;
+      GList *ders, *l;
+
+      issuer_hash = X509_NAME_hash (x_name);
+
+      /* Find the full DER value of the certificate */
+      g_mutex_lock (&priv->mutex);
+      ders = bytes_multi_table_lookup_ref_all (priv->issuers, issuer_hash);
+      g_mutex_unlock (&priv->mutex);
+
+      for (l = ders; l != NULL; l = g_list_next (l))
+        {
+          if (g_cancellable_set_error_if_cancelled (cancellable, error))
+            {
+              g_list_free_full (issued, g_object_unref);
+              issued = NULL;
+              break;
+            }
+
+          issued = g_list_prepend (issued, g_tls_certificate_openssl_new (l->data, NULL));
+        }
+
+      g_list_free_full (ders, (GDestroyNotify)g_bytes_unref);
+      X509_NAME_free (x_name);
+    }
+
+  return issued;
+}
+
+static gboolean
+lookup_assertion (GTlsDatabaseOpenssl           *database,
+                  GTlsCertificateOpenssl        *certificate,
+                  GTlsDatabaseOpensslAssertion   assertion,
+                  const gchar                   *purpose,
+                  GSocketConnectable            *identity,
+                  GCancellable                  *cancellable,
+                  GError                       **error)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
+  GTlsFileDatabaseOpensslPrivate *priv;
+  GBytes *der = NULL;
+  gboolean contains;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return FALSE;
+
+  /* We only have anchored certificate assertions here */
+  if (assertion != G_TLS_DATABASE_OPENSSL_ANCHORED_CERTIFICATE)
+    return FALSE;
+
+  /*
+   * TODO: We should be parsing any Extended Key Usage attributes and
+   * comparing them to the purpose.
+   */
+
+  der = g_tls_certificate_openssl_get_bytes (certificate);
+
+  g_mutex_lock (&priv->mutex);
+  contains = g_hash_table_lookup (priv->complete, der) ? TRUE : FALSE;
+  g_mutex_unlock (&priv->mutex);
+
+  g_bytes_unref (der);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return FALSE;
+
+  /* All certificates in our file are anchored certificates */
+  return contains;
+}
+
+static gboolean
+is_self_signed (GTlsCertificateOpenssl *certificate)
+{
+  X509 *cert;
+  X509_STORE *store;
+  X509_STORE_CTX csc;
+  STACK_OF(X509) *trusted;
+  gboolean ret = FALSE;
+
+  store = X509_STORE_new ();
+  cert = g_tls_certificate_openssl_get_cert (certificate);
+
+  if (!X509_STORE_CTX_init(&csc, store, cert, NULL))
+    goto end;
+
+  trusted = sk_X509_new_null ();
+  sk_X509_push (trusted, cert);
+
+  X509_STORE_CTX_trusted_stack (&csc, trusted);
+  X509_STORE_CTX_set_flags (&csc, X509_V_FLAG_CHECK_SS_SIGNATURE);
+
+  ret = X509_verify_cert (&csc) > 0;
+  sk_X509_free (trusted);
+
+end:
+  X509_STORE_CTX_cleanup (&csc);
+  X509_STORE_free (store);
+
+  return ret;
+}
+
+static gint
+build_certificate_chain (GTlsDatabaseOpenssl     *openssl,
+                         GTlsCertificateOpenssl  *chain,
+                         const gchar             *purpose,
+                         GSocketConnectable      *identity,
+                         GTlsInteraction         *interaction,
+                         GTlsDatabaseVerifyFlags  flags,
+                         GCancellable            *cancellable,
+                         GTlsCertificateOpenssl  **anchor,
+                         GError                 **error)
+{
+
+  GTlsCertificateOpenssl *certificate;
+  GTlsCertificateOpenssl *previous;
+  GTlsCertificate *issuer;
+  gboolean certificate_is_from_db;
+
+  g_assert (anchor);
+  g_assert (chain);
+  g_assert (purpose);
+  g_assert (error);
+  g_assert (!*error);
+
+  /*
+   * Remember that the first certificate never changes in the chain.
+   * When we find a self-signed, pinned or anchored certificate, all
+   * issuers are truncated from the chain.
+   */
+
+  *anchor = NULL;
+  previous = NULL;
+  certificate = chain;
+  certificate_is_from_db = FALSE;
+
+  /* First check for pinned certificate */
+  if (lookup_assertion (openssl, certificate,
+                        G_TLS_DATABASE_OPENSSL_PINNED_CERTIFICATE,
+                        purpose, identity, cancellable, error))
+    {
+      g_tls_certificate_openssl_set_issuer (certificate, NULL);
+      return STATUS_PINNED;
+    }
+  else if (*error)
+    {
+      return STATUS_FAILURE;
+    }
+
+  for (;;)
+    {
+      if (g_cancellable_set_error_if_cancelled (cancellable, error))
+        return STATUS_FAILURE;
+
+      /* Look up whether this certificate is an anchor */
+      if (lookup_assertion (openssl, certificate,
+                            G_TLS_DATABASE_OPENSSL_ANCHORED_CERTIFICATE,
+                            purpose, identity, cancellable, error))
+        {
+          g_tls_certificate_openssl_set_issuer (certificate, NULL);
+          *anchor = certificate;
+          return STATUS_ANCHORED;
+        }
+      else if (*error)
+        {
+          return STATUS_FAILURE;
+        }
+
+      /* Is it self-signed? */
+      if (is_self_signed (certificate))
+        {
+          /*
+           * Since at this point we would fail with 'self-signed', can we replace
+           * this certificate with one from the database and do better?
+           */
+          if (previous && !certificate_is_from_db)
+            {
+              issuer = g_tls_database_lookup_certificate_issuer (G_TLS_DATABASE (openssl),
+                                                                 G_TLS_CERTIFICATE (previous),
+                                                                 interaction,
+                                                                 G_TLS_DATABASE_LOOKUP_NONE,
+                                                                 cancellable, error);
+              if (*error)
+                {
+                  return STATUS_FAILURE;
+                }
+              else if (issuer)
+                {
+                  /* Replaced with certificate in the db, restart step again with this certificate */
+                  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
+                  g_tls_certificate_openssl_set_issuer (previous, G_TLS_CERTIFICATE_OPENSSL (issuer));
+                  certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
+                  certificate_is_from_db = TRUE;
+                  g_object_unref (issuer);
+                  continue;
+                }
+            }
+
+          g_tls_certificate_openssl_set_issuer (certificate, NULL);
+          return STATUS_SELFSIGNED;
+        }
+
+      previous = certificate;
+
+      /* Bring over the next certificate in the chain */
+      issuer = g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (certificate));
+      if (issuer)
+        {
+          g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
+          certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
+          certificate_is_from_db = FALSE;
+        }
+
+      /* Search for the next certificate in chain */
+      else
+        {
+          issuer = g_tls_database_lookup_certificate_issuer (G_TLS_DATABASE (openssl),
+                                                             G_TLS_CERTIFICATE (certificate),
+                                                             interaction,
+                                                             G_TLS_DATABASE_LOOKUP_NONE,
+                                                             cancellable, error);
+          if (*error)
+            return STATUS_FAILURE;
+          else if (!issuer)
+            return STATUS_INCOMPLETE;
+
+          /* Found a certificate in chain, use for next step */
+          g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (issuer), STATUS_FAILURE);
+          g_tls_certificate_openssl_set_issuer (certificate, G_TLS_CERTIFICATE_OPENSSL (issuer));
+          certificate = G_TLS_CERTIFICATE_OPENSSL (issuer);
+          certificate_is_from_db = TRUE;
+          g_object_unref (issuer);
+        }
+    }
+
+  g_assert_not_reached ();
+}
+
+static GTlsCertificateFlags
+double_check_before_after_dates (GTlsCertificateOpenssl *chain)
+{
+  GTlsCertificateFlags gtls_flags = 0;
+  X509 *cert;
+
+  while (chain)
+    {
+      ASN1_TIME *not_before;
+      ASN1_TIME *not_after;
+
+      cert = g_tls_certificate_openssl_get_cert (chain);
+      not_before = X509_get_notBefore (cert);
+      not_after = X509_get_notAfter (cert);
+
+      if (X509_cmp_current_time (not_before) > 0)
+        gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
+
+      if (X509_cmp_current_time (not_after) < 0)
+        gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
+
+      chain = G_TLS_CERTIFICATE_OPENSSL (g_tls_certificate_get_issuer
+                                         (G_TLS_CERTIFICATE (chain)));
+    }
+
+  return gtls_flags;
+}
+
+static STACK_OF(X509) *
+convert_certificate_chain_to_openssl (GTlsCertificateOpenssl *chain)
+{
+  GTlsCertificate *cert;
+  STACK_OF(X509) *openssl_chain;
+
+  openssl_chain = sk_X509_new_null ();
+
+  for (cert = G_TLS_CERTIFICATE (chain); cert; cert = g_tls_certificate_get_issuer (cert))
+    sk_X509_push (openssl_chain, g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
+
+  return openssl_chain;
+}
+
+static GTlsCertificateFlags
+g_tls_file_database_openssl_verify_chain (GTlsDatabase             *database,
+                                          GTlsCertificate          *chain,
+                                          const gchar              *purpose,
+                                          GSocketConnectable       *identity,
+                                          GTlsInteraction          *interaction,
+                                          GTlsDatabaseVerifyFlags   flags,
+                                          GCancellable             *cancellable,
+                                          GError                  **error)
+{
+  GTlsDatabaseOpenssl *openssl;
+  GTlsCertificateOpenssl *anchor;
+  STACK_OF(X509) *certs, *anchors;
+  X509_STORE *store;
+  X509_STORE_CTX csc;
+  X509 *x;
+  gint status;
+  GTlsCertificateFlags result = 0;
+  GError *err = NULL;
+
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (chain),
+                        G_TLS_CERTIFICATE_GENERIC_ERROR);
+
+  openssl = G_TLS_DATABASE_OPENSSL (database);
+  anchor = NULL;
+
+  status = build_certificate_chain (openssl, G_TLS_CERTIFICATE_OPENSSL (chain), purpose,
+                                    identity, interaction, flags, cancellable, &anchor, &err);
+  if (status == STATUS_FAILURE)
+    {
+      g_propagate_error (error, err);
+      return G_TLS_CERTIFICATE_GENERIC_ERROR;
+    }
+
+  /*
+   * A pinned certificate is verified on its own, without any further
+   * verification.
+   */
+  if (status == STATUS_PINNED)
+      return 0;
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+  certs = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
+
+  store = X509_STORE_new ();
+
+  x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (chain));
+  if (!X509_STORE_CTX_init(&csc, store, x, certs))
+    {
+      X509_STORE_CTX_cleanup (&csc);
+      X509_STORE_free (store);
+      sk_X509_free (certs);
+      return G_TLS_CERTIFICATE_GENERIC_ERROR;
+    }
+
+  if (anchor)
+    {
+      g_assert (g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (anchor)) == NULL);
+      anchors = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (anchor));
+      X509_STORE_CTX_trusted_stack (&csc, anchors);
+    }
+  else
+    anchors = NULL;
+
+  if (X509_verify_cert (&csc) <= 0)
+    result = g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (&csc));
+
+  X509_STORE_CTX_cleanup (&csc);
+  X509_STORE_free (store);
+  sk_X509_free (certs);
+  if (anchors)
+    sk_X509_free (anchors);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+  /* We have to check these ourselves since openssl
+   * does not give us flags and UNKNOWN_CA will take priority.
+   */
+  result |= double_check_before_after_dates (G_TLS_CERTIFICATE_OPENSSL (chain));
+
+  if (identity)
+    result |= g_tls_certificate_openssl_verify_identity (G_TLS_CERTIFICATE_OPENSSL (chain),
+                                                         identity);
+
+  return result;
+}
+
+static void
+g_tls_file_database_openssl_class_init (GTlsFileDatabaseOpensslClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
+
+  gobject_class->get_property = g_tls_file_database_openssl_get_property;
+  gobject_class->set_property = g_tls_file_database_openssl_set_property;
+  gobject_class->finalize     = g_tls_file_database_openssl_finalize;
+
+  database_class->create_certificate_handle = g_tls_file_database_openssl_create_certificate_handle;
+  database_class->lookup_certificate_for_handle = g_tls_file_database_openssl_lookup_certificate_for_handle;
+  database_class->lookup_certificate_issuer = g_tls_file_database_openssl_lookup_certificate_issuer;
+  database_class->lookup_certificates_issued_by = g_tls_file_database_openssl_lookup_certificates_issued_by;
+  database_class->verify_chain = g_tls_file_database_openssl_verify_chain;
+
+  g_object_class_override_property (gobject_class, PROP_ANCHORS, "anchors");
+}
+
+static void
+g_tls_file_database_openssl_file_database_interface_init (GTlsFileDatabaseInterface *iface)
+{
+}
+
+static gboolean
+g_tls_file_database_openssl_initable_init (GInitable    *initable,
+                                           GCancellable *cancellable,
+                                           GError      **error)
+{
+  GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (initable);
+  GTlsFileDatabaseOpensslPrivate *priv;
+  GHashTable *subjects, *issuers, *complete, *certs_by_handle;
+  gboolean result;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return FALSE;
+
+  subjects = bytes_multi_table_new ();
+  issuers = bytes_multi_table_new ();
+
+  complete = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
+                                    (GDestroyNotify)g_bytes_unref,
+                                    (GDestroyNotify)g_bytes_unref);
+
+  certs_by_handle = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                           (GDestroyNotify)g_free,
+                                           (GDestroyNotify)g_object_unref);
+
+  if (priv->anchor_filename)
+    result = load_anchor_file (file_database,
+                               priv->anchor_filename,
+                               subjects, issuers, complete,
+                               certs_by_handle,
+                               error);
+  else
+    result = TRUE;
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    result = FALSE;
+
+  if (result)
+    {
+      g_mutex_lock (&priv->mutex);
+      if (!priv->subjects)
+        {
+          priv->subjects = subjects;
+          subjects = NULL;
+        }
+      if (!priv->issuers)
+        {
+          priv->issuers = issuers;
+          issuers = NULL;
+        }
+      if (!priv->complete)
+        {
+          priv->complete = complete;
+          complete = NULL;
+        }
+      if (!priv->certs_by_handle)
+        {
+          priv->certs_by_handle = certs_by_handle;
+          certs_by_handle = NULL;
+        }
+      g_mutex_unlock (&priv->mutex);
+    }
+
+  if (subjects != NULL)
+    g_hash_table_unref (subjects);
+  if (issuers != NULL)
+    g_hash_table_unref (issuers);
+  if (complete != NULL)
+    g_hash_table_unref (complete);
+  if (certs_by_handle != NULL)
+    g_hash_table_unref (certs_by_handle);
+  return result;
+}
+
+static void
+g_tls_file_database_openssl_initable_interface_init (GInitableIface *iface)
+{
+  iface->init = g_tls_file_database_openssl_initable_init;
+}
diff --git a/tls/openssl/gtlsfiledatabase-openssl.h b/tls/openssl/gtlsfiledatabase-openssl.h
new file mode 100644
index 0000000..4ec6627
--- /dev/null
+++ b/tls/openssl/gtlsfiledatabase-openssl.h
@@ -0,0 +1,64 @@
+/*
+ * gtlsfiledatabase-openssl.h
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#ifndef __G_TLS_FILE_DATABASE_OPENSSL_H__
+#define __G_TLS_FILE_DATABASE_OPENSSL_H__
+
+#include <gio/gio.h>
+
+#ifdef G_OS_WIN32
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include "gtlsdatabase-openssl.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_FILE_DATABASE_OPENSSL            (g_tls_file_database_openssl_get_type ())
+#define G_TLS_FILE_DATABASE_OPENSSL(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), 
G_TYPE_TLS_FILE_DATABASE_OPENSSL, GTlsFileDatabaseOpenssl))
+#define G_TLS_FILE_DATABASE_OPENSSL_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), 
G_TYPE_TLS_FILE_DATABASE_OPENSSL, GTlsFileDatabaseOpensslClass))
+#define G_IS_TLS_FILE_DATABASE_OPENSSL(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), 
G_TYPE_TLS_FILE_DATABASE_OPENSSL))
+#define G_IS_TLS_FILE_DATABASE_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), 
G_TYPE_TLS_FILE_DATABASE_OPENSSL))
+#define G_TLS_FILE_DATABASE_OPENSSL_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), 
G_TYPE_TLS_FILE_DATABASE_OPENSSL, GTlsFileDatabaseOpensslClass))
+
+typedef struct _GTlsFileDatabaseOpensslClass GTlsFileDatabaseOpensslClass;
+typedef struct _GTlsFileDatabaseOpenssl      GTlsFileDatabaseOpenssl;
+
+struct _GTlsFileDatabaseOpensslClass
+{
+  GTlsDatabaseOpensslClass parent_class;
+};
+
+struct _GTlsFileDatabaseOpenssl
+{
+  GTlsDatabaseOpenssl parent_instance;
+};
+
+GType                        g_tls_file_database_openssl_get_type              (void) G_GNUC_CONST;
+
+GTlsDatabase                *g_tls_file_database_openssl_new                   (const gchar *anchor_file);
+
+G_END_DECLS
+
+#endif /* __G_TLS_FILE_DATABASE_OPENSSL_H___ */
diff --git a/tls/openssl/gtlsserverconnection-openssl.c b/tls/openssl/gtlsserverconnection-openssl.c
new file mode 100644
index 0000000..e9add65
--- /dev/null
+++ b/tls/openssl/gtlsserverconnection-openssl.c
@@ -0,0 +1,316 @@
+/*
+ * gtlsserverconnection-openssl.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "config.h"
+#include "glib.h"
+#include "gtlsserverconnection-openssl.h"
+#include "gtlscertificate-openssl.h"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <glib/gi18n-lib.h>
+
+typedef struct _GTlsServerConnectionOpensslPrivate
+{
+  GTlsAuthenticationMode authentication_mode;
+  SSL_SESSION *session;
+  SSL *ssl;
+  SSL_CTX *ssl_ctx;
+} GTlsServerConnectionOpensslPrivate;
+
+enum
+{
+  PROP_0,
+  PROP_AUTHENTICATION_MODE
+};
+
+static void g_tls_server_connection_openssl_initable_interface_init (GInitableIface  *iface);
+
+static void g_tls_server_connection_openssl_server_connection_interface_init (GTlsServerConnectionInterface 
*iface);
+
+static GInitableIface *g_tls_server_connection_openssl_parent_initable_iface;
+
+G_DEFINE_TYPE_WITH_CODE (GTlsServerConnectionOpenssl, g_tls_server_connection_openssl, 
G_TYPE_TLS_CONNECTION_OPENSSL,
+                         G_ADD_PRIVATE (GTlsServerConnectionOpenssl)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                g_tls_server_connection_openssl_initable_interface_init)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_TLS_SERVER_CONNECTION,
+                                                
g_tls_server_connection_openssl_server_connection_interface_init))
+
+static void
+g_tls_server_connection_openssl_finalize (GObject *object)
+{
+  GTlsServerConnectionOpenssl *openssl = G_TLS_SERVER_CONNECTION_OPENSSL (object);
+  GTlsServerConnectionOpensslPrivate *priv;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (openssl);
+
+  SSL_free (priv->ssl);
+  SSL_CTX_free (priv->ssl_ctx);
+  SSL_SESSION_free (priv->session);
+
+  G_OBJECT_CLASS (g_tls_server_connection_openssl_parent_class)->finalize (object);
+}
+
+static void
+g_tls_server_connection_openssl_get_property (GObject    *object,
+                                              guint       prop_id,
+                                              GValue     *value,
+                                              GParamSpec *pspec)
+{
+  GTlsServerConnectionOpenssl *openssl = G_TLS_SERVER_CONNECTION_OPENSSL (object);
+  GTlsServerConnectionOpensslPrivate *priv;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (openssl);
+
+  switch (prop_id)
+    {
+    case PROP_AUTHENTICATION_MODE:
+      g_value_set_enum (value, priv->authentication_mode);
+      break;
+      
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_tls_server_connection_openssl_set_property (GObject      *object,
+                                              guint         prop_id,
+                                              const GValue *value,
+                                              GParamSpec   *pspec)
+{
+  GTlsServerConnectionOpenssl *openssl = G_TLS_SERVER_CONNECTION_OPENSSL (object);
+  GTlsServerConnectionOpensslPrivate *priv;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (openssl);
+
+  switch (prop_id)
+    {
+    case PROP_AUTHENTICATION_MODE:
+      priv->authentication_mode = g_value_get_enum (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static int
+verify_callback (int             preverify_ok,
+                 X509_STORE_CTX *ctx)
+{
+  return 1;
+}
+
+static GTlsConnectionBaseStatus
+g_tls_server_connection_openssl_handshake (GTlsConnectionBase  *tls,
+                                           GCancellable        *cancellable,
+                                           GError             **error)
+{
+  GTlsServerConnectionOpenssl *openssl = G_TLS_SERVER_CONNECTION_OPENSSL (tls);
+  GTlsServerConnectionOpensslPrivate *priv;
+  int req_mode = 0;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (openssl);
+
+  switch (priv->authentication_mode)
+    {
+    case G_TLS_AUTHENTICATION_REQUIRED:
+      req_mode = SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+    case G_TLS_AUTHENTICATION_REQUESTED:
+      req_mode |= SSL_VERIFY_PEER;
+      break;
+    case G_TLS_AUTHENTICATION_NONE:
+    default:
+      req_mode = SSL_VERIFY_NONE;
+      break;
+    }
+
+  SSL_set_verify (priv->ssl, req_mode, verify_callback);
+  /* FIXME: is this ok? */
+  SSL_set_verify_depth (priv->ssl, 0);
+
+  return G_TLS_CONNECTION_BASE_CLASS (g_tls_server_connection_openssl_parent_class)->
+    handshake (tls, cancellable, error);
+}
+
+static SSL *
+g_tls_server_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection)
+{
+  GTlsServerConnectionOpenssl *server = G_TLS_SERVER_CONNECTION_OPENSSL (connection);
+  GTlsServerConnectionOpensslPrivate *priv;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (server);
+
+  return priv->ssl;
+}
+
+static SSL_CTX *
+g_tls_server_connection_openssl_get_ssl_ctx (GTlsConnectionOpenssl *connection)
+{
+  GTlsServerConnectionOpenssl *server = G_TLS_SERVER_CONNECTION_OPENSSL (connection);
+  GTlsServerConnectionOpensslPrivate *priv;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (server);
+
+  return priv->ssl_ctx;
+}
+
+static void
+g_tls_server_connection_openssl_class_init (GTlsServerConnectionOpensslClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
+  GTlsConnectionOpensslClass *connection_class = G_TLS_CONNECTION_OPENSSL_CLASS (klass);
+
+  gobject_class->finalize = g_tls_server_connection_openssl_finalize;
+  gobject_class->get_property = g_tls_server_connection_openssl_get_property;
+  gobject_class->set_property = g_tls_server_connection_openssl_set_property;
+
+  base_class->handshake = g_tls_server_connection_openssl_handshake;
+
+  connection_class->get_ssl = g_tls_server_connection_openssl_get_ssl;
+  connection_class->get_ssl_ctx = g_tls_server_connection_openssl_get_ssl_ctx;
+
+  g_object_class_override_property (gobject_class, PROP_AUTHENTICATION_MODE, "authentication-mode");
+}
+
+static void
+g_tls_server_connection_openssl_init (GTlsServerConnectionOpenssl *openssl)
+{
+}
+
+static void
+g_tls_server_connection_openssl_server_connection_interface_init (GTlsServerConnectionInterface *iface)
+{
+}
+
+static gboolean
+g_tls_server_connection_openssl_initable_init (GInitable       *initable,
+                                               GCancellable    *cancellable,
+                                               GError         **error)
+{
+  GTlsServerConnectionOpenssl *server = G_TLS_SERVER_CONNECTION_OPENSSL (initable);
+  GTlsServerConnectionOpensslPrivate *priv;
+  GTlsCertificate *cert;
+  long options;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (server);
+
+  priv->session = SSL_SESSION_new ();
+
+  priv->ssl_ctx = SSL_CTX_new (SSLv23_server_method ());
+  if (priv->ssl_ctx == NULL)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   _("Could not create TLS context: %s"),
+                   ERR_error_string (ERR_get_error (), NULL));
+      return FALSE;
+    }
+
+  options = SSL_OP_NO_TICKET;
+
+  /* Only TLS 1.2 or higher */
+  SSL_CTX_set_options (priv->ssl_ctx, options);
+
+  cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (initable));
+  if (cert != NULL)
+    {
+      EVP_PKEY *key;
+      X509 *x;
+      GTlsCertificate *issuer;
+
+      key = g_tls_certificate_openssl_get_key (G_TLS_CERTIFICATE_OPENSSL (cert));
+
+      if (key == NULL)
+        {
+          g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                               _("Certificate has no private key"));
+          return FALSE;
+        }
+
+      if (SSL_CTX_use_PrivateKey (priv->ssl_ctx, key) <= 0)
+        {
+          g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                       _("There is a problem with the certificate private key: %s"),
+                       ERR_error_string (ERR_get_error (), NULL));
+          return FALSE;
+        }
+
+      x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert));
+      if (SSL_CTX_use_certificate (priv->ssl_ctx, x) <= 0)
+        {
+          g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                       _("There is a problem with the certificate: %s"),
+                       ERR_error_string (ERR_get_error (), NULL));
+          return FALSE;
+        }
+
+      /* Add all the issuers to create the full certificate chain */
+      for (issuer = g_tls_certificate_get_issuer (G_TLS_CERTIFICATE (cert));
+           issuer != NULL;
+           issuer = g_tls_certificate_get_issuer (issuer))
+        {
+          X509 *issuer_x;
+
+          /* Be careful here and duplicate the certificate since the context
+           * will take the ownership
+           */
+          issuer_x = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (issuer)));
+          if (!SSL_CTX_add_extra_chain_cert (priv->ssl_ctx, issuer_x))
+            g_warning ("There was a problem adding the extra chain certificate: %s",
+                       ERR_error_string (ERR_get_error (), NULL));
+        }
+    }
+
+  SSL_CTX_add_session (priv->ssl_ctx, priv->session);
+
+  SSL_CTX_set_cipher_list (priv->ssl_ctx, "HIGH:!DSS:!aNULL STRENGTH");
+
+  priv->ssl = SSL_new (priv->ssl_ctx);
+  if (priv->ssl == NULL)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   _("Could not create TLS connection: %s"),
+                   ERR_error_string (ERR_get_error (), NULL));
+      return FALSE;
+    }
+
+  SSL_set_accept_state (priv->ssl);
+
+  if (!g_tls_server_connection_openssl_parent_initable_iface->
+      init (initable, cancellable, error))
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+g_tls_server_connection_openssl_initable_interface_init (GInitableIface  *iface)
+{
+  g_tls_server_connection_openssl_parent_initable_iface = g_type_interface_peek_parent (iface);
+
+  iface->init = g_tls_server_connection_openssl_initable_init;
+}
diff --git a/tls/openssl/gtlsserverconnection-openssl.h b/tls/openssl/gtlsserverconnection-openssl.h
new file mode 100644
index 0000000..96e0fb7
--- /dev/null
+++ b/tls/openssl/gtlsserverconnection-openssl.h
@@ -0,0 +1,57 @@
+/*
+ * gtlsserverconnection-openssl.h
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#ifndef __G_TLS_SERVER_CONNECTION_OPENSSL_H__
+#define __G_TLS_SERVER_CONNECTION_OPENSSL_H__
+
+#include <gio/gio.h> 
+#include "gtlsconnection-openssl.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_SERVER_CONNECTION_OPENSSL            (g_tls_server_connection_openssl_get_type ())
+#define G_TLS_SERVER_CONNECTION_OPENSSL(inst)           (G_TYPE_CHECK_INSTANCE_CAST ((inst), 
G_TYPE_TLS_SERVER_CONNECTION_OPENSSL, GTlsServerConnectionOpenssl))
+#define G_TLS_SERVER_CONNECTION_OPENSSL_CLASS(class)    (G_TYPE_CHECK_CLASS_CAST ((class), 
G_TYPE_TLS_SERVER_CONNECTION_OPENSSL, GTlsServerConnectionOpensslClass))
+#define G_IS_TLS_SERVER_CONNECTION_OPENSSL(inst)        (G_TYPE_CHECK_INSTANCE_TYPE ((inst), 
G_TYPE_TLS_SERVER_CONNECTION_OPENSSL))
+#define G_IS_TLS_SERVER_CONNECTION_OPENSSL_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), 
G_TYPE_TLS_SERVER_CONNECTION_OPENSSL))
+#define G_TLS_SERVER_CONNECTION_OPENSSL_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), 
G_TYPE_TLS_SERVER_CONNECTION_OPENSSL, GTlsServerConnectionOpensslClass))
+
+typedef struct _GTlsServerConnectionOpensslClass GTlsServerConnectionOpensslClass;
+typedef struct _GTlsServerConnectionOpenssl      GTlsServerConnectionOpenssl;
+
+struct _GTlsServerConnectionOpensslClass
+{
+  GTlsConnectionOpensslClass parent_class;
+};
+
+struct _GTlsServerConnectionOpenssl
+{
+  GTlsConnectionOpenssl parent_instance;
+};
+
+GType g_tls_server_connection_openssl_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_TLS_SERVER_CONNECTION_OPENSSL_H___ */
diff --git a/tls/openssl/openssl-module.c b/tls/openssl/openssl-module.c
new file mode 100644
index 0000000..f58aed3
--- /dev/null
+++ b/tls/openssl/openssl-module.c
@@ -0,0 +1,69 @@
+/*
+ * gtlsbio.c
+ *
+ * Copyright (C) 2015 NICE s.r.l.
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ * Authors: Ignacio Casal Quinteiro
+ */
+
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "gtlsbackend-openssl.h"
+
+
+void
+g_io_module_load (GIOModule *module)
+{
+  gchar *locale_dir;
+#ifdef G_OS_WIN32
+  gchar *base_dir;
+#endif
+
+  g_tls_backend_openssl_register (module);
+
+#ifdef G_OS_WIN32
+  base_dir = g_win32_get_package_installation_directory_of_module (NULL);
+  locale_dir = g_build_filename (base_dir, "share", "locale", NULL);
+  g_free (base_dir);
+#else
+  locale_dir = g_strdup (LOCALE_DIR);
+#endif
+
+  bindtextdomain (GETTEXT_PACKAGE, locale_dir);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+  g_free (locale_dir);
+}
+
+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/openssl/openssl-util.c b/tls/openssl/openssl-util.c
new file mode 100644
index 0000000..5ba63f1
--- /dev/null
+++ b/tls/openssl/openssl-util.c
@@ -0,0 +1,487 @@
+/* v3_utl.c */
+/*
+ * Written by Dr Stephen N Henson (steve openssl org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2003 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing OpenSSL org 
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay cryptsoft com).  This product includes software written by Tim
+ * Hudson (tjh cryptsoft com).
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ */
+/* X509 v3 extension utilities */
+
+/* NOTE: this has been copied from openssl */
+
+#include "openssl-util.h"
+#include <string.h>
+#include <openssl/x509v3.h>
+
+#ifdef _MSC_VER
+#define strncasecmp _strnicmp
+#endif
+
+typedef int (*equal_fn) (const unsigned char *pattern, size_t pattern_len,
+                         const unsigned char *subject, size_t subject_len,
+                         unsigned int flags);
+
+
+/* Skip pattern prefix to match "wildcard" subject */
+static void skip_prefix(const unsigned char **p, size_t *plen,
+                        const unsigned char *subject, size_t subject_len,
+                        unsigned int flags)
+{
+    const unsigned char *pattern = *p;
+    size_t pattern_len = *plen;
+
+    /*
+     * If subject starts with a leading '.' followed by more octets, and
+     * pattern is longer, compare just an equal-length suffix with the
+     * full subject (starting at the '.'), provided the prefix contains
+     * no NULs.
+     */
+    if ((flags & _G_TLS_X509_CHECK_FLAG_DOT_SUBDOMAINS) == 0)
+        return;
+
+    while (pattern_len > subject_len && *pattern) {
+        if ((flags & G_TLS_X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS) &&
+            *pattern == '.')
+            break;
+        ++pattern;
+        --pattern_len;
+    }
+
+    /* Skip if entire prefix acceptable */
+    if (pattern_len == subject_len) {
+        *p = pattern;
+        *plen = pattern_len;
+    }
+}
+
+/* Compare while ASCII ignoring case. */
+static int equal_nocase(const unsigned char *pattern, size_t pattern_len,
+                        const unsigned char *subject, size_t subject_len,
+                        unsigned int flags)
+{
+    skip_prefix(&pattern, &pattern_len, subject, subject_len, flags);
+    if (pattern_len != subject_len)
+        return 0;
+    while (pattern_len) {
+        unsigned char l = *pattern;
+        unsigned char r = *subject;
+        /* The pattern must not contain NUL characters. */
+        if (l == 0)
+            return 0;
+        if (l != r) {
+            if ('A' <= l && l <= 'Z')
+                l = (l - 'A') + 'a';
+            if ('A' <= r && r <= 'Z')
+                r = (r - 'A') + 'a';
+            if (l != r)
+                return 0;
+        }
+        ++pattern;
+        ++subject;
+        --pattern_len;
+    }
+    return 1;
+}
+
+/* Compare using memcmp. */
+static int equal_case(const unsigned char *pattern, size_t pattern_len,
+                      const unsigned char *subject, size_t subject_len,
+                      unsigned int flags)
+{
+    skip_prefix(&pattern, &pattern_len, subject, subject_len, flags);
+    if (pattern_len != subject_len)
+        return 0;
+    return !memcmp(pattern, subject, pattern_len);
+}
+
+/*
+ * RFC 5280, section 7.5, requires that only the domain is compared in a
+ * case-insensitive manner.
+ */
+static int equal_email(const unsigned char *a, size_t a_len,
+                       const unsigned char *b, size_t b_len,
+                       unsigned int unused_flags)
+{
+    size_t i = a_len;
+    if (a_len != b_len)
+        return 0;
+    /*
+     * We search backwards for the '@' character, so that we do not have to
+     * deal with quoted local-parts.  The domain part is compared in a
+     * case-insensitive manner.
+     */
+    while (i > 0) {
+        --i;
+        if (a[i] == '@' || b[i] == '@') {
+            if (!equal_nocase(a + i, a_len - i, b + i, a_len - i, 0))
+                return 0;
+            break;
+        }
+    }
+    if (i == 0)
+        i = a_len;
+    return equal_case(a, i, b, i, 0);
+}
+
+/*
+ * Compare an ASN1_STRING to a supplied string. If they match return 1. If
+ * cmp_type > 0 only compare if string matches the type, otherwise convert it
+ * to UTF8.
+ */
+
+static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal,
+                           unsigned int flags, const char *b, size_t blen,
+                           char **peername)
+{
+    int rv = 0;
+
+    if (!a->data || !a->length)
+        return 0;
+    if (cmp_type > 0) {
+        if (cmp_type != a->type)
+            return 0;
+        if (cmp_type == V_ASN1_IA5STRING)
+            rv = equal(a->data, a->length, (unsigned char *)b, blen, flags);
+        else if (a->length == (int)blen && !memcmp(a->data, b, blen))
+            rv = 1;
+        if (rv > 0 && peername)
+            *peername = BUF_strndup((char *)a->data, a->length);
+    } else {
+        int astrlen;
+        unsigned char *astr;
+        astrlen = ASN1_STRING_to_UTF8(&astr, a);
+        if (astrlen < 0) {
+            /*
+             * -1 could be an internal malloc failure or a decoding error from
+             * malformed input; we can't distinguish.
+             */
+            return -1;
+        }
+        rv = equal(astr, astrlen, (unsigned char *)b, blen, flags);
+        if (rv > 0 && peername)
+            *peername = BUF_strndup((char *)astr, astrlen);
+        OPENSSL_free(astr);
+    }
+    return rv;
+}
+
+/*
+ * Compare the prefix and suffix with the subject, and check that the
+ * characters in-between are valid.
+ */
+static int wildcard_match(const unsigned char *prefix, size_t prefix_len,
+                          const unsigned char *suffix, size_t suffix_len,
+                          const unsigned char *subject, size_t subject_len,
+                          unsigned int flags)
+{
+    const unsigned char *wildcard_start;
+    const unsigned char *wildcard_end;
+    const unsigned char *p;
+    int allow_multi = 0;
+    int allow_idna = 0;
+
+    if (subject_len < prefix_len + suffix_len)
+        return 0;
+    if (!equal_nocase(prefix, prefix_len, subject, prefix_len, flags))
+        return 0;
+    wildcard_start = subject + prefix_len;
+    wildcard_end = subject + (subject_len - suffix_len);
+    if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len, flags))
+        return 0;
+    /*
+     * If the wildcard makes up the entire first label, it must match at
+     * least one character.
+     */
+    if (prefix_len == 0 && *suffix == '.') {
+        if (wildcard_start == wildcard_end)
+            return 0;
+        allow_idna = 1;
+        if (flags & G_TLS_X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS)
+            allow_multi = 1;
+    }
+    /* IDNA labels cannot match partial wildcards */
+    if (!allow_idna &&
+        subject_len >= 4 && strncasecmp((char *)subject, "xn--", 4) == 0)
+        return 0;
+    /* The wildcard may match a literal '*' */
+    if (wildcard_end == wildcard_start + 1 && *wildcard_start == '*')
+        return 1;
+    /*
+     * Check that the part matched by the wildcard contains only
+     * permitted characters and only matches a single label unless
+     * allow_multi is set.
+     */
+    for (p = wildcard_start; p != wildcard_end; ++p)
+        if (!(('0' <= *p && *p <= '9') ||
+              ('A' <= *p && *p <= 'Z') ||
+              ('a' <= *p && *p <= 'z') ||
+              *p == '-' || (allow_multi && *p == '.')))
+            return 0;
+    return 1;
+}
+
+#define LABEL_START     (1 << 0)
+#define LABEL_END       (1 << 1)
+#define LABEL_HYPHEN    (1 << 2)
+#define LABEL_IDNA      (1 << 3)
+
+static const unsigned char *valid_star(const unsigned char *p, size_t len,
+                                       unsigned int flags)
+{
+    const unsigned char *star = 0;
+    size_t i;
+    int state = LABEL_START;
+    int dots = 0;
+    for (i = 0; i < len; ++i) {
+        /*
+         * Locate first and only legal wildcard, either at the start
+         * or end of a non-IDNA first and not final label.
+         */
+        if (p[i] == '*') {
+            int atstart = (state & LABEL_START);
+            int atend = (i == len - 1 || p[i + 1] == '.');
+            /*-
+             * At most one wildcard per pattern.
+             * No wildcards in IDNA labels.
+             * No wildcards after the first label.
+             */
+            if (star != NULL || (state & LABEL_IDNA) != 0 || dots)
+                return NULL;
+            /* Only full-label '*.example.com' wildcards? */
+            if ((flags & G_TLS_X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS)
+                && (!atstart || !atend))
+                return NULL;
+            /* No 'foo*bar' wildcards */
+            if (!atstart && !atend)
+                return NULL;
+            star = &p[i];
+            state &= ~LABEL_START;
+        } else if (('a' <= p[i] && p[i] <= 'z')
+                   || ('A' <= p[i] && p[i] <= 'Z')
+                   || ('0' <= p[i] && p[i] <= '9')) {
+            if ((state & LABEL_START) != 0
+                && len - i >= 4 && strncasecmp((char *)&p[i], "xn--", 4) == 0)
+                state |= LABEL_IDNA;
+            state &= ~(LABEL_HYPHEN | LABEL_START);
+        } else if (p[i] == '.') {
+            if ((state & (LABEL_HYPHEN | LABEL_START)) != 0)
+                return NULL;
+            state = LABEL_START;
+            ++dots;
+        } else if (p[i] == '-') {
+            if ((state & LABEL_HYPHEN) != 0)
+                return NULL;
+            state |= LABEL_HYPHEN;
+        } else
+            return NULL;
+    }
+
+    /*
+     * The final label must not end in a hyphen or ".", and
+     * there must be at least two dots after the star.
+     */
+    if ((state & (LABEL_START | LABEL_HYPHEN)) != 0 || dots < 2)
+        return NULL;
+    return star;
+}
+
+/* Compare using wildcards. */
+static int equal_wildcard(const unsigned char *pattern, size_t pattern_len,
+                          const unsigned char *subject, size_t subject_len,
+                          unsigned int flags)
+{
+    const unsigned char *star = NULL;
+
+    /*
+     * Subject names starting with '.' can only match a wildcard pattern
+     * via a subject sub-domain pattern suffix match.
+     */
+    if (!(subject_len > 1 && subject[0] == '.'))
+        star = valid_star(pattern, pattern_len, flags);
+    if (star == NULL)
+        return equal_nocase(pattern, pattern_len,
+                            subject, subject_len, flags);
+    return wildcard_match(pattern, star - pattern,
+                          star + 1, (pattern + pattern_len) - star - 1,
+                          subject, subject_len, flags);
+}
+
+static int do_x509_check(X509 *x, const char *chk, size_t chklen,
+                         unsigned int flags, int check_type, char **peername)
+{
+    GENERAL_NAMES *gens = NULL;
+    X509_NAME *name = NULL;
+    int i;
+    int cnid;
+    int alt_type;
+    int san_present = 0;
+    int rv = 0;
+    equal_fn equal;
+
+    /* See below, this flag is internal-only */
+    flags &= ~_G_TLS_X509_CHECK_FLAG_DOT_SUBDOMAINS;
+    if (check_type == GEN_EMAIL) {
+        cnid = NID_pkcs9_emailAddress;
+        alt_type = V_ASN1_IA5STRING;
+        equal = equal_email;
+    } else if (check_type == GEN_DNS) {
+        cnid = NID_commonName;
+        /* Implicit client-side DNS sub-domain pattern */
+        if (chklen > 1 && chk[0] == '.')
+            flags |= _G_TLS_X509_CHECK_FLAG_DOT_SUBDOMAINS;
+        alt_type = V_ASN1_IA5STRING;
+        if (flags & G_TLS_X509_CHECK_FLAG_NO_WILDCARDS)
+            equal = equal_nocase;
+        else
+            equal = equal_wildcard;
+    } else {
+        cnid = 0;
+        alt_type = V_ASN1_OCTET_STRING;
+        equal = equal_case;
+    }
+
+    if (chklen == 0)
+        chklen = strlen(chk);
+
+    gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+    if (gens) {
+        for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+            GENERAL_NAME *gen;
+            ASN1_STRING *cstr;
+            gen = sk_GENERAL_NAME_value(gens, i);
+            if (gen->type != check_type)
+                continue;
+            san_present = 1;
+            if (check_type == GEN_EMAIL)
+                cstr = gen->d.rfc822Name;
+            else if (check_type == GEN_DNS)
+                cstr = gen->d.dNSName;
+            else
+                cstr = gen->d.iPAddress;
+            /* Positive on success, negative on error! */
+            if ((rv = do_check_string(cstr, alt_type, equal, flags,
+                                      chk, chklen, peername)) != 0)
+                break;
+        }
+        GENERAL_NAMES_free(gens);
+        if (rv != 0)
+            return rv;
+        if (!cnid
+            || (san_present
+                && !(flags & G_TLS_X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT)))
+            return 0;
+    }
+    i = -1;
+    name = X509_get_subject_name(x);
+    while ((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) {
+        X509_NAME_ENTRY *ne;
+        ASN1_STRING *str;
+        ne = X509_NAME_get_entry(name, i);
+        str = X509_NAME_ENTRY_get_data(ne);
+        /* Positive on success, negative on error! */
+        if ((rv = do_check_string(str, -1, equal, flags,
+                                  chk, chklen, peername)) != 0)
+            return rv;
+    }
+    return 0;
+}
+
+int g_tls_X509_check_host(X509 *x, const char *chk, size_t chklen,
+                    unsigned int flags, char **peername)
+{
+    if (chk == NULL)
+        return -2;
+    /*
+     * Embedded NULs are disallowed, except as the last character of a
+     * string of length 2 or more (tolerate caller including terminating
+     * NUL in string length).
+     */
+    if (chklen == 0)
+        chklen = strlen(chk);
+    else if (memchr(chk, '\0', chklen > 1 ? chklen - 1 : chklen))
+        return -2;
+    if (chklen > 1 && chk[chklen - 1] == '\0')
+        --chklen;
+    return do_x509_check(x, chk, chklen, flags, GEN_DNS, peername);
+}
+
+int g_tls_X509_check_email(X509 *x, const char *chk, size_t chklen,
+                     unsigned int flags)
+{
+    if (chk == NULL)
+        return -2;
+    /*
+     * Embedded NULs are disallowed, except as the last character of a
+     * string of length 2 or more (tolerate caller including terminating
+     * NUL in string length).
+     */
+    if (chklen == 0)
+        chklen = strlen((char *)chk);
+    else if (memchr(chk, '\0', chklen > 1 ? chklen - 1 : chklen))
+        return -2;
+    if (chklen > 1 && chk[chklen - 1] == '\0')
+        --chklen;
+    return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, NULL);
+}
+
+int g_tls_X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+                  unsigned int flags)
+{
+    if (chk == NULL)
+        return -2;
+    return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, NULL);
+}
diff --git a/tls/openssl/openssl-util.h b/tls/openssl/openssl-util.h
new file mode 100644
index 0000000..72cd2c9
--- /dev/null
+++ b/tls/openssl/openssl-util.h
@@ -0,0 +1,99 @@
+/* v3_utl.c */
+/*
+ * Written by Dr Stephen N Henson (steve openssl org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2003 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing OpenSSL org 
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay cryptsoft com).  This product includes software written by Tim
+ * Hudson (tjh cryptsoft com).
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ *
+ */
+/* X509 v3 extension utilities */
+
+#ifndef __G_TLS_OPENSSL_UTIL_H__
+#define __G_TLS_OPENSSL_UTIL_H__
+
+#include <openssl/x509.h>
+
+/*
+ * Always check subject name for host match even if subject alt names present
+ */
+# define G_TLS_X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT    0x1
+/* Disable wildcard matching for dnsName fields and common name. */
+# define G_TLS_X509_CHECK_FLAG_NO_WILDCARDS    0x2
+/* Wildcards must not match a partial label. */
+# define G_TLS_X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0x4
+/* Allow (non-partial) wildcards to match multiple labels. */
+# define G_TLS_X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8
+/* Constraint verifier subdomain patterns to match a single labels. */
+# define G_TLS_X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10
+/*
+ * Match reference identifiers starting with "." to any sub-domain.
+ * This is a non-public flag, turned on implicitly when the subject
+ * reference identity is a DNS name.
+ */
+# define _G_TLS_X509_CHECK_FLAG_DOT_SUBDOMAINS 0x8000
+
+int g_tls_X509_check_host(X509 *x, const char *chk, size_t chklen,
+                    unsigned int flags, char **peername);
+
+int g_tls_X509_check_email(X509 *x, const char *chk, size_t chklen,
+                     unsigned int flags);
+
+int g_tls_X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+                  unsigned int flags);
+
+#endif /* __G_TLS_OPENSSL_UTIL_H__ */
+
+
diff --git a/tls/tests/Makefile.am b/tls/tests/Makefile.am
index 0ecd483..8245c49 100644
--- a/tls/tests/Makefile.am
+++ b/tls/tests/Makefile.am
@@ -32,6 +32,27 @@ file_database_gnutls_LDADD = $(GLIB_LIBS) $(GNUTLS_LIBS)
 
 endif
 
+if HAVE_OPENSSL
+test_programs +=             \
+       certificate-openssl   \
+       file-database-openssl \
+       connection-openssl    \
+       $(NULL)
+
+certificate_openssl_SOURCES = certificate.c
+certificate_openssl_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_CFLAGS) -DBACKEND=\""openssl"\" 
-DWITH_BACKEND_OPENSSL
+certificate_openssl_LDADD = $(GLIB_LIBS) $(OPENSSL_LIBS)
+
+connection_openssl_SOURCES = connection.c mock-interaction.c mock-interaction.h
+connection_openssl_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_CFLAGS) -DBACKEND=\""openssl"\" -DWITH_BACKEND_OPENSSL
+connection_openssl_LDADD = $(GLIB_LIBS) $(OPENSSL_LIBS)
+
+file_database_openssl_SOURCES = file-database.c
+file_database_openssl_CPPFLAGS = $(AM_CPPFLAGS) $(OPENSSL_CFLAGS) -DBACKEND=\""openssl"\" 
-DWITH_BACKEND_OPENSSL
+file_database_openssl_LDADD = $(GLIB_LIBS) $(OPENSSL_LIBS)
+
+endif
+
 if HAVE_PKCS11
 
 test_programs +=           \
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index 8f4095e..beb8243 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -1439,6 +1439,7 @@ test_simultaneous_async (TestConnection *test,
   g_assert_cmpstr (test->buf, ==, TEST_DATA);
 }
 
+#ifdef WITH_BACKEND_GNUTLS
 static gboolean
 check_gnutls_has_rehandshaking_bug (void)
 {
@@ -1451,16 +1452,22 @@ check_gnutls_has_rehandshaking_bug (void)
          !strcmp (version, "3.3.9") ||
           !strcmp (version, "3.3.10"));
 }
+#endif
 
 static void
 test_simultaneous_async_rehandshake (TestConnection *test,
                                     gconstpointer   data)
 {
+#ifdef WITH_BACKEND_GNUTLS
   if (check_gnutls_has_rehandshaking_bug ())
     {
       g_test_skip ("test would fail due to gnutls bug 108690");
       return;
     }
+#else
+  g_test_skip ("this needs more research on openssl");
+  return;
+#endif
 
   test->rehandshake = TRUE;
   test_simultaneous_async (test, data);
@@ -1556,11 +1563,16 @@ static void
 test_simultaneous_sync_rehandshake (TestConnection *test,
                                    gconstpointer   data)
 {
+#ifdef WITH_BACKEND_GNUTLS
   if (check_gnutls_has_rehandshaking_bug ())
     {
       g_test_skip ("test would fail due to gnutls bug 108690");
       return;
     }
+#else
+  g_test_skip ("this needs more research on openssl");
+  return;
+#endif
 
   test->rehandshake = TRUE;
   test_simultaneous_sync (test, data);


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