[glib-networking/mcatanzaro/tls-thread] ridicuous unstable wip progress
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/mcatanzaro/tls-thread] ridicuous unstable wip progress
- Date: Sat, 21 Dec 2019 20:38:38 +0000 (UTC)
commit 656ffbd15e4e84f92f1d54f01b044918b0cbaed4
Author: Michael Catanzaro <mcatanzaro gnome org>
Date: Sat Dec 21 13:45:42 2019 -0600
ridicuous unstable wip progress
tls/base/gtlsconnection-base.c | 200 +--------
tls/base/gtlsconnection-base.h | 45 +-
tls/base/gtlsoperationsthread-base.c | 7 +-
tls/base/gtlsoperationsthread-base.h | 12 +-
tls/gnutls/gtlsclientconnection-gnutls.c | 84 ----
tls/gnutls/gtlsconnection-gnutls.c | 657 ++---------------------------
tls/gnutls/gtlsconnection-gnutls.h | 3 -
tls/gnutls/gtlsoperationsthread-gnutls.c | 603 +++++++++++++++++++++++++-
tls/gnutls/gtlsoperationsthread-gnutls.h | 8 +-
tls/openssl/gtlsconnection-openssl.c | 227 +---------
tls/openssl/gtlsconnection-openssl.h | 2 +
tls/openssl/gtlsoperationsthread-openssl.c | 30 ++
12 files changed, 700 insertions(+), 1178 deletions(-)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index 83e0765..d2dcfef 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -143,14 +143,7 @@ typedef struct
gboolean write_closing, write_closed;
gboolean reading;
- gint64 read_timeout;
- GError *read_error;
- GCancellable *read_cancellable;
-
gboolean writing;
- gint64 write_timeout;
- GError *write_error;
- GCancellable *write_cancellable;
gboolean successful_posthandshake_op;
@@ -291,10 +284,6 @@ g_tls_connection_base_finalize (GObject *object)
g_clear_object (&priv->async_implicit_handshake);
g_clear_error (&priv->handshake_error);
- g_clear_error (&priv->read_error);
- g_clear_error (&priv->write_error);
- g_clear_object (&priv->read_cancellable);
- g_clear_object (&priv->write_cancellable);
g_clear_object (&priv->waiting_for_op);
g_mutex_clear (&priv->op_mutex);
@@ -766,29 +755,7 @@ yield_op (GTlsConnectionBase *tls,
g_mutex_unlock (&priv->op_mutex);
}
-static void
-g_tls_connection_base_real_push_io (GTlsConnectionBase *tls,
- GIOCondition direction,
- gint64 timeout,
- GCancellable *cancellable)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- if (direction & G_IO_IN)
- {
- priv->read_timeout = timeout;;
- priv->read_cancellable = cancellable;
- g_clear_error (&priv->read_error);
- }
-
- if (direction & G_IO_OUT)
- {
- priv->write_timeout = timeout;
- priv->write_cancellable = cancellable;
- g_clear_error (&priv->write_error);
- }
-}
-
+/* FIXME: removable? */
void
g_tls_connection_base_push_io (GTlsConnectionBase *tls,
GIOCondition direction,
@@ -802,6 +769,7 @@ g_tls_connection_base_push_io (GTlsConnectionBase *tls,
timeout, cancellable);
}
+/* FIXME: rename, if push_io is removed? */
static GTlsConnectionBaseStatus
g_tls_connection_base_real_pop_io (GTlsConnectionBase *tls,
GIOCondition direction,
@@ -813,30 +781,6 @@ g_tls_connection_base_real_pop_io (GTlsConnectionBase *tls,
/* This function MAY or MAY NOT set error when it fails! */
- if (direction & G_IO_IN)
- {
- priv->read_cancellable = NULL;
- if (!success)
- {
- my_error = priv->read_error;
- priv->read_error = NULL;
- }
- else
- g_clear_error (&priv->read_error);
- }
-
- if (direction & G_IO_OUT)
- {
- priv->write_cancellable = NULL;
- if (!success && !my_error)
- {
- my_error = priv->write_error;
- priv->write_error = NULL;
- }
- else
- g_clear_error (&priv->write_error);
- }
-
if (success)
return G_TLS_CONNECTION_BASE_OK;
@@ -902,7 +846,8 @@ g_tls_connection_base_pop_io (GTlsConnectionBase *tls,
}
/* Checks whether the underlying base stream or GDatagramBased meets
- * @condition. */
+ * @condition.
+ */
gboolean
g_tls_connection_base_base_check (GTlsConnectionBase *tls,
GIOCondition condition)
@@ -922,7 +867,8 @@ g_tls_connection_base_base_check (GTlsConnectionBase *tls,
}
/* Checks whether the (D)TLS stream meets @condition; not the underlying base
- * stream or GDatagramBased. */
+ * stream or GDatagramBased.
+ */
gboolean
g_tls_connection_base_check (GTlsConnectionBase *tls,
GIOCondition condition)
@@ -1474,13 +1420,9 @@ handshake (GTlsConnectionBase *tls,
GError **error)
{
GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
- GTlsConnectionBaseClass *tls_class = G_TLS_CONNECTION_BASE_GET_CLASS (tls);
- gint64 start_time;
g_tls_log_debug (tls, "TLS handshake starts");
- start_time = g_get_monotonic_time ();
-
priv->started_handshake = FALSE;
priv->missing_requested_client_certificate = FALSE;
@@ -1498,44 +1440,17 @@ handshake (GTlsConnectionBase *tls,
if (priv->ever_handshaked && !priv->need_handshake)
{
- GTlsConnectionBaseStatus status;
-
- /* FIXME: no longer handshake thread */
- if (tls_class->handshake_thread_safe_renegotiation_status (tls) !=
G_TLS_SAFE_RENEGOTIATION_SUPPORTED_BY_PEER)
- {
- g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
- _("Peer does not support safe renegotiation"));
- g_tls_log_debug (tls, "TLS handshake failed: peer does not support safe renegotiation");
- return FALSE;
- }
-
- /* Adjust the timeout for the next operation in the sequence. */
- if (timeout > 0)
- {
- timeout -= (g_get_monotonic_time () - start_time);
- if (timeout <= 0)
- timeout = 1;
- }
-
- /* FIXME: no longer handshake thread */
- status = tls_class->handshake_thread_request_rehandshake (tls, timeout, cancellable, error);
- if (status != G_TLS_CONNECTION_BASE_OK)
- {
- g_tls_log_debug (tls, "TLS handshake failed: %s", *error ? (*error)->message : "no error");
- return FALSE;
- }
- }
-
- /* Adjust the timeout for the next operation in the sequence. */
- if (timeout > 0)
- {
- timeout -= (g_get_monotonic_time () - start_time);
- if (timeout <= 0)
- timeout = 1;
+ /* Once upon a time, we allowed calling g_tls_connection_handshake()
+ * twice in order to request a rehandshake. Now that rehandshaking has
+ * been removed from TLS 1.3, we'll instead just ignore the request. We
+ * can't throw an error here because this used to be allowed.
+ */
+ g_tls_log_debug (tls, "Ignoring duplicate TLS handshake request");
+ return TRUE;
}
priv->started_handshake = TRUE;
- g_tls_operations_thread_base_handshake (priv->thread, timeout, cancellable, error);
+ g_tls_operations_thread_base_handshake (priv->thread, priv->advertised_protocols, timeout, cancellable,
error);
priv->need_handshake = FALSE;
if (error && *error)
@@ -1632,9 +1547,6 @@ g_tls_connection_base_handshake (GTlsConnection *conn,
g_main_context_push_thread_default (priv->handshake_context);
- if (tls_class->prepare_handshake)
- tls_class->prepare_handshake (tls, priv->advertised_protocols);
-
success = handshake (tls, -1 /* blocking */, cancellable, error);
g_mutex_lock (&priv->op_mutex);
@@ -1783,9 +1695,6 @@ g_tls_connection_base_handshake_async (GTlsConnection *conn,
g_assert (!priv->handshake_context);
priv->handshake_context = g_main_context_ref_thread_default ();
- if (tls_class->prepare_handshake)
- tls_class->prepare_handshake (tls, priv->advertised_protocols);
-
caller_task = g_task_new (conn, cancellable, callback, user_data);
g_task_set_source_tag (caller_task, g_tls_connection_base_handshake_async);
g_task_set_name (caller_task, "[glib-networking] g_tls_connection_base_handshake_async (caller task)");
@@ -1852,9 +1761,6 @@ start_async_implicit_handshake (GTlsConnectionBase *tls,
g_task_set_source_tag (priv->async_implicit_handshake, do_implicit_handshake);
g_task_set_name (priv->async_implicit_handshake, "[glib-networking] do_implicit_handshake");
- if (tls_class->prepare_handshake)
- tls_class->prepare_handshake (tls, priv->advertised_protocols);
-
/* In the non-blocking case, start the asynchronous handshake operation
* and return EWOULDBLOCK to the caller, who will handle polling for
* completion of the handshake and whatever operation they actually cared
@@ -1889,9 +1795,6 @@ do_sync_implicit_handshake (GTlsConnectionBase *tls,
priv->handshake_context = g_main_context_new ();
g_main_context_push_thread_default (priv->handshake_context);
- if (tls_class->prepare_handshake)
- tls_class->prepare_handshake (tls, priv->advertised_protocols);
-
g_mutex_unlock (&priv->op_mutex);
success = handshake (tls, timeout, cancellable, &my_error);
@@ -2561,70 +2464,6 @@ g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate
priv->missing_requested_client_certificate = TRUE;
}
-GError **
-g_tls_connection_base_get_read_error (GTlsConnectionBase *tls)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- return &priv->read_error;
-}
-
-GError **
-g_tls_connection_base_get_write_error (GTlsConnectionBase *tls)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- return &priv->write_error;
-}
-
-gint64
-g_tls_connection_base_get_read_timeout (GTlsConnectionBase *tls)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- return priv->read_timeout;
-}
-
-gint64
-g_tls_connection_base_get_write_timeout (GTlsConnectionBase *tls)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- return priv->write_timeout;
-}
-
-GCancellable *
-g_tls_connection_base_get_read_cancellable (GTlsConnectionBase *tls)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- return priv->read_cancellable;
-}
-
-GCancellable *
-g_tls_connection_base_get_write_cancellable (GTlsConnectionBase *tls)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- return priv->write_cancellable;
-}
-
-gboolean
-g_tls_connection_base_is_handshaking (GTlsConnectionBase *tls)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- return priv->handshaking;
-}
-
-gboolean
-g_tls_connection_base_ever_handshaked (GTlsConnectionBase *tls)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- return priv->ever_handshaked;
-}
-
gboolean
g_tls_connection_base_handshake_thread_request_certificate (GTlsConnectionBase *tls)
{
@@ -2644,7 +2483,7 @@ g_tls_connection_base_handshake_thread_request_certificate (GTlsConnectionBase *
return FALSE;
res = g_tls_interaction_invoke_request_certificate (interaction, conn, 0,
- priv->read_cancellable,
+ /* FIXME: priv->read_cancellable */ NULL,
&priv->interaction_error);
return res != G_TLS_INTERACTION_FAILED;
}
@@ -2662,6 +2501,14 @@ g_tls_connection_base_handshake_thread_buffer_application_data (GTlsConnectionBa
g_byte_array_append (priv->app_data_buf, data, length);
}
+GTlsOperationsThreadBase *
+g_tls_connection_base_get_op_thread (GTlsConnectionBase *tls)
+{
+ GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
+
+ return priv->thread;
+}
+
static void
g_tls_connection_base_class_init (GTlsConnectionBaseClass *klass)
{
@@ -2683,7 +2530,6 @@ g_tls_connection_base_class_init (GTlsConnectionBaseClass *klass)
iostream_class->close_async = g_tls_connection_base_close_async;
iostream_class->close_finish = g_tls_connection_base_close_finish;
- klass->push_io = g_tls_connection_base_real_push_io;
klass->pop_io = g_tls_connection_base_real_pop_io;
/* For GTlsConnection and GDtlsConnection: */
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index fa155f3..65058d0 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -48,11 +48,6 @@ typedef enum {
G_TLS_DIRECTION_WRITE = 1 << 1,
} GTlsDirection;
-typedef enum {
- G_TLS_SAFE_RENEGOTIATION_SUPPORTED_BY_PEER,
- G_TLS_SAFE_RENEGOTIATION_UNSUPPORTED
-} GTlsSafeRenegotiationStatus;
-
#define G_TLS_DIRECTION_BOTH (G_TLS_DIRECTION_READ | G_TLS_DIRECTION_WRITE)
typedef struct _GTlsOperationsThreadBase GTlsOperationsThreadBase;
@@ -63,28 +58,6 @@ struct _GTlsConnectionBaseClass
GTlsOperationsThreadBase *(*create_op_thread) (GTlsConnectionBase *tls);
- /* FIXME: deal with all the handshaking stuff */
- void (*prepare_handshake) (GTlsConnectionBase *tls,
- gchar **advertised_protocols);
- GTlsSafeRenegotiationStatus (*handshake_thread_safe_renegotiation_status)
- (GTlsConnectionBase *tls);
- GTlsConnectionBaseStatus (*handshake_thread_request_rehandshake)
- (GTlsConnectionBase *tls,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error);
- GTlsConnectionBaseStatus (*handshake_thread_handshake) (GTlsConnectionBase *tls,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error);
- GTlsCertificate *(*retrieve_peer_certificate) (GTlsConnectionBase *tls);
- GTlsCertificateFlags (*verify_peer_certificate) (GTlsConnectionBase *tls,
- GTlsCertificate *certificate,
- GTlsCertificateFlags flags);
- void (*complete_handshake) (GTlsConnectionBase *tls,
- gchar **negotiated_protocol,
- GError **error);
-
gboolean (*is_session_resumed) (GTlsConnectionBase *tls);
void (*push_io) (GTlsConnectionBase *tls,
@@ -139,6 +112,8 @@ gboolean g_tls_connection_base_close_internal (GIOStre
GCancellable *cancellable,
GError **error);
+/* FIXME: audit, which are still needed? */
+
gboolean g_tls_connection_base_is_dtls (GTlsConnectionBase *tls);
GDatagramBased *g_tls_connection_base_get_base_socket (GTlsConnectionBase *tls);
@@ -150,19 +125,6 @@ GPollableOutputStream *g_tls_connection_base_get_base_ostream (GTlsCon
void g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate
(GTlsConnectionBase *tls);
-GError **g_tls_connection_base_get_read_error (GTlsConnectionBase *tls);
-GError **g_tls_connection_base_get_write_error (GTlsConnectionBase *tls);
-
-gint64 g_tls_connection_base_get_read_timeout (GTlsConnectionBase *tls);
-gint64 g_tls_connection_base_get_write_timeout (GTlsConnectionBase *tls);
-
-GCancellable *g_tls_connection_base_get_read_cancellable (GTlsConnectionBase *tls);
-GCancellable *g_tls_connection_base_get_write_cancellable (GTlsConnectionBase *tls);
-
-gboolean g_tls_connection_base_is_handshaking (GTlsConnectionBase *tls);
-
-gboolean g_tls_connection_base_ever_handshaked (GTlsConnectionBase *tls);
-
gboolean g_tls_connection_base_handshake_thread_request_certificate
(GTlsConnectionBase *tls);
@@ -171,4 +133,7 @@ void g_tls_connection_base_handshake_thread_buffer_applicat
guint8 *data,
gsize length);
+/* FIXME: needed? */
+GTlsOperationsThreadBase *g_tls_connection_base_get_op_thread (GTlsConnectionBase *tls);
+
G_END_DECLS
diff --git a/tls/base/gtlsoperationsthread-base.c b/tls/base/gtlsoperationsthread-base.c
index 18cf84c..fc37fd2 100644
--- a/tls/base/gtlsoperationsthread-base.c
+++ b/tls/base/gtlsoperationsthread-base.c
@@ -133,7 +133,7 @@ enum
static GParamSpec *obj_properties[LAST_PROP];
-G_DEFINE_TYPE_WITH_PRIVATE (GTlsOperationsThreadBase, g_tls_operations_thread_base, G_TYPE_OBJECT)
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GTlsOperationsThreadBase, g_tls_operations_thread_base, G_TYPE_OBJECT)
GTlsConnectionBase *
g_tls_operations_thread_base_get_connection (GTlsOperationsThreadBase *self)
@@ -898,7 +898,7 @@ g_tls_operations_thread_base_set_property (GObject *object,
/* This weak pointer is not required for correctness, because the
* thread should never outlive its GTlsConnection. It's only here
- * as a sanity-check and debugging aid, to ensure self->connection
+ * as a sanity-check and debugging aid, to ensure priv->connection
* isn't ever dangling.
*/
g_object_add_weak_pointer (G_OBJECT (priv->connection),
@@ -952,6 +952,9 @@ g_tls_operations_thread_base_class_init (GTlsOperationsThreadBaseClass *klass)
gobject_class->get_property = g_tls_operations_thread_base_get_property;
gobject_class->set_property = g_tls_operations_thread_base_set_property;
+ /* FIXME: remove this. subclass has been designed to not need it!
+ * Move base_iostream and base_socket up to this level.
+ */
obj_properties[PROP_TLS_CONNECTION] =
g_param_spec_object ("tls-connection",
"TLS Connection",
diff --git a/tls/base/gtlsoperationsthread-base.h b/tls/base/gtlsoperationsthread-base.h
index 63f7a34..a26dd7d 100644
--- a/tls/base/gtlsoperationsthread-base.h
+++ b/tls/base/gtlsoperationsthread-base.h
@@ -38,10 +38,19 @@ struct _GTlsOperationsThreadBaseClass
{
GObjectClass parent_class;
+/* FIXME: working on these... */
GTlsConnectionBaseStatus (*handshake_fn) (GTlsOperationsThreadBase *self,
+ gchar **advertised_protocols,
gint64 timeout,
GCancellable *cancellable,
GError **error);
+ GTlsCertificate *(*retrieve_peer_certificate) (GTlsOperationsThreadBase *self);
+ GTlsCertificateFlags (*verify_peer_certificate) (GTlsOperationsThreadBase *self,
+ GTlsCertificate *certificate,
+ GTlsCertificateFlags flags);
+ void (*complete_handshake) (GTlsOperationsThreadBase *self,
+ gchar **negotiated_protocol,
+ GError **error);
GTlsConnectionBaseStatus (*read_fn) (GTlsOperationsThreadBase *self,
void *buffer,
@@ -74,10 +83,11 @@ struct _GTlsOperationsThreadBaseClass
GError **error);
};
-/* FIXME: remove? */
+/* FIXME: remove!!! */
GTlsConnectionBase *g_tls_operations_thread_base_get_connection (GTlsOperationsThreadBase *self);
GTlsConnectionBaseStatus g_tls_operations_thread_base_handshake (GTlsOperationsThreadBase *self,
+ gchar
**advertised_protocols,
gint64 timeout,
GCancellable
*cancellable,
GError **error);
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 1d2ba78..e74b43f 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -120,87 +120,6 @@ get_server_identity (GTlsClientConnectionGnutls *gnutls)
return NULL;
}
-static void
-g_tls_client_connection_gnutls_compute_session_id (GTlsClientConnectionGnutls *gnutls)
-{
- GSocketConnection *base_conn;
- GSocketAddress *remote_addr;
- GInetAddress *iaddr;
- guint port;
-
- /* The testsuite expects handshakes to actually happen. E.g. a test might
- * check to see that a handshake succeeds and then later check that a new
- * handshake fails. If we get really unlucky and the same port number is
- * reused for the server socket between connections, then we'll accidentally
- * resume the old session and skip certificate verification. Such failures
- * are difficult to debug because they require running the tests hundreds of
- * times simultaneously to reproduce (the port number does not get reused
- * quickly enough if the tests are run sequentially).
- *
- * So session resumption will just need to be tested manually.
- */
- if (g_test_initialized ())
- return;
-
- /* 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)
- *
- * Note that our session IDs have no relation to TLS protocol
- * session IDs, e.g. as provided by gnutls_session_get_id2(). Unlike
- * our session IDs, actual TLS session IDs can no longer be used for
- * session resumption.
- */
- g_object_get (G_OBJECT (gnutls), "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;
- GTlsCertificate *cert = NULL;
- gchar *cert_hash = NULL;
-
- 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 (gnutls);
-
- /* If we have a certificate, make its hash part of the session ID, so
- * that different connections to the same server can use different
- * certificates.
- */
- g_object_get (G_OBJECT (gnutls), "certificate", &cert, NULL);
- if (cert)
- {
- GByteArray *der = NULL;
- g_object_get (G_OBJECT (cert), "certificate", &der, NULL);
- if (der)
- {
- cert_hash = g_compute_checksum_for_data (G_CHECKSUM_SHA256, der->data, der->len);
- g_byte_array_unref (der);
- }
- g_object_unref (cert);
- }
- session_id = g_strdup_printf ("%s/%s/%d/%s", addrstr,
- server_hostname ? server_hostname : "",
- port,
- cert_hash ? cert_hash : "");
- gnutls->session_id = g_bytes_new_take (session_id, strlen (session_id));
- g_free (addrstr);
- g_free (cert_hash);
- }
- g_object_unref (remote_addr);
- }
- g_clear_object (&base_conn);
-}
-
static int
handshake_thread_session_ticket_received_cb (gnutls_session_t session,
guint htype,
@@ -478,8 +397,6 @@ g_tls_client_connection_gnutls_prepare_handshake (GTlsConnectionBase *tls,
}
}
- G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_gnutls_parent_class)->
- prepare_handshake (tls, advertised_protocols);
}
static void
@@ -535,7 +452,6 @@ g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klas
gobject_class->set_property = g_tls_client_connection_gnutls_set_property;
gobject_class->finalize = g_tls_client_connection_gnutls_finalize;
- base_class->prepare_handshake = g_tls_client_connection_gnutls_prepare_handshake;
base_class->complete_handshake = g_tls_client_connection_gnutls_complete_handshake;
g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 3bccc98..d1a6b68 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -27,6 +27,8 @@
#include "config.h"
#include "glib.h"
+/* FIXME: audit includes to remove */
+
#include <errno.h>
#include <stdarg.h>
#include <gnutls/dtls.h>
@@ -52,19 +54,6 @@
#include <glib/gi18n-lib.h>
#include <glib/gprintf.h>
-static ssize_t g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t transport_data,
- const void *buf,
- size_t buflen);
-static ssize_t g_tls_connection_gnutls_vec_push_func (gnutls_transport_ptr_t transport_data,
- const giovec_t *iov,
- int iovcnt);
-static ssize_t g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t transport_data,
- void *buf,
- size_t buflen);
-
-static int g_tls_connection_gnutls_pull_timeout_func (gnutls_transport_ptr_t transport_data,
- unsigned int ms);
-
static GInitableIface *g_tls_connection_gnutls_parent_initable_iface;
static void g_tls_connection_gnutls_initable_iface_init (GInitableIface *iface);
@@ -75,7 +64,6 @@ static gnutls_priority_t priority;
typedef struct
{
- gnutls_certificate_credentials_t creds;
gnutls_session_t session; /* FIXME: should be used only by GTlsOperationsThreadGnutls */
gchar *interaction_id;
GCancellable *cancellable;
@@ -121,65 +109,14 @@ g_tls_connection_gnutls_initable_init (GInitable *initable,
{
GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (initable);
GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- GIOStream *base_io_stream = NULL;
- GDatagramBased *base_socket = NULL;
- gboolean client = G_IS_TLS_CLIENT_CONNECTION (gnutls);
- guint flags = client ? GNUTLS_CLIENT : GNUTLS_SERVER;
- int status;
- int ret;
- g_object_get (gnutls,
- "base-io-stream", &base_io_stream,
- "base-socket", &base_socket,
- NULL);
-
- /* Ensure we are in TLS mode or DTLS mode. */
- g_return_val_if_fail (!!base_io_stream != !!base_socket, FALSE);
-
- if (base_socket)
- flags |= GNUTLS_DATAGRAM;
-
- ret = gnutls_certificate_allocate_credentials (&priv->creds);
- if (ret != GNUTLS_E_SUCCESS)
+ if (!g_tls_connection_gnutls_parent_initable_iface->init (initable, cancellable, error))
return FALSE;
- gnutls_init (&priv->session, flags);
-
- gnutls_session_set_ptr (priv->session, gnutls);
- gnutls_session_set_verify_function (priv->session, verify_certificate_cb);
-
- status = gnutls_credentials_set (priv->session,
- GNUTLS_CRD_CERTIFICATE,
- priv->creds);
- if (status != 0)
- {
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
- _("Could not create TLS connection: %s"),
- gnutls_strerror (status));
- return FALSE;
- }
-
- gnutls_transport_set_push_function (priv->session,
- g_tls_connection_gnutls_push_func);
- gnutls_transport_set_pull_function (priv->session,
- g_tls_connection_gnutls_pull_func);
- /* FIXME: remove timeout func and switch to GNUTLS_NONBLOCK */
- gnutls_transport_set_pull_timeout_function (priv->session,
- g_tls_connection_gnutls_pull_timeout_func);
- gnutls_transport_set_ptr (priv->session, gnutls);
-
- /* GDatagramBased supports vectored I/O; GPollableOutputStream does not. */
- if (base_socket)
- {
- gnutls_transport_set_vec_push_function (priv->session,
- g_tls_connection_gnutls_vec_push_func);
- }
-
- /* Set reasonable MTU */
- if (flags & GNUTLS_DATAGRAM)
- gnutls_dtls_set_mtu (priv->session, 1400);
+ /* FIXME bad */
+ priv->session = g_tls_operations_thread_gnutls_get_session (G_TLS_OPERATIONS_THREAD_GNUTLS
(g_tls_connection_base_get_op_thread (G_TLS_CONNECTION_BASE (gnutls))));
- return g_tls_connection_gnutls_parent_initable_iface->init (initable, cancellable, error);
+ return TRUE;
}
static void
@@ -188,11 +125,6 @@ g_tls_connection_gnutls_finalize (GObject *object)
GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (object);
GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- if (priv->session)
- gnutls_deinit (priv->session);
- if (priv->creds)
- gnutls_certificate_free_credentials (priv->creds);
-
if (priv->cancellable)
{
g_cancellable_cancel (priv->cancellable);
@@ -209,15 +141,7 @@ g_tls_connection_gnutls_get_credentials (GTlsConnectionGnutls *gnutls)
{
GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- return priv->creds;
-}
-
-gnutls_session_t
-g_tls_connection_gnutls_get_session (GTlsConnectionGnutls *gnutls)
-{
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
-
- return priv->session;
+ return priv->creds; /* FIXME: get via op thread? */
}
static int
@@ -316,489 +240,35 @@ g_tls_connection_gnutls_handshake_thread_get_certificate (GTlsConnectionGnutls
}
}
-// FIXME: remove
-static GTlsConnectionBaseStatus
-end_gnutls_io (GTlsConnectionGnutls *gnutls,
- GIOCondition direction,
- int ret,
- GError **error,
- const char *err_prefix)
-{
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (gnutls);
- GTlsConnectionBaseStatus status;
- gboolean handshaking;
- gboolean ever_handshaked;
- GError *my_error = NULL;
-
- /* We intentionally do not check for GNUTLS_E_INTERRUPTED here
- * Instead, the caller may poll for the source to become ready again.
- * (Note that GTlsOutputStreamGnutls and GTlsInputStreamGnutls inherit
- * from GPollableOutputStream and GPollableInputStream, respectively.)
- * See also the comment in set_gnutls_error().
- */
- if (ret == GNUTLS_E_AGAIN ||
- ret == GNUTLS_E_WARNING_ALERT_RECEIVED)
- return G_TLS_CONNECTION_BASE_TRY_AGAIN;
-
- status = g_tls_connection_base_pop_io (tls, direction, ret >= 0, &my_error);
- 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;
- }
-
- g_assert (status == G_TLS_CONNECTION_BASE_ERROR);
-
- handshaking = g_tls_connection_base_is_handshaking (tls);
- ever_handshaked = g_tls_connection_base_ever_handshaked (tls);
-
- if (handshaking && !ever_handshaked)
- {
- if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
- g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE))
- {
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
- _("Peer failed to perform TLS handshake: %s"), my_error->message);
- g_clear_error (&my_error);
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH ||
- status == GNUTLS_E_DECRYPTION_FAILED ||
- status == GNUTLS_E_UNSUPPORTED_VERSION_PACKET)
- {
- g_clear_error (&my_error);
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
- _("Peer failed to perform TLS handshake: %s"), gnutls_strerror (ret));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
- }
-
- if (ret == GNUTLS_E_REHANDSHAKE)
- return G_TLS_CONNECTION_BASE_REHANDSHAKE;
-
- if (ret == GNUTLS_E_PREMATURE_TERMINATION)
- {
- if (handshaking && !ever_handshaked)
- {
- g_clear_error (&my_error);
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
- _("Peer failed to perform TLS handshake: %s"), gnutls_strerror (ret));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (g_tls_connection_get_require_close_notify (G_TLS_CONNECTION (gnutls)))
- {
- g_clear_error (&my_error);
- g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_EOF,
- _("TLS connection closed unexpectedly"));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- return G_TLS_CONNECTION_BASE_OK;
- }
-
- if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND
-#ifdef GNUTLS_E_CERTIFICATE_REQUIRED
- || ret == GNUTLS_E_CERTIFICATE_REQUIRED /* Added in GnuTLS 3.6.7 */
-#endif
- )
- {
- 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 G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (ret == GNUTLS_E_CERTIFICATE_ERROR)
- {
- g_clear_error (&my_error);
- g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Unacceptable TLS certificate"));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (ret == GNUTLS_E_FATAL_ALERT_RECEIVED)
- {
- g_clear_error (&my_error);
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
- _("Peer sent fatal TLS alert: %s"),
- gnutls_alert_get_name (gnutls_alert_get (priv->session)));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (ret == GNUTLS_E_INAPPROPRIATE_FALLBACK)
- {
- g_clear_error (&my_error);
- g_set_error_literal (error, G_TLS_ERROR,
- G_TLS_ERROR_INAPPROPRIATE_FALLBACK,
- _("Protocol version downgrade attack detected"));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (ret == GNUTLS_E_LARGE_PACKET)
- {
- guint mtu = gnutls_dtls_get_data_mtu (priv->session);
- g_clear_error (&my_error);
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_MESSAGE_TOO_LARGE,
- ngettext ("Message is too large for DTLS connection; maximum is %u byte",
- "Message is too large for DTLS connection; maximum is %u bytes", mtu), mtu);
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (ret == GNUTLS_E_TIMEDOUT)
- {
- g_clear_error (&my_error);
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
- _("The operation timed out"));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (error && my_error)
- g_propagate_error (error, my_error);
-
- if (error && !*error)
- {
- *error = g_error_new (G_TLS_ERROR, G_TLS_ERROR_MISC, "%s: %s",
- err_prefix, gnutls_strerror (ret));
- }
-
- return G_TLS_CONNECTION_BASE_ERROR;
-}
-
-// FIXME: remove
-
-#define BEGIN_GNUTLS_IO(gnutls, direction, timeout, cancellable) \
- g_tls_connection_base_push_io (G_TLS_CONNECTION_BASE (gnutls), \
- direction, timeout, cancellable); \
- do {
-
-#define END_GNUTLS_IO(gnutls, direction, ret, status, errmsg, err) \
- status = end_gnutls_io (gnutls, direction, ret, err, errmsg); \
- } while (status == G_TLS_CONNECTION_BASE_TRY_AGAIN);
-
-static void
-set_gnutls_error (GTlsConnectionGnutls *gnutls,
- GError *error)
-{
- GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (gnutls);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
-
- /* We set EINTR rather than EAGAIN for G_IO_ERROR_WOULD_BLOCK so
- * that GNUTLS_E_AGAIN only gets returned for gnutls-internal
- * reasons, not for actual socket EAGAINs (and we have access
- * to @error at the higher levels, so we can distinguish them
- * that way later).
- */
-
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- gnutls_transport_set_errno (priv->session, EINTR);
- else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
- {
- /* Return EAGAIN while handshaking so that GnuTLS handles retries for us
- * internally in its handshaking code. */
- if (g_tls_connection_base_is_dtls (tls) && g_tls_connection_base_is_handshaking (tls))
- gnutls_transport_set_errno (priv->session, EAGAIN);
- else
- gnutls_transport_set_errno (priv->session, EINTR);
- }
- else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT))
- gnutls_transport_set_errno (priv->session, EINTR);
- else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_MESSAGE_TOO_LARGE))
- gnutls_transport_set_errno (priv->session, EMSGSIZE);
- else
- gnutls_transport_set_errno (priv->session, EIO);
-}
-
-/* FIXME: remove timeouts, make these always nonblocking */
-
-static ssize_t
-g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t transport_data,
- void *buf,
- size_t buflen)
-{
- GTlsConnectionBase *tls = transport_data;
- GTlsConnectionGnutls *gnutls = transport_data;
- ssize_t ret;
-
- /* If read_error is nonnull when we're called, it means
- * that an error previously occurred, but GnuTLS decided not to
- * propagate it. So it's correct for us to just clear it. (Usually
- * this means it ignored an EAGAIN after a short read, and now
- * we'll return EAGAIN again, which it will obey this time.)
- */
- g_clear_error (g_tls_connection_base_get_read_error (tls));
-
- if (g_tls_connection_base_is_dtls (tls))
- {
- GInputVector vector = { buf, buflen };
- GInputMessage message = { NULL, &vector, 1, 0, 0, NULL, NULL };
-
- ret = g_datagram_based_receive_messages (g_tls_connection_base_get_base_socket (tls),
- &message, 1, 0,
- g_tls_connection_base_is_handshaking (tls) ? 0 :
g_tls_connection_base_get_read_timeout (tls),
- g_tls_connection_base_get_read_cancellable (tls),
- g_tls_connection_base_get_read_error (tls));
-
- if (ret > 0)
- ret = message.bytes_received;
- }
- else
- {
- ret = g_pollable_stream_read (G_INPUT_STREAM (g_tls_connection_base_get_base_istream (tls)),
- buf, buflen,
- g_tls_connection_base_get_read_timeout (tls) != 0,
- g_tls_connection_base_get_read_cancellable (tls),
- g_tls_connection_base_get_read_error (tls));
- }
-
- if (ret < 0)
- set_gnutls_error (gnutls, *g_tls_connection_base_get_read_error (tls));
-
- return ret;
-}
-
-static ssize_t
-g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t transport_data,
- const void *buf,
- size_t buflen)
-{
- GTlsConnectionBase *tls = transport_data;
- GTlsConnectionGnutls *gnutls = transport_data;
- ssize_t ret;
-
- /* See comment in pull_func. */
- g_clear_error (g_tls_connection_base_get_write_error (tls));
-
- if (g_tls_connection_base_is_dtls (tls))
- {
- GOutputVector vector = { buf, buflen };
- GOutputMessage message = { NULL, &vector, 1, 0, NULL, 0 };
-
- ret = g_datagram_based_send_messages (g_tls_connection_base_get_base_socket (tls),
- &message, 1, 0,
- g_tls_connection_base_get_write_timeout (tls),
- g_tls_connection_base_get_write_cancellable (tls),
- g_tls_connection_base_get_write_error (tls));
-
- if (ret > 0)
- ret = message.bytes_sent;
- }
- else
- {
- ret = g_pollable_stream_write (G_OUTPUT_STREAM (g_tls_connection_base_get_base_ostream (tls)),
- buf, buflen,
- g_tls_connection_base_get_write_timeout (tls) != 0,
- g_tls_connection_base_get_write_cancellable (tls),
- g_tls_connection_base_get_write_error (tls));
- }
-
- if (ret < 0)
- set_gnutls_error (gnutls, *g_tls_connection_base_get_write_error (tls));
-
- return ret;
-}
-
-static ssize_t
-g_tls_connection_gnutls_vec_push_func (gnutls_transport_ptr_t transport_data,
- const giovec_t *iov,
- int iovcnt)
-{
- GTlsConnectionBase *tls = transport_data;
- GTlsConnectionGnutls *gnutls = transport_data;
- ssize_t ret;
- GOutputMessage message = { NULL, };
- GOutputVector *vectors;
-
- g_assert (g_tls_connection_base_is_dtls (tls));
-
- /* See comment in pull_func. */
- g_clear_error (g_tls_connection_base_get_write_error (tls));
-
- /* this entire expression will be evaluated at compile time */
- if (sizeof *iov == sizeof *vectors &&
- sizeof iov->iov_base == sizeof vectors->buffer &&
- G_STRUCT_OFFSET (giovec_t, iov_base) ==
- G_STRUCT_OFFSET (GOutputVector, buffer) &&
- sizeof iov->iov_len == sizeof vectors->size &&
- G_STRUCT_OFFSET (giovec_t, iov_len) ==
- G_STRUCT_OFFSET (GOutputVector, size))
- /* ABI is compatible */
- {
- message.vectors = (GOutputVector *)iov;
- message.num_vectors = iovcnt;
- }
- else
- /* ABI is incompatible */
- {
- gint i;
-
- message.vectors = g_newa (GOutputVector, iovcnt);
- for (i = 0; i < iovcnt; i++)
- {
- message.vectors[i].buffer = (void *)iov[i].iov_base;
- message.vectors[i].size = iov[i].iov_len;
- }
- message.num_vectors = iovcnt;
- }
-
- ret = g_datagram_based_send_messages (g_tls_connection_base_get_base_socket (tls),
- &message, 1, 0,
- g_tls_connection_base_get_write_timeout (tls),
- g_tls_connection_base_get_write_cancellable (tls),
- g_tls_connection_base_get_write_error (tls));
-
- if (ret > 0)
- ret = message.bytes_sent;
- else if (ret < 0)
- set_gnutls_error (gnutls, *g_tls_connection_base_get_write_error (tls));
-
- return ret;
-}
-
-static gboolean
-read_pollable_cb (GPollableInputStream *istream,
- gpointer user_data)
-{
- gboolean *read_done = user_data;
-
- *read_done = TRUE;
-
- return G_SOURCE_CONTINUE;
-}
-
-static gboolean
-read_datagram_based_cb (GDatagramBased *datagram_based,
- GIOCondition condition,
- gpointer user_data)
-{
- gboolean *read_done = user_data;
-
- *read_done = TRUE;
-
- return G_SOURCE_CONTINUE;
-}
-
-static gboolean
-read_timeout_cb (gpointer user_data)
-{
- gboolean *timed_out = user_data;
-
- *timed_out = TRUE;
-
- return G_SOURCE_REMOVE;
-}
-
-static int
-g_tls_connection_gnutls_pull_timeout_func (gnutls_transport_ptr_t transport_data,
- unsigned int ms)
-{
- GTlsConnectionBase *tls = transport_data;
-
- /* Fast path. */
- if (g_tls_connection_base_base_check (tls, G_IO_IN) ||
- g_cancellable_is_cancelled (g_tls_connection_base_get_read_cancellable (tls)))
- return 1;
-
- /* If @ms is 0, GnuTLS wants an instant response, so there’s no need to
- * construct and query a #GSource. */
- if (ms > 0)
- {
- GMainContext *ctx = NULL;
- GSource *read_source = NULL, *timeout_source = NULL;
- gboolean read_done = FALSE, timed_out = FALSE;
-
- ctx = g_main_context_new ();
-
- /* Create a timeout source. */
- timeout_source = g_timeout_source_new (ms);
- g_source_set_callback (timeout_source, (GSourceFunc)read_timeout_cb,
- &timed_out, NULL);
-
- /* Create a read source. We cannot use g_source_set_ready_time() on this
- * to combine it with the @timeout_source, as that could mess with the
- * internals of the #GDatagramBased’s #GSource implementation. */
- if (g_tls_connection_base_is_dtls (tls))
- {
- read_source = g_datagram_based_create_source (g_tls_connection_base_get_base_socket (tls),
- G_IO_IN, NULL);
- g_source_set_callback (read_source, (GSourceFunc)read_datagram_based_cb,
- &read_done, NULL);
- }
- else
- {
- read_source = g_pollable_input_stream_create_source (g_tls_connection_base_get_base_istream (tls),
- NULL);
- g_source_set_callback (read_source, (GSourceFunc)read_pollable_cb,
- &read_done, NULL);
- }
-
- g_source_attach (read_source, ctx);
- g_source_attach (timeout_source, ctx);
-
- while (!read_done && !timed_out)
- g_main_context_iteration (ctx, TRUE);
-
- g_source_destroy (read_source);
- g_source_destroy (timeout_source);
-
- g_main_context_unref (ctx);
- g_source_unref (read_source);
- g_source_unref (timeout_source);
-
- /* If @read_source was dispatched due to cancellation, the resulting error
- * will be handled in g_tls_connection_gnutls_pull_func(). */
- if (g_tls_connection_base_base_check (tls, G_IO_IN) ||
- g_cancellable_is_cancelled (g_tls_connection_base_get_read_cancellable (tls)))
- return 1;
- }
-
- return 0;
-}
-
static GTlsOperationsThreadBase *
g_tls_connection_gnutls_create_op_thread (GTlsConnectionBase *tls)
{
- return g_tls_operations_thread_gnutls_new (G_TLS_CONNECTION_GNUTLS (tls));
-}
+ GIOStream *base_io_stream = NULL;
+ GDatagramBased *base_socket = NULL;
+ gboolean client = G_IS_TLS_CLIENT_CONNECTION (tls);
+ guint flags = client ? GNUTLS_CLIENT : GNUTLS_SERVER;
+ GTlsOperationsThreadGnutls *thread;
-static GTlsSafeRenegotiationStatus
-g_tls_connection_gnutls_handshake_thread_safe_renegotiation_status (GTlsConnectionBase *tls)
-{
- GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (tls);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
+ g_object_get (tls,
+ "base-io-stream", &base_io_stream,
+ "base-socket", &base_socket,
+ NULL);
- return gnutls_safe_renegotiation_status (priv->session) ? G_TLS_SAFE_RENEGOTIATION_SUPPORTED_BY_PEER
- : G_TLS_SAFE_RENEGOTIATION_UNSUPPORTED;
-}
+ /* Ensure we are in TLS mode or DTLS mode. */
+ g_return_val_if_fail (!!base_io_stream != !!base_socket, FALSE);
-static GTlsConnectionBaseStatus
-g_tls_connection_gnutls_handshake_thread_request_rehandshake (GTlsConnectionBase *tls,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (tls);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- GTlsConnectionBaseStatus status;
- int ret;
+ if (base_socket)
+ flags |= GNUTLS_DATAGRAM;
- /* On a client-side connection, gnutls_handshake() 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;
+ thread = g_tls_operations_thread_gnutls_new (G_TLS_CONNECTION_GNUTLS (tls),
+ base_io_stream,
+ base_socket,
+ flags);
- BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, timeout, cancellable);
- ret = gnutls_rehandshake (priv->session);
- END_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, ret, status, _("Error performing TLS handshake: %s"), error);
+ g_clear_object (&base_io_stream);
+ g_clear_object (&base_socket);
- return status;
+ return thread;
}
static GTlsCertificate *
@@ -834,76 +304,6 @@ verify_certificate_cb (gnutls_session_t session)
return !g_tls_connection_base_handshake_thread_verify_certificate (tls);
}
-static void
-g_tls_connection_gnutls_prepare_handshake (GTlsConnectionBase *tls,
- gchar **advertised_protocols)
-{
- GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (tls);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
-
- if (advertised_protocols)
- {
- gnutls_datum_t *protocols;
- int n_protos, i;
-
- n_protos = g_strv_length (advertised_protocols);
- protocols = g_new (gnutls_datum_t, n_protos);
- for (i = 0; advertised_protocols[i]; i++)
- {
- protocols[i].size = strlen (advertised_protocols[i]);
- protocols[i].data = (guchar *)advertised_protocols[i];
- }
- gnutls_alpn_set_protocols (priv->session, protocols, n_protos, 0);
- g_free (protocols);
- }
-}
-
-static GTlsConnectionBaseStatus
-g_tls_connection_gnutls_handshake_thread_handshake (GTlsConnectionBase *tls,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (tls);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- GTlsConnectionBaseStatus status;
- int ret;
-
- if (!g_tls_connection_base_ever_handshaked (tls))
- g_tls_connection_gnutls_set_handshake_priority (gnutls);
-
- if (timeout > 0)
- {
- unsigned int timeout_ms;
-
- /* Convert from microseconds to milliseconds, but ensure the timeout
- * remains positive. */
- timeout_ms = (timeout + 999) / 1000;
-
- gnutls_handshake_set_timeout (priv->session, timeout_ms);
- gnutls_dtls_set_timeouts (priv->session, 1000 /* default */, timeout_ms);
- }
-
- BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, timeout, cancellable);
- ret = gnutls_handshake (priv->session);
- if (ret == GNUTLS_E_GOT_APPLICATION_DATA)
- {
- guint8 buf[1024];
-
- /* Got app data while waiting for rehandshake; buffer it and try again */
- ret = gnutls_record_recv (priv->session, buf, sizeof (buf));
- if (ret > -1)
- {
- g_tls_connection_base_handshake_thread_buffer_application_data (tls, buf, ret);
- ret = GNUTLS_E_AGAIN;
- }
- }
- END_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, ret, status,
- _("Error performing TLS handshake"), error);
-
- return status;
-}
-
static void
g_tls_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
gchar **negotiated_protocol,
@@ -961,10 +361,7 @@ g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
gobject_class->finalize = g_tls_connection_gnutls_finalize;
base_class->create_op_thread = g_tls_connection_gnutls_create_op_thread;
- base_class->prepare_handshake = g_tls_connection_gnutls_prepare_handshake;
base_class->handshake_thread_safe_renegotiation_status =
g_tls_connection_gnutls_handshake_thread_safe_renegotiation_status;
- base_class->handshake_thread_request_rehandshake =
g_tls_connection_gnutls_handshake_thread_request_rehandshake;
- base_class->handshake_thread_handshake =
g_tls_connection_gnutls_handshake_thread_handshake;
base_class->retrieve_peer_certificate = g_tls_connection_gnutls_retrieve_peer_certificate;
base_class->complete_handshake = g_tls_connection_gnutls_complete_handshake;
base_class->is_session_resumed = g_tls_connection_gnutls_is_session_resumed;
diff --git a/tls/gnutls/gtlsconnection-gnutls.h b/tls/gnutls/gtlsconnection-gnutls.h
index 3e9fa9b..edb617f 100644
--- a/tls/gnutls/gtlsconnection-gnutls.h
+++ b/tls/gnutls/gtlsconnection-gnutls.h
@@ -43,9 +43,6 @@ struct _GTlsConnectionGnutlsClass
gnutls_certificate_credentials_t g_tls_connection_gnutls_get_credentials (GTlsConnectionGnutls *connection);
-/* FIXME: remove to ensure threadsafety */
-gnutls_session_t g_tls_connection_gnutls_get_session (GTlsConnectionGnutls *connection);
-
void g_tls_connection_gnutls_handshake_thread_get_certificate (GTlsConnectionGnutls *gnutls,
gnutls_pcert_st **pcert,
unsigned int *pcert_length,
diff --git a/tls/gnutls/gtlsoperationsthread-gnutls.c b/tls/gnutls/gtlsoperationsthread-gnutls.c
index 11b1bc9..c6559d6 100644
--- a/tls/gnutls/gtlsoperationsthread-gnutls.c
+++ b/tls/gnutls/gtlsoperationsthread-gnutls.c
@@ -30,19 +30,52 @@
#include "gtlsconnection-gnutls.h"
+#include <errno.h>
#include <glib/gi18n-lib.h>
#include <gnutls/dtls.h>
+#include <limits.h>
struct _GTlsOperationsThreadGnutls {
GTlsOperationsThreadBase parent_instance;
+ guint init_flags;
+ gnutls_certificate_credentials_t creds; /* owned by GTlsConnectionGnutls */
+
gnutls_session_t session;
+
+ GIOStream *base_iostream;
+ GInputStream *base_istream;
+ GOutputStream *base_ostream;
+ GDatagramBased *base_socket;
+
+ gboolean handshaking;
+ gboolean ever_handshaked;
+
+ GCancellable *op_cancellable;
+ GError *op_error;
+};
+
+enum
+{
+ PROP_0,
+ PROP_BASE_IO_STREAM,
+ PROP_BASE_SOCKET,
+ PROP_GNUTLS_FLAGS,
+ LAST_PROP
};
+static GParamSpec *obj_properties[LAST_PROP];
+
static gnutls_priority_t priority;
G_DEFINE_TYPE (GTlsOperationsThreadGnutls, g_tls_operations_thread_gnutls, G_TYPE_TLS_OPERATIONS_THREAD_BASE)
+static inline gboolean
+is_dtls (GTlsOperationsThreadGnutls *self)
+{
+ return self->init_flags & GNUTLS_DATAGRAM;
+}
+
static GTlsConnectionBaseStatus
end_gnutls_io (GTlsOperationsThreadGnutls *self,
GIOCondition direction,
@@ -52,8 +85,6 @@ end_gnutls_io (GTlsOperationsThreadGnutls *self,
{
GTlsConnectionBase *tls;
GTlsConnectionBaseStatus status;
- gboolean handshaking;
- gboolean ever_handshaked;
GError *my_error = NULL;
/* We intentionally do not check for GNUTLS_E_INTERRUPTED here
@@ -80,10 +111,7 @@ end_gnutls_io (GTlsOperationsThreadGnutls *self,
g_assert (status == G_TLS_CONNECTION_BASE_ERROR);
- handshaking = g_tls_connection_base_is_handshaking (tls);
- ever_handshaked = g_tls_connection_base_ever_handshaked (tls);
-
- if (handshaking && !ever_handshaked)
+ if (self->handshaking && !self->ever_handshaked)
{
if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE))
@@ -110,7 +138,7 @@ end_gnutls_io (GTlsOperationsThreadGnutls *self,
if (ret == GNUTLS_E_PREMATURE_TERMINATION)
{
- if (handshaking && !ever_handshaked)
+ if (self->handshaking && !self->ever_handshaked)
{
g_clear_error (&my_error);
g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
@@ -193,14 +221,24 @@ end_gnutls_io (GTlsOperationsThreadGnutls *self,
return G_TLS_CONNECTION_BASE_ERROR;
}
+/* FIXME: do not use GTlsConnectionBase at all. */
+
#define BEGIN_GNUTLS_IO(self, direction, cancellable) \
+ g_assert (!self->op_error); \
+ g_assert (!self->op_cancellable); \
+ self->op_cancellable = cancellable; \
g_tls_connection_base_push_io (g_tls_operations_thread_base_get_connection (G_TLS_OPERATIONS_THREAD_BASE
(self)), \
- direction, 0, cancellable); \
+ direction, 0, cancellable); \
do {
#define END_GNUTLS_IO(self, direction, ret, status, errmsg, err) \
status = end_gnutls_io (self, direction, ret, err, errmsg); \
- } while (status == G_TLS_CONNECTION_BASE_TRY_AGAIN);
+ } while (status == G_TLS_CONNECTION_BASE_TRY_AGAIN); \
+ self->op_cancellable = NULL; \
+ if (self->op_error) { \
+ g_propagate_error (err, self->op_error); \
+ self->op_error = NULL; \
+ }
static void
initialize_gnutls_priority (void)
@@ -237,11 +275,91 @@ set_handshake_priority (GTlsOperationsThreadGnutls *self)
g_warning ("Failed to set GnuTLS session priority: %s", gnutls_strerror (ret));
}
+static void
+compute_session_id (GTlsOperationsThreadGnutls *self)
+{
+ GSocketAddress *remote_addr;
+ GInetAddress *iaddr;
+ guint port;
+
+ /* The testsuite expects handshakes to actually happen. E.g. a test might
+ * check to see that a handshake succeeds and then later check that a new
+ * handshake fails. If we get really unlucky and the same port number is
+ * reused for the server socket between connections, then we'll accidentally
+ * resume the old session and skip certificate verification. Such failures
+ * are difficult to debug because they require running the tests hundreds of
+ * times simultaneously to reproduce (the port number does not get reused
+ * quickly enough if the tests are run sequentially).
+ *
+ * So session resumption will just need to be tested manually.
+ */
+ if (g_test_initialized ())
+ return;
+
+ /* 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)
+ *
+ * Note that our session IDs have no relation to TLS protocol
+ * session IDs, e.g. as provided by gnutls_session_get_id2(). Unlike
+ * our session IDs, actual TLS session IDs can no longer be used for
+ * session resumption.
+ */
+ if (G_IS_SOCKET_CONNECTION (self->base_iostream))
+ {
+ remote_addr = g_socket_connection_get_remote_address (G_SOCKET_CONNECTION (self->base_iostream), 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;
+ GTlsCertificate *cert = NULL;
+ gchar *cert_hash = NULL;
+
+ 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 (gnutls);
+
+ /* If we have a certificate, make its hash part of the session ID, so
+ * that different connections to the same server can use different
+ * certificates.
+ */
+ g_object_get (G_OBJECT (gnutls), "certificate", &cert, NULL);
+ if (cert)
+ {
+ GByteArray *der = NULL;
+ g_object_get (G_OBJECT (cert), "certificate", &der, NULL);
+ if (der)
+ {
+ cert_hash = g_compute_checksum_for_data (G_CHECKSUM_SHA256, der->data, der->len);
+ g_byte_array_unref (der);
+ }
+ g_object_unref (cert);
+ }
+ session_id = g_strdup_printf ("%s/%s/%d/%s", addrstr,
+ server_hostname ? server_hostname : "",
+ port,
+ cert_hash ? cert_hash : "");
+ gnutls->session_id = g_bytes_new_take (session_id, strlen (session_id));
+ g_free (addrstr);
+ g_free (cert_hash);
+ }
+ g_object_unref (remote_addr);
+ }
+ g_clear_object (&base_conn);
+}
+
static GTlsConnectionBaseStatus
-g_tls_operations_thread_gnutls_handshake (GTlsOperationsThreadBase *base,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error)
+g_tls_operations_thread_gnutls_handshake (GTlsOperationsThreadBase *base,
+ gchar **advertised_protocols,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error)
{
GTlsOperationsThreadGnutls *self = G_TLS_OPERATIONS_THREAD_GNUTLS (base);
GTlsConnectionBase *tls;
@@ -250,7 +368,7 @@ g_tls_operations_thread_gnutls_handshake (GTlsOperationsThreadBase *base,
tls = g_tls_operations_thread_base_get_connection (base);
- if (!g_tls_connection_base_ever_handshaked (tls))
+ if (!self->ever_handshaked)
set_handshake_priority (self);
if (timeout > 0)
@@ -258,13 +376,32 @@ g_tls_operations_thread_gnutls_handshake (GTlsOperationsThreadBase *base,
unsigned int timeout_ms;
/* Convert from microseconds to milliseconds, but ensure the timeout
- * remains positive. */
+ * remains positive.
+ */
timeout_ms = (timeout + 999) / 1000;
gnutls_handshake_set_timeout (self->session, timeout_ms);
gnutls_dtls_set_timeouts (self->session, 1000 /* default */, timeout_ms);
}
+ if (advertised_protocols)
+ {
+ gnutls_datum_t *protocols;
+ int n_protos, i;
+
+ n_protos = g_strv_length (advertised_protocols);
+ protocols = g_new (gnutls_datum_t, n_protos);
+ for (i = 0; advertised_protocols[i]; i++)
+ {
+ protocols[i].size = strlen (advertised_protocols[i]);
+ protocols[i].data = (guchar *)advertised_protocols[i];
+ }
+ gnutls_alpn_set_protocols (self->session, protocols, n_protos, 0);
+ g_free (protocols);
+ }
+
+ self->handshaking = TRUE;
+
BEGIN_GNUTLS_IO (self, G_IO_IN | G_IO_OUT, cancellable);
ret = gnutls_handshake (self->session);
if (ret == GNUTLS_E_GOT_APPLICATION_DATA)
@@ -275,7 +412,7 @@ g_tls_operations_thread_gnutls_handshake (GTlsOperationsThreadBase *base,
ret = gnutls_record_recv (self->session, buf, sizeof (buf));
if (ret > -1)
{
- /* FIXME: no longer belongs in GTlsConnectionBase? */
+ /* FIXME: no longer belongs in GTlsConnectionBase, don't use GTlsConnectionBase */
g_tls_connection_base_handshake_thread_buffer_application_data (tls, buf, ret);
ret = GNUTLS_E_AGAIN;
}
@@ -283,6 +420,9 @@ g_tls_operations_thread_gnutls_handshake (GTlsOperationsThreadBase *base,
END_GNUTLS_IO (self, G_IO_IN | G_IO_OUT, ret, status,
_("Error performing TLS handshake"), error);
+ self->handshaking = FALSE;
+ self->ever_handshaked = TRUE;
+
return status;
}
@@ -465,16 +605,402 @@ g_tls_operations_thread_gnutls_close (GTlsOperationsThreadBase *base,
return status;
}
+static void
+set_gnutls_error (GTlsOperationsThreadGnutls *self,
+ GError *error)
+{
+ /* We set EINTR rather than EAGAIN for G_IO_ERROR_WOULD_BLOCK so
+ * that GNUTLS_E_AGAIN only gets returned for gnutls-internal
+ * reasons, not for actual socket EAGAINs (and we have access
+ * to @error at the higher levels, so we can distinguish them
+ * that way later).
+ */
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ gnutls_transport_set_errno (self->session, EINTR);
+ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+ {
+ /* Return EAGAIN while handshaking so that GnuTLS handles retries for us
+ * internally in its handshaking code.
+ */
+ if (is_dtls (self) && self->handshaking)
+ gnutls_transport_set_errno (self->session, EAGAIN);
+ else
+ gnutls_transport_set_errno (self->session, EINTR);
+ }
+ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT))
+ gnutls_transport_set_errno (self->session, EINTR);
+ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_MESSAGE_TOO_LARGE))
+ gnutls_transport_set_errno (self->session, EMSGSIZE);
+ else
+ gnutls_transport_set_errno (self->session, EIO);
+}
+
+static ssize_t
+g_tls_operations_thread_gnutls_pull_func (gnutls_transport_ptr_t transport_data,
+ void *buf,
+ size_t buflen)
+{
+ GTlsOperationsThreadGnutls *self = transport_data;
+ ssize_t ret;
+
+ /* If op_error is nonnull when we're called, it means
+ * that an error previously occurred, but GnuTLS decided not to
+ * propagate it. So it's correct for us to just clear it. (Usually
+ * this means it ignored an EAGAIN after a short read, and now
+ * we'll return EAGAIN again, which it will obey this time.)
+ */
+ g_clear_error (&self->op_error);
+
+ if (is_dtls (self))
+ {
+ GInputVector vector = { buf, buflen };
+ GInputMessage message = { NULL, &vector, 1, 0, 0, NULL, NULL };
+
+ ret = g_datagram_based_receive_messages (self->base_socket,
+ &message, 1,
+ 0, 0,
+ self->op_cancellable,
+ &self->op_error);
+
+ if (ret > 0)
+ ret = message.bytes_received;
+ }
+ else
+ {
+ ret = g_pollable_stream_read (self->base_istream,
+ buf, buflen,
+ FALSE,
+ self->op_cancellable,
+ &self->op_error);
+ }
+
+ if (ret < 0)
+ set_gnutls_error (self, self->op_error);
+
+ return ret;
+}
+
+static ssize_t
+g_tls_operations_thread_gnutls_push_func (gnutls_transport_ptr_t transport_data,
+ const void *buf,
+ size_t buflen)
+{
+ GTlsOperationsThreadGnutls *self = transport_data;
+ ssize_t ret;
+
+ /* See comment in pull_func. */
+ g_clear_error (&self->op_error);
+
+ if (is_dtls (self))
+ {
+ GOutputVector vector = { buf, buflen };
+ GOutputMessage message = { NULL, &vector, 1, 0, NULL, 0 };
+
+ ret = g_datagram_based_send_messages (self->base_socket,
+ &message, 1,
+ 0, 0,
+ self->op_cancellable,
+ &self->op_error);
+
+ if (ret > 0)
+ ret = message.bytes_sent;
+ }
+ else
+ {
+ ret = g_pollable_stream_write (self->base_ostream,
+ buf, buflen,
+ FALSE,
+ self->op_cancellable,
+ &self->op_error);
+ }
+
+ if (ret < 0)
+ set_gnutls_error (self, self->op_error);
+
+ return ret;
+}
+
+static ssize_t
+g_tls_operations_thread_gnutls_vec_push_func (gnutls_transport_ptr_t transport_data,
+ const giovec_t *iov,
+ int iovcnt)
+{
+ GTlsOperationsThreadGnutls *self = transport_data;
+ ssize_t ret;
+ GOutputMessage message = { NULL, };
+ GOutputVector *vectors;
+
+ g_assert (is_dtls (self));
+
+ /* See comment in pull_func. */
+ g_clear_error (&self->op_error);
+
+ /* this entire expression will be evaluated at compile time */
+ if (sizeof *iov == sizeof *vectors &&
+ sizeof iov->iov_base == sizeof vectors->buffer &&
+ G_STRUCT_OFFSET (giovec_t, iov_base) ==
+ G_STRUCT_OFFSET (GOutputVector, buffer) &&
+ sizeof iov->iov_len == sizeof vectors->size &&
+ G_STRUCT_OFFSET (giovec_t, iov_len) ==
+ G_STRUCT_OFFSET (GOutputVector, size))
+ /* ABI is compatible */
+ {
+ message.vectors = (GOutputVector *)iov;
+ message.num_vectors = iovcnt;
+ }
+ else
+ /* ABI is incompatible */
+ {
+ gint i;
+
+ message.vectors = g_newa (GOutputVector, iovcnt);
+ for (i = 0; i < iovcnt; i++)
+ {
+ message.vectors[i].buffer = (void *)iov[i].iov_base;
+ message.vectors[i].size = iov[i].iov_len;
+ }
+ message.num_vectors = iovcnt;
+ }
+
+ ret = g_datagram_based_send_messages (self->base_socket,
+ &message, 1,
+ 0, 0,
+ self->op_cancellable,
+ &self->op_error);
+
+ if (ret > 0)
+ ret = message.bytes_sent;
+ else if (ret < 0)
+ set_gnutls_error (self, self->op_error);
+
+ return ret;
+}
+
+static gboolean
+read_pollable_cb (GPollableInputStream *istream,
+ gpointer user_data)
+{
+ gboolean *read_done = user_data;
+
+ *read_done = TRUE;
+
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+read_datagram_based_cb (GDatagramBased *datagram_based,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ gboolean *read_done = user_data;
+
+ *read_done = TRUE;
+
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+read_timeout_cb (gpointer user_data)
+{
+ gboolean *timed_out = user_data;
+
+ *timed_out = TRUE;
+
+ return G_SOURCE_REMOVE;
+}
+
+static int /* FIXME: can this be removed? switch to GNUTLS_NONBLOCK, right? */
+g_tls_operations_thread_gnutls_pull_timeout_func (gnutls_transport_ptr_t transport_data,
+ unsigned int ms)
+{
+ GTlsOperationsThreadGnutls *self = transport_data;
+ /* FIXME: don't use GTlsConnection */
+ GTlsConnectionBase *tls = g_tls_operations_thread_base_get_connection (G_TLS_OPERATIONS_THREAD_BASE
(self));
+
+ /* Fast path. */
+ if (g_tls_connection_base_base_check (tls, G_IO_IN) ||
+ g_cancellable_is_cancelled (self->op_cancellable))
+ return 1;
+
+ /* If @ms is 0, GnuTLS wants an instant response, so there’s no need to
+ * construct and query a #GSource. */
+ if (ms > 0)
+ {
+ GMainContext *ctx = NULL;
+ GSource *read_source = NULL, *timeout_source = NULL;
+ gboolean read_done = FALSE, timed_out = FALSE;
+
+ ctx = g_main_context_new ();
+
+ /* Create a timeout source. */
+ timeout_source = g_timeout_source_new (ms);
+ g_source_set_callback (timeout_source, (GSourceFunc)read_timeout_cb,
+ &timed_out, NULL);
+
+ /* Create a read source. We cannot use g_source_set_ready_time() on this
+ * to combine it with the @timeout_source, as that could mess with the
+ * internals of the #GDatagramBased’s #GSource implementation. */
+ if (is_dtls (self))
+ {
+ read_source = g_datagram_based_create_source (self->base_socket,
+ G_IO_IN, NULL);
+ g_source_set_callback (read_source, (GSourceFunc)read_datagram_based_cb,
+ &read_done, NULL);
+ }
+ else
+ {
+ read_source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (self->base_istream),
+ NULL);
+ g_source_set_callback (read_source, (GSourceFunc)read_pollable_cb,
+ &read_done, NULL);
+ }
+
+ g_source_attach (read_source, ctx);
+ g_source_attach (timeout_source, ctx);
+
+ while (!read_done && !timed_out)
+ g_main_context_iteration (ctx, TRUE);
+
+ g_source_destroy (read_source);
+ g_source_destroy (timeout_source);
+
+ g_main_context_unref (ctx);
+ g_source_unref (read_source);
+ g_source_unref (timeout_source);
+
+ /* If @read_source was dispatched due to cancellation, the resulting error
+ * will be handled in g_tls_connection_gnutls_pull_func(). */
+ if (g_tls_connection_base_base_check (tls, G_IO_IN) ||
+ g_cancellable_is_cancelled (self->op_cancellable))
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+g_tls_operations_thread_gnutls_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GTlsOperationsThreadGnutls *self = G_TLS_OPERATIONS_THREAD_GNUTLS (object);
+
+ switch (prop_id)
+ {
+ case PROP_BASE_IO_STREAM:
+ g_value_set_object (value, self->base_iostream);
+ break;
+
+ case PROP_BASE_SOCKET:
+ g_value_set_object (value, self->base_socket);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_tls_operations_thread_gnutls_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GTlsOperationsThreadGnutls *self = G_TLS_OPERATIONS_THREAD_GNUTLS (object);
+
+ switch (prop_id)
+ {
+ case PROP_BASE_IO_STREAM:
+ g_assert (!self->base_socket);
+ self->base_iostream = g_value_get_object (value);
+ self->base_istream = g_io_stream_get_input_stream (self->base_iostream);
+ self->base_ostream = g_io_stream_get_output_stream (self->base_iostream);
+ break;
+
+ case PROP_BASE_SOCKET:
+ g_assert (!self->base_iostream);
+ self->base_socket = g_value_get_object (value);
+ break;
+
+ case PROP_GNUTLS_FLAGS:
+ self->init_flags = g_value_get_uint (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_tls_operations_thread_gnutls_finalize (GObject *object)
+{
+ GTlsOperationsThreadGnutls *self = G_TLS_OPERATIONS_THREAD_GNUTLS (object);
+
+ if (self->session)
+ gnutls_deinit (self->session);
+ if (self->creds)
+ gnutls_certificate_free_credentials (self->creds);
+
+ G_OBJECT_CLASS (g_tls_operations_thread_gnutls_parent_class)->finalize (object);
+}
+
static void
g_tls_operations_thread_gnutls_constructed (GObject *object)
{
GTlsOperationsThreadGnutls *self = G_TLS_OPERATIONS_THREAD_GNUTLS (object);
GTlsConnectionBase *tls;
+ int ret;
G_OBJECT_CLASS (g_tls_operations_thread_gnutls_parent_class)->constructed (object);
tls = g_tls_operations_thread_base_get_connection (G_TLS_OPERATIONS_THREAD_BASE (self));
- self->session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls));
+
+ ret = gnutls_certificate_allocate_credentials (&self->creds);
+ /* FIXME: GInitable? */
+#if 0
+ if (ret != GNUTLS_E_SUCCESS)
+ return FALSE;
+#endif
+
+ gnutls_init (&self->session, self->init_flags);
+
+ gnutls_session_set_ptr (self->session, self);
+ gnutls_session_set_verify_function (self->session, verify_certificate_cb);
+
+ ret = gnutls_credentials_set (self->session,
+ GNUTLS_CRD_CERTIFICATE,
+ self->creds);
+ /* FIXME: GInitable? */
+#if 0
+ if (ret != 0)
+ {
+ g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+ _("Could not create TLS connection: %s"),
+ gnutls_strerror (status));
+ return FALSE;
+ }
+#endif
+
+ gnutls_transport_set_push_function (self->session,
+ g_tls_operations_thread_gnutls_push_func);
+ gnutls_transport_set_pull_function (self->session,
+ g_tls_operations_thread_gnutls_pull_func);
+ /* FIXME: remove timeout func and switch to GNUTLS_NONBLOCK */
+ gnutls_transport_set_pull_timeout_function (self->session,
+ g_tls_operations_thread_gnutls_pull_timeout_func);
+ gnutls_transport_set_ptr (self->session, self);
+
+ if (is_dtls (self))
+ {
+ /* GDatagramBased supports vectored I/O; GPollableOutputStream does not. */
+ gnutls_transport_set_vec_push_function (self->session,
+ g_tls_operations_thread_gnutls_vec_push_func);
+
+ /* Set reasonable MTU */
+ gnutls_dtls_set_mtu (self->session, 1400);
+ }
}
static void
@@ -489,6 +1015,9 @@ g_tls_operations_thread_gnutls_class_init (GTlsOperationsThreadGnutlsClass *klas
GTlsOperationsThreadBaseClass *base_class = G_TLS_OPERATIONS_THREAD_BASE_CLASS (klass);
gobject_class->constructed = g_tls_operations_thread_gnutls_constructed;
+ gobject_class->finalize = g_tls_operations_thread_gnutls_finalize;
+ gobject_class->get_property = g_tls_operations_thread_gnutls_get_property;
+ gobject_class->set_property = g_tls_operations_thread_gnutls_set_property;
base_class->handshake_fn = g_tls_operations_thread_gnutls_handshake;
base_class->read_fn = g_tls_operations_thread_gnutls_read;
@@ -497,13 +1026,49 @@ g_tls_operations_thread_gnutls_class_init (GTlsOperationsThreadGnutlsClass *klas
base_class->write_message_fn = g_tls_operations_thread_gnutls_write_message;
base_class->close_fn = g_tls_operations_thread_gnutls_close;
+ obj_properties[PROP_BASE_IO_STREAM] =
+ g_param_spec_object ("base-io-stream",
+ "Base IOStream",
+ "The underlying GIOStream, for TLS connections",
+ G_TYPE_IO_STREAM,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_BASE_SOCKET] =
+ g_param_spec_object ("base-socket",
+ "Base socket",
+ "The underlying GDatagramBased, for DTLS connections",
+ G_TYPE_DATAGRAM_BASED,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ obj_properties[PROP_GNUTLS_FLAGS] =
+ g_param_spec_uint ("gnutls-flags",
+ "GnuTLS flags",
+ "Flags for initializing GnuTLS session",
+ 0, UINT_MAX, 0,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, LAST_PROP, obj_properties);
+
initialize_gnutls_priority ();
}
GTlsOperationsThreadBase *
-g_tls_operations_thread_gnutls_new (GTlsConnectionGnutls *tls)
+g_tls_operations_thread_gnutls_new (GTlsConnectionGnutls *connection,
+ GIOStream *base_iostream,
+ GDatagramBased *base_socket,
+ guint flags)
{
return G_TLS_OPERATIONS_THREAD_BASE (g_object_new (G_TYPE_TLS_OPERATIONS_THREAD_GNUTLS,
- "tls-connection", tls,
+ "base-iostream", base_iostream,
+ "base-socket", base_socket,
+ "gnutls-flags", flags,
+ "tls-connection", connection,
NULL));
}
+
+/* FIXME: must remove this! */
+gnutls_session_t
+g_tls_operations_thread_gnutls_get_session (GTlsOperationsThreadGnutls *self)
+{
+ return self->session;
+}
diff --git a/tls/gnutls/gtlsoperationsthread-gnutls.h b/tls/gnutls/gtlsoperationsthread-gnutls.h
index b3fce2d..7637a42 100644
--- a/tls/gnutls/gtlsoperationsthread-gnutls.h
+++ b/tls/gnutls/gtlsoperationsthread-gnutls.h
@@ -35,6 +35,12 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GTlsOperationsThreadGnutls, g_tls_operations_thread_gnutls, G,
TLS_OPERATIONS_THREAD_GNUTLS, GTlsOperationsThreadBase)
-GTlsOperationsThreadBase *g_tls_operations_thread_gnutls_new (GTlsConnectionGnutls *tls);
+GTlsOperationsThreadBase *g_tls_operations_thread_gnutls_new (GTlsConnectionGnutls *connection,
+ GIOStream *base_iostream,
+ GDatagramBased *base_socket,
+ guint flags);
+
+/* FIXME: must remove this!!! */
+gnutls_session_t g_tls_operations_thread_gnutls_get_session (GTlsOperationsThreadGnutls *self);
G_END_DECLS
diff --git a/tls/openssl/gtlsconnection-openssl.c b/tls/openssl/gtlsconnection-openssl.c
index b06465e..bb9f507 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -59,191 +59,6 @@ g_tls_connection_openssl_create_op_thread (GTlsConnectionBase *tls)
return g_tls_operations_thread_openssl_new (G_TLS_CONNECTION_OPENSSL (tls));
}
-static GTlsSafeRenegotiationStatus
-g_tls_connection_openssl_handshake_thread_safe_renegotiation_status (GTlsConnectionBase *tls)
-{
- GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
- SSL *ssl;
-
- ssl = g_tls_connection_openssl_get_ssl (openssl);
-
- return SSL_get_secure_renegotiation_support (ssl) ? G_TLS_SAFE_RENEGOTIATION_SUPPORTED_BY_PEER
- : G_TLS_SAFE_RENEGOTIATION_UNSUPPORTED;
-}
-
-static GTlsConnectionBaseStatus
-end_openssl_io (GTlsConnectionOpenssl *openssl,
- GIOCondition direction,
- int ret,
- gboolean blocking,
- GError **error,
- const char *err_prefix,
- const char *err_str)
-{
- GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (openssl);
- int err_code, err, err_lib, reason;
- GError *my_error = NULL;
- GTlsConnectionBaseStatus status;
- SSL *ssl;
-
- 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);
-
- if ((err_code == SSL_ERROR_WANT_READ ||
- err_code == SSL_ERROR_WANT_WRITE) &&
- blocking)
- {
- 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 */
- /* FIXME: broke this, but entire func should be deleted so OK */
- if (err_code == SSL_ERROR_SYSCALL &&
- g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE))
- {
- g_clear_error (&my_error);
- return G_TLS_CONNECTION_BASE_OK;
- }
-
- err = ERR_get_error ();
- err_lib = ERR_GET_LIB (err);
- reason = ERR_GET_REASON (err);
-
- if (g_tls_connection_base_is_handshaking (tls) && !g_tls_connection_base_ever_handshaked (tls))
- {
- 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 (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
- _("Peer failed to perform TLS handshake: %s"), ERR_reason_error_string (err));
- 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
-#ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED
- || reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED
-#endif
- )
- {
- 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 (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)
- {
- g_clear_error (&my_error);
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Unacceptable TLS certificate"));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- if (reason == SSL_R_TLSV1_ALERT_UNKNOWN_CA)
- {
- g_clear_error (&my_error);
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Unacceptable TLS certificate authority"));
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- 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)
- 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)
- *error = g_error_new (G_TLS_ERROR, G_TLS_ERROR_MISC, "%s: %s", err_prefix, err_str);
-
- return G_TLS_CONNECTION_BASE_ERROR;
-}
-
-#define BEGIN_OPENSSL_IO(openssl, direction, timeout, cancellable) \
- do { \
- char error_str[256]; \
- g_tls_connection_base_push_io (G_TLS_CONNECTION_BASE (openssl), \
- direction, timeout, cancellable);
-
-#define END_OPENSSL_IO(openssl, direction, ret, timeout, status, errmsg, err) \
- ERR_error_string_n (SSL_get_error (ssl, ret), error_str, sizeof(error_str)); \
- status = end_openssl_io (openssl, direction, ret, timeout == -1, err, errmsg, error_str); \
- } while (status == G_TLS_CONNECTION_BASE_TRY_AGAIN);
-
-static GTlsConnectionBaseStatus
-g_tls_connection_openssl_handshake_thread_request_rehandshake (GTlsConnectionBase *tls,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsConnectionOpenssl *openssl;
- GTlsConnectionBaseStatus status;
- SSL *ssl;
- int ret;
-
- /* On a client-side connection, SSL_renegotiate() itself will start
- * a rehandshake, so we only need to do something special here for
- * server-side connections.
- */
- if (!G_IS_TLS_SERVER_CONNECTION (tls))
- return G_TLS_CONNECTION_BASE_OK;
-
- openssl = G_TLS_CONNECTION_OPENSSL (tls);
-
- ssl = g_tls_connection_openssl_get_ssl (openssl);
-
- BEGIN_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, timeout, cancellable);
- ret = SSL_renegotiate (ssl);
- END_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, ret, timeout, status,
- _("Error performing TLS handshake"), error);
-
- return status;
-}
-
static GTlsCertificate *
g_tls_connection_openssl_retrieve_peer_certificate (GTlsConnectionBase *tls)
{
@@ -273,33 +88,7 @@ g_tls_connection_openssl_retrieve_peer_certificate (GTlsConnectionBase *tls)
return G_TLS_CERTIFICATE (chain);
}
-static GTlsConnectionBaseStatus
-g_tls_connection_openssl_handshake_thread_handshake (GTlsConnectionBase *tls,
- gint64 timeout,
- GCancellable *cancellable,
- GError **error)
-{
- GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
- GTlsConnectionBaseStatus status;
- SSL *ssl;
- int ret;
-
- ssl = g_tls_connection_openssl_get_ssl (openssl);
-
- BEGIN_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, timeout, cancellable);
- ret = SSL_do_handshake (ssl);
- END_OPENSSL_IO (openssl, G_IO_IN | G_IO_OUT, ret, timeout, status,
- _("Error performing TLS handshake"), error);
-
- if (ret > 0)
- {
- if (!g_tls_connection_base_handshake_thread_verify_certificate (G_TLS_CONNECTION_BASE (openssl)))
- return G_TLS_CONNECTION_BASE_ERROR;
- }
-
- return status;
-}
-
+/* FIXME: move to op thread? */
static void
g_tls_connection_openssl_push_io (GTlsConnectionBase *tls,
GIOCondition direction,
@@ -310,13 +99,11 @@ g_tls_connection_openssl_push_io (GTlsConnectionBase *tls,
GTlsConnectionOpensslPrivate *priv;
GError **error;
- priv = g_tls_connection_openssl_get_instance_private (openssl);
-
- G_TLS_CONNECTION_BASE_CLASS (g_tls_connection_openssl_parent_class)->push_io (tls, direction,
- timeout, cancellable);
+ priv = g_tls_connection_openssl_get_instance_private (openssl);;
/* FIXME: need to support timeout > 0
- * This will require changes in GTlsBio */
+ * This will require changes in GTlsBio
+ */
if (direction & G_IO_IN)
{
@@ -364,11 +151,9 @@ g_tls_connection_openssl_class_init (GTlsConnectionOpensslClass *klass)
GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
base_class->create_op_thread = g_tls_connection_openssl_create_op_thread;
- base_class->handshake_thread_safe_renegotiation_status =
g_tls_connection_openssl_handshake_thread_safe_renegotiation_status;
- base_class->handshake_thread_request_rehandshake =
g_tls_connection_openssl_handshake_thread_request_rehandshake;
- base_class->handshake_thread_handshake =
g_tls_connection_openssl_handshake_thread_handshake;
+ /* FIXME: remove */
base_class->retrieve_peer_certificate =
g_tls_connection_openssl_retrieve_peer_certificate;
- base_class->push_io = g_tls_connection_openssl_push_io;
+ base_class->push_io = g_tls_connection_openssl_push_io; /* FIXME: move
to op thread */
base_class->pop_io = g_tls_connection_openssl_pop_io;
}
diff --git a/tls/openssl/gtlsconnection-openssl.h b/tls/openssl/gtlsconnection-openssl.h
index 10f93c3..ba5a6bc 100644
--- a/tls/openssl/gtlsconnection-openssl.h
+++ b/tls/openssl/gtlsconnection-openssl.h
@@ -40,9 +40,11 @@ struct _GTlsConnectionOpensslClass
{
GTlsConnectionBaseClass parent_class;
+ /* FIXME: remove this, or entire refactor is a failure */
SSL *(*get_ssl) (GTlsConnectionOpenssl *connection);
};
+/* FIXME: remove this, or entire refactor is a failure */
SSL *g_tls_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection);
GTlsConnectionOpenssl *g_tls_connection_openssl_get_connection_from_ssl (SSL *ssl);
diff --git a/tls/openssl/gtlsoperationsthread-openssl.c b/tls/openssl/gtlsoperationsthread-openssl.c
index d7ecc0b..f3f0fd8 100644
--- a/tls/openssl/gtlsoperationsthread-openssl.c
+++ b/tls/openssl/gtlsoperationsthread-openssl.c
@@ -172,6 +172,35 @@ end_openssl_io (GTlsOperationsThreadOpenssl *self,
status = end_openssl_io (self, direction, ret, err, errmsg, error_str); \
} while (status == G_TLS_CONNECTION_BASE_TRY_AGAIN);
+static GTlsConnectionBaseStatus
+g_tls_operations_thread_openssl_handshake (GTlsOperationsThreadBase *base,
+ gint64 timeout,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GTlsOperationsThreadOpenssl *self = G_TLS_OPERATIONS_THREAD_OPENSSL (base);
+ GTlsConnectionBaseStatus status;
+ int ret;
+
+ /* FIXME: doesn't respect timeout */
+
+ BEGIN_OPENSSL_IO (self, G_IO_IN | G_IO_OUT, cancellable);
+ ret = SSL_do_handshake (ssl);
+ END_OPENSSL_IO (self, G_IO_IN | G_IO_OUT, ret, status,
+ _("Error performing TLS handshake"), error);
+
+ /* FIXME: sabotage */
+#if 0
+ if (ret > 0)
+ {
+ if (!g_tls_connection_base_handshake_thread_verify_certificate (G_TLS_CONNECTION_BASE (openssl)))
+ return G_TLS_CONNECTION_BASE_ERROR;
+ }
+#endif
+
+ return status;
+}
+
static GTlsConnectionBaseStatus
g_tls_operations_thread_openssl_read (GTlsOperationsThreadBase *base,
void *buffer,
@@ -262,6 +291,7 @@ g_tls_operations_thread_openssl_class_init (GTlsOperationsThreadOpensslClass *kl
gobject_class->constructed = g_tls_operations_thread_openssl_constructed;
+ base_class->handshake_fn = g_tls_operations_thread_openssl_handshake;
base_class->read_fn = g_tls_operations_thread_openssl_read;
base_class->write_fn = g_tls_operations_thread_openssl_write;
base_class->close_fn = g_tls_operations_thread_openssl_close;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]