Add log messages for debugging
[platform/upstream/glib-networking.git] / tls / openssl / gtlsclientconnection-openssl.c
index 70e26a0..7c163a8 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /*
  * gtlsclientconnection-openssl.c
  *
 #include "gtlsclientconnection-openssl.h"
 #include "gtlsbackend-openssl.h"
 #include "gtlscertificate-openssl.h"
+#include "gtlsdatabase-openssl.h"
 #include <glib/gi18n-lib.h>
 
-#define DEFAULT_CIPHER_LIST "HIGH:!DSS:!aNULL@STRENGTH"
-
-typedef struct _GTlsClientConnectionOpensslPrivate
+struct _GTlsClientConnectionOpenssl
 {
+  GTlsConnectionOpenssl parent_instance;
+
   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
 {
@@ -70,27 +68,23 @@ static void g_tls_client_connection_openssl_client_connection_interface_init (GT
 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))
+                                                g_tls_client_connection_openssl_client_connection_interface_init)
+                         G_IMPLEMENT_INTERFACE (G_TYPE_DTLS_CLIENT_CONNECTION,
+                                                NULL));
 
 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);
+  g_clear_object (&openssl->server_identity);
 
-  SSL_free (priv->ssl);
-  SSL_CTX_free (priv->ssl_ctx);
-  SSL_SESSION_free (priv->session);
+  SSL_free (openssl->ssl);
+  SSL_CTX_free (openssl->ssl_ctx);
+  SSL_SESSION_free (openssl->session);
 
   G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->finalize (object);
 }
@@ -98,14 +92,10 @@ g_tls_client_connection_openssl_finalize (GObject *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));
+  if (G_IS_NETWORK_ADDRESS (openssl->server_identity))
+    return g_network_address_get_hostname (G_NETWORK_ADDRESS (openssl->server_identity));
+  else if (G_IS_NETWORK_SERVICE (openssl->server_identity))
+    return g_network_service_get_domain (G_NETWORK_SERVICE (openssl->server_identity));
   else
     return NULL;
 }
@@ -117,41 +107,38 @@ g_tls_client_connection_openssl_get_property (GObject    *object,
                                              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);
+      g_value_set_flags (value, openssl->validation_flags);
       break;
 
     case PROP_SERVER_IDENTITY:
-      g_value_set_object (value, priv->server_identity);
+      g_value_set_object (value, openssl->server_identity);
       break;
 
     case PROP_USE_SSL3:
-      g_value_set_boolean (value, priv->use_ssl3);
+      g_value_set_boolean (value, openssl->use_ssl3);
       break;
 
     case PROP_ACCEPTED_CAS:
       accepted_cas = NULL;
-      if (priv->ca_list)
+      if (openssl->ca_list)
         {
-          for (i = 0; i < sk_X509_NAME_num (priv->ca_list); ++i)
+          for (i = 0; i < sk_X509_NAME_num (openssl->ca_list); ++i)
             {
               int size;
 
-              size = i2d_X509_NAME (sk_X509_NAME_value (priv->ca_list, i), NULL);
+              size = i2d_X509_NAME (sk_X509_NAME_value (openssl->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);
+                  size = i2d_X509_NAME (sk_X509_NAME_value (openssl->ca_list, i), &ca);
                   if (size > 0)
                     accepted_cas = g_list_prepend (accepted_cas, g_byte_array_new_take (
                                                    ca, size));
@@ -176,24 +163,21 @@ g_tls_client_connection_openssl_set_property (GObject      *object,
                                              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);
+      openssl->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);
+      if (openssl->server_identity)
+        g_object_unref (openssl->server_identity);
+      openssl->server_identity = g_value_dup_object (value);
       break;
 
     case PROP_USE_SSL3:
-      priv->use_ssl3 = g_value_get_boolean (value);
+      openssl->use_ssl3 = g_value_get_boolean (value);
       break;
 
     default:
@@ -202,82 +186,80 @@ g_tls_client_connection_openssl_set_property (GObject      *object,
 }
 
 static void
-g_tls_client_connection_openssl_constructed (GObject *object)
+g_tls_client_connection_openssl_complete_handshake (GTlsConnectionBase   *tls,
+                                                    gboolean              handshake_succeeded,
+                                                    gchar               **negotiated_protocol,
+                                                    GTlsProtocolVersion  *protocol_version,
+                                                    gchar               **ciphersuite_name,
+                                                    GError              **error)
 {
-  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)
+  GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (tls);
+
+  if (G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->complete_handshake)
+    G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->complete_handshake (tls,
+                                                                                                    handshake_succeeded,
+                                                                                                    negotiated_protocol,
+                                                                                                    protocol_version,
+                                                                                                    ciphersuite_name,
+                                                                                                    error);
+
+  /* It may have changed during the handshake, but we have to wait until here
+   * because we can't emit notifies on the handshake thread.
    */
-  g_object_get (G_OBJECT (openssl), "base-io-stream", &base_conn, NULL);
-  if (G_IS_SOCKET_CONNECTION (base_conn))
+  g_object_notify (G_OBJECT (client), "accepted-cas");
+}
+
+static GTlsCertificateFlags
+verify_ocsp_response (GTlsClientConnectionOpenssl *openssl,
+                      GTlsCertificate             *peer_certificate)
+{
+  SSL *ssl = NULL;
+  OCSP_RESPONSE *resp = NULL;
+  GTlsDatabase *database;
+  long len = 0;
+  unsigned char *p = NULL;
+
+  ssl = g_tls_connection_openssl_get_ssl (G_TLS_CONNECTION_OPENSSL (openssl));
+  len = SSL_get_tlsext_status_ocsp_resp (ssl, &p);
+  if (p)
     {
-      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);
+      resp = d2i_OCSP_RESPONSE (NULL, (const unsigned char **)&p, len);
+      if (!resp)
+        return G_TLS_CERTIFICATE_GENERIC_ERROR;
     }
-  g_object_unref (base_conn);
 
-  G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->constructed (object);
-}
+  database = g_tls_connection_get_database (G_TLS_CONNECTION (openssl));
 
-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);
+  /* If there's no database, then G_TLS_CERTIFICATE_UNKNOWN_CA must be flagged,
+   * and this function is only called if there are no flags.
+   */
+  g_assert (database);
+
+  /* Note we have to call this even if resp is NULL, because it will check
+   * whether Must-Staple is set.
+   */
+  return g_tls_database_openssl_verify_ocsp_response (G_TLS_DATABASE_OPENSSL (database),
+                                                      peer_certificate,
+                                                      resp);
 }
 
-static GTlsConnectionBaseStatus
-g_tls_client_connection_openssl_complete_handshake (GTlsConnectionBase  *tls,
-                                                    GError             **error)
+static GTlsCertificateFlags
+g_tls_client_connection_openssl_verify_peer_certificate (GTlsConnectionBase   *tls,
+                                                         GTlsCertificate      *certificate,
+                                                         GTlsCertificateFlags  flags)
 {
-  GTlsConnectionBaseStatus status;
+  GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (tls);
 
-  status = G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->
-    complete_handshake (tls, error);
+  if (flags == 0)
+    flags = verify_ocsp_response (openssl, certificate);
 
-  return status;
+  return flags;
 }
 
 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;
+  return G_TLS_CLIENT_CONNECTION_OPENSSL (connection)->ssl;
 }
 
 static void
@@ -285,17 +267,16 @@ g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *kl
 {
   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);
+  GTlsConnectionOpensslClass *openssl_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;
+  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;
 
-  base_class->handshake          = g_tls_client_connection_openssl_handshake;
-  base_class->complete_handshake = g_tls_client_connection_openssl_complete_handshake;
+  base_class->complete_handshake      = g_tls_client_connection_openssl_complete_handshake;
+  base_class->verify_peer_certificate = g_tls_client_connection_openssl_verify_peer_certificate;
 
-  connection_class->get_ssl = g_tls_client_connection_openssl_get_ssl;
+  openssl_class->get_ssl              = g_tls_client_connection_openssl_get_ssl;
 
   g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
   g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
@@ -308,7 +289,6 @@ g_tls_client_connection_openssl_init (GTlsClientConnectionOpenssl *openssl)
 {
 }
 
-
 static void
 g_tls_client_connection_openssl_copy_session_state (GTlsClientConnection *conn,
                                                     GTlsClientConnection *source)
@@ -322,102 +302,123 @@ g_tls_client_connection_openssl_client_connection_interface_init (GTlsClientConn
 }
 
 static int data_index = -1;
+#ifdef TIZEN_EXT
+G_LOCK_DEFINE_STATIC(data_index);
+#define DATA_INDEX_LOCK(m) G_LOCK(m)
+#define DATA_INDEX_UNLOCK(m) G_UNLOCK(m)
+#else
+#define DATA_INDEX_LOCK(m)
+#define DATA_INDEX_UNLOCK(m)
+#endif
 
 static int
-retrieve_certificate (SSL       *ssl,
-                      X509     **x509,
-                      EVP_PKEY **pkey)
+handshake_thread_retrieve_certificate (SSL       *ssl,
+                                       X509     **x509,
+                                       EVP_PKEY **pkey)
 {
   GTlsClientConnectionOpenssl *client;
-  GTlsClientConnectionOpensslPrivate *priv;
   GTlsConnectionBase *tls;
-  GTlsConnectionOpenssl *openssl;
   GTlsCertificate *cert;
-  gboolean set_certificate = FALSE;
+  int idx;
 
+  DATA_INDEX_LOCK(data_index);
+  idx = data_index;
   client = SSL_get_ex_data (ssl, data_index);
+  DATA_INDEX_UNLOCK(data_index);
+  if (!client)
+  {
+         TIZEN_LOGE("SSL_get_ex_data(%p) returns NULL.", ssl);
+         return 0;
+  }
   tls = G_TLS_CONNECTION_BASE (client);
-  openssl = G_TLS_CONNECTION_OPENSSL (client);
 
-  priv = g_tls_client_connection_openssl_get_instance_private (client);
+  TIZEN_LOGI("ssl[%p] client[%p] tls[%p] data_index[%d]", ssl, client, tls, idx);
 
-  tls->certificate_requested = TRUE;
-
-  priv->ca_list = SSL_get_client_CA_list (priv->ssl);
-  g_object_notify (G_OBJECT (client), "accepted-cas");
+  client->ca_list = SSL_get_client_CA_list (client->ssl);
 
   cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
-  if (cert != NULL)
-    set_certificate = TRUE;
-  else
+  if (!cert)
     {
-      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 (g_tls_connection_base_handshake_thread_request_certificate (tls))
+        cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
     }
 
-  if (set_certificate)
+  if (cert)
     {
       EVP_PKEY *key;
 
       key = g_tls_certificate_openssl_get_key (G_TLS_CERTIFICATE_OPENSSL (cert));
-      /* increase ref count */
+
+      if (key != NULL)
+        {
+          /* increase ref count */
 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
-      CRYPTO_add (&key->references, 1, CRYPTO_LOCK_EVP_PKEY);
+          CRYPTO_add (&key->references, 1, CRYPTO_LOCK_EVP_PKEY);
 #else
-      EVP_PKEY_up_ref (key);
+          EVP_PKEY_up_ref (key);
 #endif
-      *pkey = key;
+          *pkey = key;
 
-      *x509 = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
+          *x509 = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
 
-      return 1;
+          return 1;
+        }
     }
 
-  return 0;
-}
+  g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate (tls);
 
-static int
-generate_session_id (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;
+  return 0;
 }
 
 static gboolean
 set_cipher_list (GTlsClientConnectionOpenssl  *client,
                  GError                      **error)
 {
-  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;
+  if (cipher_list)
+    {
+      if (!SSL_CTX_set_cipher_list (client->ssl_ctx, cipher_list))
+        {
+          char error_buffer[256];
+          ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
+          g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                       _("Could not set TLS cipher list: %s"),
+                       error_buffer);
+          return FALSE;
+        }
+    }
 
-  if (!SSL_CTX_set_cipher_list (priv->ssl_ctx, cipher_list))
+  return TRUE;
+}
+
+static gboolean
+set_max_protocol (GTlsClientConnectionOpenssl  *client,
+                  GError                      **error)
+{
+#ifdef SSL_CTX_set_max_proto_version
+  const gchar *proto;
+
+  proto = g_getenv ("G_TLS_OPENSSL_MAX_PROTO");
+  if (proto)
     {
-      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;
+      gint64 version = g_ascii_strtoll (proto, NULL, 0);
+
+      if (version > 0 && version < G_MAXINT)
+        {
+          if (!SSL_CTX_set_max_proto_version (client->ssl_ctx, (int)version))
+            {
+              char error_buffer[256];
+              ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
+              g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                           _("Could not set MAX protocol to %d: %s"),
+                           (int)version, error_buffer);
+              return FALSE;
+            }
+        }
     }
+#endif
 
   return TRUE;
 }
@@ -426,16 +427,13 @@ set_cipher_list (GTlsClientConnectionOpenssl  *client,
 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)
+  if (!signature_algorithm_list)
     return;
 
-  SSL_CTX_set1_sigalgs_list (priv->ssl_ctx, signature_algorithm_list);
+  SSL_CTX_set1_sigalgs_list (client->ssl_ctx, signature_algorithm_list);
 }
 #endif
 
@@ -443,51 +441,51 @@ set_signature_algorithm_list (GTlsClientConnectionOpenssl *client)
 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)
+  if (!curve_list)
     return;
 
-  SSL_CTX_set1_curves_list (priv->ssl_ctx, curve_list);
+  SSL_CTX_set1_curves_list (client->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;
+  char error_buffer[256];
 
-  priv = g_tls_client_connection_openssl_get_instance_private (client);
-
-  priv->session = SSL_SESSION_new ();
+  client->session = SSL_SESSION_new ();
 
-  priv->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
-  if (priv->ssl_ctx == NULL)
+  client->ssl_ctx = SSL_CTX_new (g_tls_connection_base_is_dtls (G_TLS_CONNECTION_BASE (client))
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+                                 ? DTLS_client_method ()
+                                 : TLS_client_method ());
+#else
+                                 ? DTLSv1_client_method ()
+                                 : SSLv23_client_method ());
+#endif
+  if (!client->ssl_ctx)
     {
+      ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
                    _("Could not create TLS context: %s"),
-                   ERR_error_string (ERR_get_error (), NULL));
+                   error_buffer);
       return FALSE;
     }
 
   if (!set_cipher_list (client, error))
     return FALSE;
 
+  if (!set_max_protocol (client, error))
+    return FALSE;
+
   /* Only TLS 1.2 or higher */
   options = SSL_OP_NO_TICKET |
             SSL_OP_NO_COMPRESSION |
@@ -497,29 +495,25 @@ g_tls_client_connection_openssl_initable_init (GInitable       *initable,
             SSL_OP_NO_SSLv2 |
             SSL_OP_NO_SSLv3 |
             SSL_OP_NO_TLSv1;
-  SSL_CTX_set_options (priv->ssl_ctx, options);
+  SSL_CTX_set_options (client->ssl_ctx, options);
 
-  SSL_CTX_clear_options (priv->ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT);
+  SSL_CTX_clear_options (client->ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT);
 
   hostname = get_server_identity (client);
 
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined (LIBRESSL_VERSION_NUMBER)
   if (hostname)
     {
       X509_VERIFY_PARAM *param;
 
       param = X509_VERIFY_PARAM_new ();
       X509_VERIFY_PARAM_set1_host (param, hostname, 0);
-      SSL_CTX_set1_param (priv->ssl_ctx, param);
+      SSL_CTX_set1_param (client->ssl_ctx, param);
       X509_VERIFY_PARAM_free (param);
     }
-#endif
 
-  SSL_CTX_set_generate_session_id (priv->ssl_ctx, (GEN_SESSION_CB)generate_session_id);
+  SSL_CTX_add_session (client->ssl_ctx, client->session);
 
-  SSL_CTX_add_session (priv->ssl_ctx, priv->session);
-
-  SSL_CTX_set_client_cert_cb (priv->ssl_ctx, retrieve_certificate);
+  SSL_CTX_set_client_cert_cb (client->ssl_ctx, handshake_thread_retrieve_certificate);
 
 #ifdef SSL_CTX_set1_sigalgs_list
   set_signature_algorithm_list (client);
@@ -529,31 +523,36 @@ g_tls_client_connection_openssl_initable_init (GInitable       *initable,
   set_curve_list (client);
 #endif
 
-  priv->ssl = SSL_new (priv->ssl_ctx);
-  if (priv->ssl == NULL)
+  client->ssl = SSL_new (client->ssl_ctx);
+  if (!client->ssl)
     {
+      ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
                    _("Could not create TLS connection: %s"),
-                   ERR_error_string (ERR_get_error (), NULL));
+                   error_buffer);
       return FALSE;
     }
 
+  DATA_INDEX_LOCK(data_index);
   if (data_index == -1) {
-      data_index = SSL_get_ex_new_index (0, (void *)"gtlsclientconnection", NULL, NULL, NULL);
+         data_index = SSL_get_ex_new_index (0, (void *)"gtlsclientconnection", NULL, NULL, NULL);
+         TIZEN_LOGI("new data_index[%d]", data_index);
+  } else {
+         TIZEN_LOGI("data_index[%d] is already exist", data_index);
   }
-  SSL_set_ex_data (priv->ssl, data_index, client);
+  SSL_set_ex_data (client->ssl, data_index, client);
+  DATA_INDEX_UNLOCK(data_index);
 
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-  if (hostname)
-    SSL_set_tlsext_host_name (priv->ssl, hostname);
+  if (hostname && !g_hostname_is_ip_address (hostname))
+    SSL_set_tlsext_host_name (client->ssl, hostname);
 #endif
 
-  SSL_set_connect_state (priv->ssl);
+  SSL_set_connect_state (client->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);
+  SSL_set_tlsext_status_type (client->ssl, TLSEXT_STATUSTYPE_ocsp);
 #endif
 
   if (!g_tls_client_connection_openssl_parent_initable_iface->