[glib-networking/wip/nacho/openssl: 11/21] Add openssl backend



commit b4bfe5150f731726732c894306980d91716b86fe
Author: Ignacio Casal Quinteiro <qignacio amazon com>
Date:   Mon Sep 10 15:11:23 2018 +0200

    Add openssl backend

 meson.build                                |  49 ++
 meson_options.txt                          |   1 +
 tls/openssl/gtlsbackend-openssl.c          | 292 ++++++++++
 tls/openssl/gtlsbackend-openssl.h          |  48 ++
 tls/openssl/gtlsbio.c                      | 398 ++++++++++++++
 tls/openssl/gtlsbio.h                      |  55 ++
 tls/openssl/gtlscertificate-openssl.c      | 701 ++++++++++++++++++++++++
 tls/openssl/gtlscertificate-openssl.h      |  69 +++
 tls/openssl/gtlsclientconnection-openssl.c | 573 +++++++++++++++++++
 tls/openssl/gtlsclientconnection-openssl.h |  56 ++
 tls/openssl/gtlsconnection-openssl.c       | 644 ++++++++++++++++++++++
 tls/openssl/gtlsconnection-openssl.h       |  68 +++
 tls/openssl/gtlsdatabase-openssl.c         |  39 ++
 tls/openssl/gtlsdatabase-openssl.h         |  63 +++
 tls/openssl/gtlsfiledatabase-openssl.c     | 852 +++++++++++++++++++++++++++++
 tls/openssl/gtlsfiledatabase-openssl.h     |  62 +++
 tls/openssl/gtlsserverconnection-openssl.c | 421 ++++++++++++++
 tls/openssl/gtlsserverconnection-openssl.h |  57 ++
 tls/openssl/meson.build                    |  44 ++
 tls/openssl/openssl-include.h              |  58 ++
 tls/openssl/openssl-module.c               |  65 +++
 tls/openssl/openssl-util.c                 | 488 +++++++++++++++++
 tls/openssl/openssl-util.h                 |  99 ++++
 23 files changed, 5202 insertions(+)
---
diff --git a/meson.build b/meson.build
index 46cd898..d679c11 100644
--- a/meson.build
+++ b/meson.build
@@ -85,6 +85,51 @@ if gnutls_dep.found()
   endif
 endif
 
+# *** Checks for OpenSSL    ***
+openssl_dep = dependency('openssl', required: get_option('openssl'))
+if openssl_dep.found()
+  backends += ['openssl']
+elif cc.get_id() == 'msvc'
+  # MSVC builds of OpenSSL does not generate pkg-config files,
+  # so we check for it manually here in this case, if we can't find those files
+  # Based on the CMake check for OpenSSL in CURL's CMakeLists.txt,
+  # on which headers we should check for
+  cc.has_header('openssl/crypto.h')
+  cc.has_header('openssl/engine.h')
+  cc.has_header('openssl/err.h')
+  cc.has_header('openssl/pem.h')
+  cc.has_header('openssl/rsa.h')
+  cc.has_header('openssl/ssl.h')
+  cc.has_header('openssl/x509.h')
+  cc.has_header('openssl/rand.h')
+  cc.has_header('openssl/tls1.h')
+
+  # OpenSSL 1.1.x and 1.0.x (or earlier) have different .lib names,
+  # so we need to look for the correct pair
+
+  # Find either libcrypto.lib (1.1.x) or libeay32.lib (1.0.x or earlier) first
+  libcrypto_dep = cc.find_library('libcrypto', required: false)
+  if not libcrypto_dep.found()
+    libeay_dep = cc.find_library('libeay32')
+  endif
+
+  # Find the corresponding SSL library depending on which crypto .lib we found
+  if libcrypto_dep.found()
+    libssl_dep = cc.find_library('libssl')
+  elif libeay_dep.found()
+    ssleay_dep = cc.find_library('ssleay32')
+  endif
+
+  # Now set the openssl dependency to the corresponding pair of .lib files that we found
+  if libcrypto_dep.found()
+    openssl_dep = [libcrypto_dep, libssl_dep]
+  else
+    openssl_dep = [libeay_dep, ssleay_dep]
+  endif
+
+  backends += ['openssl']
+endif
+
 if backends.length() == 0
   error('No TLS backends enabled. Please enable at least one TLS backend')
 endif
@@ -139,6 +184,10 @@ if gnutls_dep.found()
   subdir('tls/gnutls')
 endif
 
+if backends.contains('openssl')
+  subdir('tls/openssl')
+endif
+
 subdir('tls/tests')
 
 # Will automatically pick it up from the cross file if defined
diff --git a/meson_options.txt b/meson_options.txt
index 9ae11ed..04706be 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,4 +1,5 @@
 option('gnutls', type: 'feature', value: 'auto', description: 'support for GnuTLS networking configration')
+option('openssl', type: 'feature', value: 'disabled', description: 'support for OpenSSL networking 
configration')
 option('libproxy', type: 'feature', value: 'auto', description: 'support for libproxy proxy configration')
 option('gnome_proxy', type: 'feature', value: 'auto', description: 'support for GNOME desktop proxy 
configuration')
 option('pkcs11', type: 'feature', value: 'disabled', description: 'support for PKCS#11 using p11-kit')
diff --git a/tls/openssl/gtlsbackend-openssl.c b/tls/openssl/gtlsbackend-openssl.c
new file mode 100644
index 0000000..6515c77
--- /dev/null
+++ b/tls/openssl/gtlsbackend-openssl.c
@@ -0,0 +1,292 @@
+/*
+ * 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-include.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)
+{
+  gchar *anchor_file = NULL;
+  GTlsDatabase *database;
+
+#ifdef G_OS_WIN32
+  if (g_getenv ("G_TLS_OPENSSL_HANDLE_CERT_RELOCATABLE") != NULL)
+    {
+      gchar *module_dir;
+
+      module_dir = g_win32_get_package_installation_directory_of_module (NULL);
+      anchor_file = g_build_filename (module_dir, "bin", "cert.pem", NULL);
+      g_free (module_dir);
+    }
+#endif
+
+#ifdef GTLS_SYSTEM_CA_FILE
+  if (anchor_file == NULL)
+    anchor_file = g_strdup (GTLS_SYSTEM_CA_FILE);
+#endif
+
+  if (anchor_file == NULL)
+    {
+      const gchar *openssl_cert_file;
+
+      openssl_cert_file = g_getenv (X509_get_default_cert_file_env ());
+      if (openssl_cert_file == NULL)
+        openssl_cert_file = X509_get_default_cert_file ();
+
+      anchor_file = g_strdup (openssl_cert_file);
+    }
+
+  database = g_tls_file_database_new (anchor_file, error);
+  g_free (anchor_file);
+
+  return database;
+}
+
+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",
+                                  -1);
+}
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..7169dea
--- /dev/null
+++ b/tls/openssl/gtlsbio.c
@@ -0,0 +1,398 @@
+/*
+ * 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)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  bio->init = 0;
+  bio->num = 0;
+  bio->ptr = NULL;
+  bio->flags = 0;
+#else
+  BIO_set_init (bio, 0);
+  BIO_set_data (bio, NULL);
+  BIO_clear_flags (bio, ~0);
+#endif
+  return 1;
+}
+
+static int
+gtls_bio_destroy (BIO *bio)
+{
+  if (bio == NULL)
+    return 0;
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  if (bio->shutdown)
+    {
+      if (bio->ptr != NULL)
+        {
+          free_gbio (bio->ptr);
+          bio->ptr = NULL;
+        }
+      bio->init = 0;
+      bio->flags = 0;
+    }
+#else
+  if (BIO_get_shutdown (bio))
+    {
+      if (BIO_get_data (bio) != NULL)
+        {
+          free_gbio (BIO_get_data (bio));
+          BIO_set_data (bio, NULL);
+        }
+      BIO_clear_flags (bio, ~0);
+      BIO_set_init (bio, 0);
+    }
+#endif
+
+    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:
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+      ret = b->shutdown;
+#else
+      ret = BIO_get_shutdown (b);
+#endif
+      break;
+    case BIO_CTRL_SET_CLOSE:
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+      b->shutdown = (int)num;
+#else
+      BIO_set_shutdown (b, (int)num);
+#endif
+      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 (
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+      !bio->init ||
+#else
+      !BIO_get_init (bio) ||
+#endif
+      in == NULL || inl == 0)
+    return 0;
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  gbio = (GTlsBio *)bio->ptr;
+#else
+  gbio = BIO_get_data (bio);
+#endif
+
+  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 (
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+      !bio->init ||
+#else
+      !BIO_get_init (bio) ||
+#endif
+      out == NULL || outl == 0)
+    return 0;
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  gbio = (GTlsBio *)bio->ptr;
+#else
+  gbio = BIO_get_data (bio);
+#endif
+
+  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;
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+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
+};
+#else
+static BIO_METHOD *methods_gtls = NULL;
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+static BIO_METHOD *
+BIO_s_gtls (void)
+{
+  return &methods_gtls;
+}
+#else
+static const BIO_METHOD *
+BIO_s_gtls (void)
+{
+  if (methods_gtls == NULL)
+    {
+      methods_gtls = BIO_meth_new (BIO_TYPE_SOURCE_SINK | BIO_get_new_index (), "gtls");
+      if (methods_gtls == NULL ||
+          !BIO_meth_set_write (methods_gtls, gtls_bio_write) ||
+          !BIO_meth_set_read (methods_gtls, gtls_bio_read) ||
+          !BIO_meth_set_puts (methods_gtls, gtls_bio_puts) ||
+          !BIO_meth_set_gets (methods_gtls, gtls_bio_gets) ||
+          !BIO_meth_set_ctrl (methods_gtls, gtls_bio_ctrl) ||
+          !BIO_meth_set_create (methods_gtls, gtls_bio_create) ||
+          !BIO_meth_set_destroy (methods_gtls, gtls_bio_destroy))
+        return NULL;
+    }
+  return methods_gtls;
+}
+#endif
+
+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);
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  ret->ptr = gbio;
+  ret->init = 1;
+#else
+  BIO_set_data (ret, gbio);
+  BIO_set_init (ret, 1);
+#endif
+
+  return ret;
+}
+
+void
+g_tls_bio_set_read_cancellable (BIO          *bio,
+                                GCancellable *cancellable)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  gbio = (GTlsBio *)bio->ptr;
+#else
+  gbio = BIO_get_data (bio);
+#endif
+  gbio->read_cancellable = cancellable;
+}
+
+void
+g_tls_bio_set_read_blocking (BIO      *bio,
+                             gboolean  blocking)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  gbio = (GTlsBio *)bio->ptr;
+#else
+  gbio = BIO_get_data (bio);
+#endif
+  gbio->read_blocking = blocking;
+}
+
+void
+g_tls_bio_set_read_error (BIO     *bio,
+                          GError **error)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  gbio = (GTlsBio *)bio->ptr;
+#else
+  gbio = BIO_get_data (bio);
+#endif
+  gbio->read_error = error;
+}
+
+void
+g_tls_bio_set_write_cancellable (BIO          *bio,
+                                 GCancellable *cancellable)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  gbio = (GTlsBio *)bio->ptr;
+#else
+  gbio = BIO_get_data (bio);
+#endif
+  gbio->write_cancellable = cancellable;
+}
+
+void
+g_tls_bio_set_write_blocking (BIO          *bio,
+                              gboolean      blocking)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  gbio = (GTlsBio *)bio->ptr;
+#else
+  gbio = BIO_get_data (bio);
+#endif
+  gbio->write_blocking = blocking;
+}
+
+void
+g_tls_bio_set_write_error (BIO     *bio,
+                           GError **error)
+{
+  GTlsBio *gbio;
+
+  g_return_if_fail (bio != NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+  gbio = (GTlsBio *)bio->ptr;
+#else
+  gbio = BIO_get_data (bio);
+#endif
+  gbio->write_error = error;
+}
diff --git a/tls/openssl/gtlsbio.h b/tls/openssl/gtlsbio.h
new file mode 100644
index 0000000..caa1e9b
--- /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-include.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..83e6e28
--- /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-include.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 ();
+      csc = X509_STORE_CTX_new ();
+
+      if (!X509_STORE_CTX_init (csc, store, x, untrusted))
+        {
+          sk_X509_free (untrusted);
+          X509_STORE_CTX_free (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_free (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 ();
+  csc = X509_STORE_CTX_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_free (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..0827c0f
--- /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-include.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..b1560c1
--- /dev/null
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -0,0 +1,573 @@
+/*
+ * 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"
+
+#include <errno.h>
+#include <string.h>
+
+#include "openssl-include.h"
+#include "gtlsconnection-base.h"
+#include "gtlsclientconnection-openssl.h"
+#include "gtlsbackend-openssl.h"
+#include "gtlscertificate-openssl.h"
+#include <glib/gi18n-lib.h>
+
+#define DEFAULT_CIPHER_LIST "HIGH:!DSS:!aNULL@STRENGTH"
+
+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 = -1;
+
+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 */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+      CRYPTO_add (&key->references, 1, CRYPTO_LOCK_EVP_PKEY);
+#else
+      EVP_PKEY_up_ref (key);
+#endif
+      *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 void
+set_cipher_list (GTlsClientConnectionOpenssl *client)
+{
+  GTlsClientConnectionOpensslPrivate *priv;
+  const gchar *cipher_list;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (client);
+
+  cipher_list = g_getenv ("G_TLS_OPENSSL_CIPHER_LIST");
+  if (cipher_list == NULL)
+    cipher_list = DEFAULT_CIPHER_LIST;
+
+  SSL_CTX_set_cipher_list (priv->ssl_ctx, cipher_list);
+}
+
+#ifdef SSL_CTX_set1_sigalgs_list
+static void
+set_signature_algorithm_list (GTlsClientConnectionOpenssl *client)
+{
+  GTlsClientConnectionOpensslPrivate *priv;
+  const gchar *signature_algorithm_list;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (client);
+
+  signature_algorithm_list = g_getenv ("G_TLS_OPENSSL_SIGNATURE_ALGORITHM_LIST");
+  if (signature_algorithm_list == NULL)
+    return;
+
+  SSL_CTX_set1_sigalgs_list (priv->ssl_ctx, signature_algorithm_list);
+}
+#endif
+
+#ifdef SSL_CTX_set1_curves_list
+static void
+set_curve_list (GTlsClientConnectionOpenssl *client)
+{
+  GTlsClientConnectionOpensslPrivate *priv;
+  const gchar *curve_list;
+
+  priv = g_tls_client_connection_openssl_get_instance_private (client);
+
+  curve_list = g_getenv ("G_TLS_OPENSSL_CURVE_LIST");
+  if (curve_list == NULL)
+    return;
+
+  SSL_CTX_set1_curves_list (priv->ssl_ctx, curve_list);
+}
+#endif
+
+static gboolean
+use_ocsp (void)
+{
+  return g_getenv ("G_TLS_OPENSSL_OCSP_ENABLED") != NULL;
+}
+
+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;
+  const char *hostname;
+
+  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;
+    }
+
+  /* Only TLS 1.2 or higher */
+  options = SSL_OP_NO_TICKET |
+            SSL_OP_NO_COMPRESSION |
+#ifdef SSL_OP_NO_TLSv1_1
+            SSL_OP_NO_TLSv1_1 |
+#endif
+            SSL_OP_NO_SSLv2 |
+            SSL_OP_NO_SSLv3 |
+            SSL_OP_NO_TLSv1;
+  SSL_CTX_set_options (priv->ssl_ctx, options);
+
+  SSL_CTX_clear_options (priv->ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT);
+
+  hostname = get_server_identity (client);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10200000L && !defined (LIBRESSL_VERSION_NUMBER)
+  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);
+
+  set_cipher_list (client);
+
+#ifdef SSL_CTX_set1_sigalgs_list
+  set_signature_algorithm_list (client);
+#endif
+
+#ifdef SSL_CTX_set1_curves_list
+  set_curve_list (client);
+#endif
+
+  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;
+    }
+
+  if (data_index == -1) {
+      data_index = SSL_get_ex_new_index (0, (void *)"gtlsclientconnection", NULL, NULL, NULL);
+  }
+  SSL_set_ex_data (priv->ssl, data_index, client);
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+  if (hostname)
+    SSL_set_tlsext_host_name (priv->ssl, hostname);
+#endif
+
+  SSL_set_connect_state (priv->ssl);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+    !defined(OPENSSL_NO_OCSP)
+  if (use_ocsp())
+    SSL_set_tlsext_status_type (priv->ssl, TLSEXT_STATUSTYPE_ocsp);
+#endif
+
+  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..fbcb869
--- /dev/null
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -0,0 +1,644 @@
+/*
+ * 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-include.h"
+
+#include "gtlsconnection-openssl.h"
+#include "gtlsbackend-openssl.h"
+#include "gtlscertificate-openssl.h"
+#include "gtlsfiledatabase-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, err_lib, 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 ();
+  err_lib = ERR_GET_LIB (err);
+  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;
+        }
+    }
+
+#ifdef SSL_R_SHUTDOWN_WHILE_IN_INIT
+  /* XXX: this error happens on ubuntu when shutting down the connection, it
+   * seems to be a bug in a specific version of openssl, so let's handle it
+   * gracefully
+   */
+  if (reason == SSL_R_SHUTDOWN_WHILE_IN_INIT)
+    {
+      g_clear_error (&my_error);
+      return G_TLS_CONNECTION_BASE_OK;
+    }
+#endif
+
+  if (reason == SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE)
+    {
+      g_clear_error (&my_error);
+      g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED,
+                           _("TLS connection peer did not send a certificate"));
+      return status;
+    }
+
+  if (err_lib == ERR_LIB_RSA && reason == RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY)
+    {
+      g_clear_error (&my_error);
+      g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+                           _("Digest too big for RSA key"));
+      return G_TLS_CONNECTION_BASE_ERROR;
+    }
+
+  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, %d", G_IS_TLS_CLIENT_CONNECTION (openssl) ? "client" : "server", 
err_code, err_lib, 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 {                                                                      \
+    char error_str[256];
+
+#define END_OPENSSL_IO(openssl, direction, ret, status, errmsg, err)        \
+    ERR_error_string_n (SSL_get_error (ssl, ret), error_str, sizeof(error_str)); \
+    status = end_openssl_io (openssl, direction, ret, err, errmsg, error_str); \
+  } 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);
+
+  if (tls->rehandshake_mode == G_TLS_REHANDSHAKE_NEVER)
+    {
+      g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                           _("Peer requested illegal TLS rehandshake"));
+      return G_TLS_CONNECTION_BASE_ERROR;
+    }
+
+  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_ocsp_response (GTlsConnectionOpenssl *openssl,
+                      GTlsDatabase          *database,
+                      GTlsCertificate       *peer_certificate)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+  !defined(OPENSSL_NO_OCSP)
+  SSL *ssl = NULL;
+  OCSP_RESPONSE *resp = NULL;
+  long len = 0;
+  const unsigned char *p = NULL;
+
+  ssl = g_tls_connection_openssl_get_ssl (openssl);
+  len = SSL_get_tlsext_status_ocsp_resp (ssl, &p);
+  /* Soft fail in case of no response is the best we can do */
+  if (p == NULL)
+    return 0;
+
+  resp = d2i_OCSP_RESPONSE (NULL, &p, len);
+  if (resp == NULL)
+    return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+  return g_tls_file_database_openssl_verify_ocsp_response (database,
+                                                           peer_certificate,
+                                                           resp);
+#else
+  return 0;
+#endif
+}
+
+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);
+        }
+    }
+
+  if (is_client && (errors == 0))
+    errors = verify_ocsp_response (openssl, database, peer_certificate);
+
+  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..31eeab3
--- /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-include.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..e45a619
--- /dev/null
+++ b/tls/openssl/gtlsfiledatabase-openssl.c
@@ -0,0 +1,852 @@
+/*
+ * 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-include.h"
+
+typedef struct _GTlsFileDatabaseOpensslPrivate
+{
+  /* read-only after construct */
+  gchar *anchor_filename;
+  STACK_OF(X509) *trusted;
+
+  /* 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;
+
+  if (priv->trusted != NULL)
+    sk_X509_pop_free (priv->trusted, X509_free);
+
+  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 STACK_OF(X509) *
+load_certs (const gchar *file_name)
+{
+  BIO *bio;
+  STACK_OF(X509) *certs;
+  STACK_OF(X509_INFO) *xis = NULL;
+  gint i;
+
+  if (file_name == NULL)
+    return NULL;
+
+  bio = BIO_new_file (file_name, "rb");
+  if (bio == NULL)
+    return NULL;
+
+  xis = PEM_X509_INFO_read_bio (bio, NULL, NULL, NULL);
+
+  BIO_free (bio);
+
+  certs = sk_X509_new_null ();
+  if (certs == NULL)
+    goto end;
+
+  for (i = 0; i < sk_X509_INFO_num (xis); i++)
+    {
+      X509_INFO *xi;
+
+      xi = sk_X509_INFO_value (xis, i);
+      if (xi->x509 != NULL)
+        {
+          if (!sk_X509_push (certs, xi->x509))
+            goto end;
+          xi->x509 = NULL;
+        }
+    }
+
+end:
+  sk_X509_INFO_pop_free (xis, X509_INFO_free);
+
+  if (sk_X509_num (certs) == 0)
+    {
+      sk_X509_pop_free (certs, X509_free);
+      certs = NULL;
+    }
+
+  return certs;
+}
+
+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;
+  const gchar *anchor_path;
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  switch (prop_id)
+    {
+    case PROP_ANCHORS:
+      anchor_path = g_value_get_string (value);
+      if (anchor_path && !g_path_is_absolute (anchor_path))
+        {
+          g_warning ("The anchor file name used with a GTlsFileDatabase "
+                     "must be an absolute path, and not relative: %s", anchor_path);
+          return;
+        }
+
+      if (priv->anchor_filename)
+        {
+          g_free (priv->anchor_filename);
+          if (priv->trusted != NULL)
+            sk_X509_pop_free (priv->trusted, X509_free);
+        }
+
+      priv->anchor_filename = g_strdup (anchor_path);
+      priv->trusted = load_certs (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 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)
+{
+  GTlsFileDatabaseOpenssl *file_database;
+  GTlsFileDatabaseOpensslPrivate *priv;
+  STACK_OF(X509) *certs;
+  X509_STORE *store;
+  X509_STORE_CTX *csc;
+  X509 *x;
+  GTlsCertificateFlags result = 0;
+
+  g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (chain),
+                        G_TLS_CERTIFICATE_GENERIC_ERROR);
+
+  file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
+
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+
+  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 ();
+  csc = X509_STORE_CTX_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_free (csc);
+      X509_STORE_free (store);
+      sk_X509_free (certs);
+      return G_TLS_CERTIFICATE_GENERIC_ERROR;
+    }
+
+  if (priv->trusted)
+    {
+      X509_STORE_CTX_trusted_stack (csc, priv->trusted);
+    }
+
+  if (X509_verify_cert (csc) <= 0)
+    result = g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (csc));
+
+  X509_STORE_CTX_free (csc);
+  X509_STORE_free (store);
+  sk_X509_free (certs);
+
+  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;
+}
+
+GTlsCertificateFlags
+g_tls_file_database_openssl_verify_ocsp_response (GTlsDatabase    *database,
+                                                  GTlsCertificate *chain,
+                                                  OCSP_RESPONSE   *resp)
+{
+  GTlsCertificateFlags errors = 0;
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+  !defined(OPENSSL_NO_OCSP)
+  GTlsFileDatabaseOpenssl *file_database;
+  GTlsFileDatabaseOpensslPrivate *priv;
+  STACK_OF(X509) *chain_openssl = NULL;
+  X509_STORE *store = NULL;
+  OCSP_BASICRESP *basic_resp = NULL;
+  int ocsp_status = 0;
+  int i;
+
+  ocsp_status = OCSP_response_status (resp);
+  if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
+    {
+      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+      goto end;
+    }
+
+  basic_resp = OCSP_response_get1_basic (resp);
+  if (basic_resp == NULL)
+    {
+      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+      goto end;
+    }
+
+  chain_openssl = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
+  file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
+  priv = g_tls_file_database_openssl_get_instance_private (file_database);
+  store = X509_STORE_new ();
+  if ((chain_openssl == NULL) ||
+      (file_database == NULL) ||
+      (priv == NULL) ||
+      (priv->trusted == NULL) ||
+      (store == NULL))
+    {
+      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+      goto end;
+    }
+
+  for (i = 0; i < sk_X509_num (priv->trusted); i++)
+    {
+      X509_STORE_add_cert (store, sk_X509_value (priv->trusted, i));
+    }
+
+  if (OCSP_basic_verify (basic_resp, chain_openssl, store, 0) <= 0)
+    {
+      errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+      goto end;
+    }
+
+  for (i = 0; i < OCSP_resp_count (basic_resp); i++)
+    {
+      OCSP_SINGLERESP *single_resp = OCSP_resp_get0 (basic_resp, i);
+      ASN1_GENERALIZEDTIME *revocation_time = NULL;
+      ASN1_GENERALIZEDTIME *this_update_time = NULL;
+      ASN1_GENERALIZEDTIME *next_update_time = NULL;
+      int crl_reason = 0;
+      int cert_status = 0;
+
+      if (single_resp == NULL)
+        continue;
+
+      cert_status = OCSP_single_get0_status (single_resp,
+                                             &crl_reason,
+                                             &revocation_time,
+                                             &this_update_time,
+                                             &next_update_time);
+      if (!OCSP_check_validity (this_update_time,
+                                next_update_time,
+                                300L,
+                                -1L))
+        {
+          errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+          goto end;
+        }
+
+      switch (cert_status)
+        {
+        case V_OCSP_CERTSTATUS_GOOD:
+          break;
+        case V_OCSP_CERTSTATUS_REVOKED:
+          errors = G_TLS_CERTIFICATE_REVOKED;
+          goto end;
+        case V_OCSP_CERTSTATUS_UNKNOWN:
+          errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
+          goto end;
+        }
+    }
+
+end:
+  if (store != NULL)
+    X509_STORE_free (store);
+
+  if (basic_resp != NULL)
+    OCSP_BASICRESP_free (basic_resp);
+
+  if (resp != NULL)
+    OCSP_RESPONSE_free (resp);
+
+#endif
+  return errors;
+}
diff --git a/tls/openssl/gtlsfiledatabase-openssl.h b/tls/openssl/gtlsfiledatabase-openssl.h
new file mode 100644
index 0000000..67086db
--- /dev/null
+++ b/tls/openssl/gtlsfiledatabase-openssl.h
@@ -0,0 +1,62 @@
+/*
+ * 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>
+
+#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;
+
+GTlsCertificateFlags         g_tls_file_database_openssl_verify_ocsp_response  (GTlsDatabase    *database,
+                                                                                GTlsCertificate *chain,
+                                                                                OCSP_RESPONSE   *resp);
+
+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..6a99574
--- /dev/null
+++ b/tls/openssl/gtlsserverconnection-openssl.c
@@ -0,0 +1,421 @@
+/*
+ * 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-include.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
+};
+
+#define DEFAULT_CIPHER_LIST "HIGH:!DSS:!aNULL@STRENGTH"
+
+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)
+{
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+static void
+ssl_info_callback (const SSL *ssl,
+                   int        type,
+                   int        val)
+{
+  if ((type & SSL_CB_HANDSHAKE_DONE) != 0)
+    {
+      /* Disable renegotiation (CVE-2009-3555) */
+      ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
+    }
+}
+#endif
+
+static void
+set_cipher_list (GTlsServerConnectionOpenssl *server)
+{
+  GTlsServerConnectionOpensslPrivate *priv;
+  const gchar *cipher_list;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (server);
+
+  cipher_list = g_getenv ("G_TLS_OPENSSL_CIPHER_LIST");
+  if (cipher_list == NULL)
+    cipher_list = DEFAULT_CIPHER_LIST;
+
+  SSL_CTX_set_cipher_list (priv->ssl_ctx, cipher_list);
+}
+
+#ifdef SSL_CTX_set1_sigalgs_list
+static void
+set_signature_algorithm_list (GTlsServerConnectionOpenssl *server)
+{
+  GTlsServerConnectionOpensslPrivate *priv;
+  const gchar *signature_algorithm_list;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (server);
+
+  signature_algorithm_list = g_getenv ("G_TLS_OPENSSL_SIGNATURE_ALGORITHM_LIST");
+  if (signature_algorithm_list == NULL)
+    return;
+
+  SSL_CTX_set1_sigalgs_list (priv->ssl_ctx, signature_algorithm_list);
+}
+#endif
+
+#ifdef SSL_CTX_set1_curves_list
+static void
+set_curve_list (GTlsServerConnectionOpenssl *server)
+{
+  GTlsServerConnectionOpensslPrivate *priv;
+  const gchar *curve_list;
+
+  priv = g_tls_server_connection_openssl_get_instance_private (server);
+
+  curve_list = g_getenv ("G_TLS_OPENSSL_CURVE_LIST");
+  if (curve_list == NULL)
+    return;
+
+  SSL_CTX_set1_curves_list (priv->ssl_ctx, curve_list);
+}
+#endif
+
+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;
+    }
+
+  /* Only TLS 1.2 or higher */
+  options = SSL_OP_NO_TICKET |
+            SSL_OP_NO_COMPRESSION |
+            SSL_OP_CIPHER_SERVER_PREFERENCE |
+            SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
+            SSL_OP_SINGLE_ECDH_USE |
+#ifdef SSL_OP_NO_TLSv1_1
+            SSL_OP_NO_TLSv1_1 |
+#endif
+            SSL_OP_NO_SSLv2 |
+            SSL_OP_NO_SSLv3 |
+            SSL_OP_NO_TLSv1;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10200000L && !defined (LIBRESSL_VERSION_NUMBER)
+  options |= SSL_OP_NO_RENEGOTIATION;
+#endif
+
+  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);
+
+  set_cipher_list (server);
+
+#ifdef SSL_CTX_set1_sigalgs_list
+  set_signature_algorithm_list (server);
+#endif
+
+#ifdef SSL_CTX_set1_curves_list
+  set_curve_list (server);
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+# ifdef SSL_CTX_set_ecdh_auto
+  SSL_CTX_set_ecdh_auto (priv->ssl_ctx, 1);
+# else
+  {
+    EC_KEY *ecdh;
+
+    ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
+    if (ecdh != NULL)
+      {
+        SSL_CTX_set_tmp_ecdh (priv->ssl_ctx, ecdh);
+        EC_KEY_free (ecdh);
+      }
+  }
+# endif
+
+  SSL_CTX_set_info_callback (priv->ssl_ctx, ssl_info_callback);
+#endif
+
+  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/meson.build b/tls/openssl/meson.build
new file mode 100644
index 0000000..5bec3b1
--- /dev/null
+++ b/tls/openssl/meson.build
@@ -0,0 +1,44 @@
+sources = files(
+  'openssl-module.c',
+  'gtlsbackend-openssl.c',
+  'gtlscertificate-openssl.c',
+  'gtlsconnection-openssl.c',
+  'gtlsserverconnection-openssl.c',
+  'gtlsclientconnection-openssl.c',
+  'gtlsdatabase-openssl.c',
+  'gtlsfiledatabase-openssl.c',
+  'gtlsbio.c',
+  'openssl-util.c',
+)
+
+incs = [top_inc]
+
+deps = [
+  gio_dep,
+  glib_dep,
+  gmodule_dep,
+  gobject_dep,
+  tlsbase_dep,
+  openssl_dep,
+]
+
+module = shared_module(
+  'gioopenssl',
+  sources: sources,
+  include_directories: incs,
+  dependencies: deps,
+  link_args: module_ldflags,
+  link_depends: symbol_map,
+  name_suffix: module_suffix,
+  install: true,
+  install_dir: gio_module_dir
+)
+
+if get_option('static_modules')
+  static_library('gioopenssl',
+    objects: module.extract_all_objects(),
+    install: true,
+    install_dir: gio_module_dir
+  )
+  pkg.generate(module)
+endif
diff --git a/tls/openssl/openssl-include.h b/tls/openssl/openssl-include.h
new file mode 100644
index 0000000..7a6a460
--- /dev/null
+++ b/tls/openssl/openssl-include.h
@@ -0,0 +1,58 @@
+/*
+ * 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
+ *          Christoph Reiter
+ */
+
+/* Due to name clashes between Windows and openssl headers we have to
+ * make sure windows.h is included before openssl and that we undef the
+ * clashing macros.
+ */
+
+#ifndef __G_TLS_OPENSSL_INCLUDE_H__
+#define __G_TLS_OPENSSL_INCLUDE_H__
+
+#include "glib.h"
+
+#ifdef G_OS_WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+/* These are defined by the Windows headers, but clash with openssl */
+#undef X509_NAME
+#undef X509_CERT_PAIR
+#undef X509_EXTENSIONS
+#undef OCSP_REQUEST
+#undef OCSP_RESPONSE
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/x509v3.h>
+#include <openssl/crypto.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
+#include <openssl/ocsp.h>
+#endif
+
+#endif /* __G_TLS_OPENSSL_INCLUDE_H__ */
diff --git a/tls/openssl/openssl-module.c b/tls/openssl/openssl-module.c
new file mode 100644
index 0000000..5cc57ed
--- /dev/null
+++ b/tls/openssl/openssl-module.c
@@ -0,0 +1,65 @@
+/*
+ * 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_openssl_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_openssl_unload (GIOModule *module)
+{
+}
+
+gchar **
+g_io_openssl_query (void)
+{
+  return g_strsplit (G_TLS_BACKEND_EXTENSION_POINT_NAME, "!", -1);
+}
diff --git a/tls/openssl/openssl-util.c b/tls/openssl/openssl-util.c
new file mode 100644
index 0000000..4c8cffe
--- /dev/null
+++ b/tls/openssl/openssl-util.c
@@ -0,0 +1,488 @@
+/* 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 <strings.h>
+#include "openssl-include.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..10618cc
--- /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-include.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__ */
+
+


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