[glib-networking/mcatanzaro/tls-thread: 12/24] progress
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/mcatanzaro/tls-thread: 12/24] progress
- Date: Sat, 28 Dec 2019 21:04:29 +0000 (UTC)
commit 94fdde36fa80b22edf152ed8d4f7505365bac71c
Author: Michael Catanzaro <mcatanzaro gnome org>
Date: Sun Dec 22 14:10:07 2019 -0600
progress
tls/base/gtlsconnection-base.c | 106 ++++++------------
tls/base/gtlsconnection-base.h | 3 +
tls/base/gtlsoperationsthread-base.c | 25 ++++-
tls/base/gtlsoperationsthread-base.h | 4 +
tls/gnutls/gtlsclientconnection-gnutls.c | 38 +++----
tls/gnutls/gtlsconnection-gnutls.c | 147 +-----------------------
tls/gnutls/gtlsoperationsthread-gnutls.c | 186 ++++++++++++++++++++++++++++---
tls/gnutls/gtlsserverconnection-gnutls.c | 1 -
8 files changed, 247 insertions(+), 263 deletions(-)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index c15bca1..a79ae93 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -135,7 +135,6 @@ typedef struct
GMainContext *handshake_context; /* FIXME remove */
GTask *async_implicit_handshake;
GError *handshake_error;
- GByteArray *app_data_buf;
/* read_closed means the read direction has closed; write_closed similarly.
* If (and only if) both are set, the entire GTlsConnection is closed. */
@@ -290,8 +289,6 @@ g_tls_connection_base_finalize (GObject *object)
g_clear_object (&priv->waiting_for_op);
g_mutex_clear (&priv->op_mutex);
- g_clear_pointer (&priv->app_data_buf, g_byte_array_unref);
-
g_clear_pointer (&priv->advertised_protocols, g_strfreev);
g_clear_pointer (&priv->negotiated_protocol, g_free);
@@ -1424,6 +1421,15 @@ handshake (GTlsConnectionBase *tls,
{
GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
GTlsAuthenticationMode auth_mode = G_TLS_AUTHENTICATION_NONE;
+ gchar *original_negotiated_protocol;
+ GList *accepted_cas;
+
+ /* FIXME: in async codepaths, this function is still called on a secondary
+ * handshake thread. That means use of priv members here needs to be guarded
+ * by a mutex. Additionally, it is SUPER UNSAFE to notify negotiated-protocol
+ * on this thread. We need to either eliminate this extra thread, or tighten
+ * up the threadsafety of this function.
+ */
g_tls_log_debug (tls, "TLS handshake starts");
@@ -1460,10 +1466,31 @@ handshake (GTlsConnectionBase *tls,
NULL);
}
+ original_negotiated_protocol = g_steal_pointer (&priv->negotiated_protocol);
+
priv->started_handshake = TRUE;
- g_tls_operations_thread_base_handshake (priv->thread, (const gchar **)priv->advertised_protocols,
auth_mode, timeout, cancellable, error);
+
+ g_tls_operations_thread_base_handshake (priv->thread,
+ (const gchar **)priv->advertised_protocols,
+ auth_mode,
+ timeout,
+ &priv->negotiated_protocol,
+ &accepted_cas,
+ cancellable,
+ error);
+
priv->need_handshake = FALSE;
+ /* FIXME: notify should be next to accepted-cas? */
+ if (g_strcmp0 (original_negotiated_protocol, priv->negotiated_protocol) != 0)
+ g_object_notify (G_OBJECT (tls), "negotiated-protocol");
+ g_free (original_negotiated_protocol);
+
+ if (G_IS_TLS_CLIENT_CONNECTION (tls))
+ G_TLS_CONNECTION_BASE_GET_CLASS (tls)->set_accepted_cas (tls, accepted_cas);
+ else
+ g_assert (!accepted_cas);
+
if (error && *error)
{
g_tls_log_debug (tls, "TLS handshake failed: %s", (*error)->message);
@@ -1482,13 +1509,10 @@ finish_handshake (GTlsConnectionBase *tls,
{
GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
GTlsConnectionBaseClass *tls_class = G_TLS_CONNECTION_BASE_GET_CLASS (tls);
- gchar *original_negotiated_protocol;
GError *my_error = NULL;
g_tls_log_debug (tls, "finishing TLS handshake");
- original_negotiated_protocol = g_steal_pointer (&priv->negotiated_protocol);
-
if (success)
{
if (tls_class->is_session_resumed && tls_class->is_session_resumed (tls))
@@ -1517,15 +1541,9 @@ finish_handshake (GTlsConnectionBase *tls,
}
}
- if (tls_class->complete_handshake)
- {
- /* If we already have an error, ignore further errors. */
- tls_class->complete_handshake (tls, &priv->negotiated_protocol, my_error ? NULL : &my_error);
-
- if (g_strcmp0 (original_negotiated_protocol, priv->negotiated_protocol) != 0)
- g_object_notify (G_OBJECT (tls), "negotiated-protocol");
- }
- g_free (original_negotiated_protocol);
+ /* FIXME: notify only when accepted-cas has actually changed. */
+ if (G_IS_TLS_CLIENT_CONNECTION (tls))
+ g_object_notify (G_OBJECT (tls), "accepted-cas");
if (my_error && priv->started_handshake)
priv->handshake_error = g_error_copy (my_error);
@@ -1547,7 +1565,6 @@ g_tls_connection_base_handshake (GTlsConnection *conn,
{
GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (conn);
GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
- GTlsConnectionBaseClass *tls_class = G_TLS_CONNECTION_BASE_GET_CLASS (tls);
gboolean success;
GError *my_error = NULL;
@@ -1865,20 +1882,7 @@ g_tls_connection_base_read (GTlsConnectionBase *tls,
timeout, cancellable, error))
return -1;
- if (priv->app_data_buf && !priv->handshaking)
- {
- nread = MIN (size, priv->app_data_buf->len);
- memcpy (buffer, priv->app_data_buf->data, nread);
- if (nread == priv->app_data_buf->len)
- g_clear_pointer (&priv->app_data_buf, g_byte_array_unref);
- else
- g_byte_array_remove_range (priv->app_data_buf, 0, nread);
- status = G_TLS_CONNECTION_BASE_OK;
- }
- else
- {
- status = g_tls_operations_thread_base_read (priv->thread, buffer, size, timeout, &nread,
cancellable, error);
- }
+ status = g_tls_operations_thread_base_read (priv->thread, buffer, size, timeout, &nread, cancellable,
error);
yield_op (tls, G_TLS_CONNECTION_BASE_OP_READ, status);
}
@@ -1914,32 +1918,7 @@ g_tls_connection_base_read_message (GTlsConnectionBase *tls,
timeout, cancellable, error))
return -1;
- /* Copy data out of the app data buffer first. */
- if (priv->app_data_buf && !priv->handshaking)
- {
- nread = 0;
-
- for (guint i = 0; i < num_vectors; i++)
- {
- gsize count;
- GInputVector *vec = &vectors[i];
-
- count = MIN (vec->size, priv->app_data_buf->len);
- nread += count;
-
- memcpy (vec->buffer, priv->app_data_buf->data, count);
- if (count == priv->app_data_buf->len)
- g_clear_pointer (&priv->app_data_buf, g_byte_array_unref);
- else
- g_byte_array_remove_range (priv->app_data_buf, 0, count);
- status = G_TLS_CONNECTION_BASE_OK;
- }
- }
- else
- {
- status = g_tls_operations_thread_base_read_message (priv->thread, vectors, num_vectors, timeout,
&nread, cancellable, error);
- }
-
+ status = g_tls_operations_thread_base_read_message (priv->thread, vectors, num_vectors, timeout, &nread,
cancellable, error);
yield_op (tls, G_TLS_CONNECTION_BASE_OP_READ, status);
} while (status == G_TLS_CONNECTION_BASE_REHANDSHAKE);
@@ -2479,19 +2458,6 @@ g_tls_connection_base_handshake_thread_request_certificate (GTlsConnectionBase *
return res != G_TLS_INTERACTION_FAILED;
}
-void
-g_tls_connection_base_handshake_thread_buffer_application_data (GTlsConnectionBase *tls,
- guint8 *data,
- gsize length)
-{
- GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-
- if (!priv->app_data_buf)
- priv->app_data_buf = g_byte_array_new ();
-
- g_byte_array_append (priv->app_data_buf, data, length);
-}
-
GTlsOperationsThreadBase *
g_tls_connection_base_get_op_thread (GTlsConnectionBase *tls)
{
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index ea764c6..3f1f5bf 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -68,6 +68,9 @@ struct _GTlsConnectionBaseClass
GIOCondition direction,
gboolean success,
GError **error);
+
+ void (*set_accepted_cas) (GTlsConnectionBase *tls,
+ GList *accepted_cas);
};
gboolean g_tls_connection_base_handshake_thread_verify_certificate
diff --git a/tls/base/gtlsoperationsthread-base.c b/tls/base/gtlsoperationsthread-base.c
index 44975af..63910a9 100644
--- a/tls/base/gtlsoperationsthread-base.c
+++ b/tls/base/gtlsoperationsthread-base.c
@@ -101,9 +101,13 @@ typedef struct {
GTlsConnectionBase *connection; /* FIXME: threadsafety nightmare, not OK */
GTlsOperationsThreadBase *source; /* for copy client session state */
+
gchar *server_identity; /* for set server identity */
+
+ gchar *negotiated_protocol; /* for handshake */
gchar **advertised_protocols; /* for handshake */
GTlsAuthenticationMode auth_mode; /* for handshake */
+ GList *accepted_cas; /* for handshake */
union {
void *data; /* for read/write */
@@ -173,7 +177,6 @@ g_tls_thread_copy_client_session_state_operation_new (GTlsOperationsThreadBase *
return op;
}
-/* FIXME: dumb, move this into handshake operation as is done for authentication mode */
static GTlsThreadOperation *
g_tls_thread_set_server_identity_operation_new (GTlsOperationsThreadBase *thread,
GTlsConnectionBase *connection,
@@ -362,7 +365,11 @@ g_tls_thread_operation_free (GTlsThreadOperation *op)
g_free (op->server_identity);
if (op->type == G_TLS_THREAD_OP_HANDSHAKE)
- g_strfreev (op->advertised_protocols);
+ {
+ g_strfreev (op->advertised_protocols);
+ g_assert (!op->accepted_cas);
+ g_assert (!op->negotiated_protocol);
+ }
if (op->type != G_TLS_THREAD_OP_SHUTDOWN_THREAD)
{
@@ -470,10 +477,13 @@ g_tls_operations_thread_base_handshake (GTlsOperationsThreadBase *self,
const gchar **advertised_protocols,
GTlsAuthenticationMode auth_mode,
gint64 timeout,
+ gchar **negotiated_protocol,
+ GList **accepted_cas,
GCancellable *cancellable,
GError **error)
{
GTlsOperationsThreadBasePrivate *priv = g_tls_operations_thread_base_get_instance_private (self);
+ GTlsConnectionBaseStatus status;
GTlsThreadOperation *op;
op = g_tls_thread_handshake_operation_new (self,
@@ -482,7 +492,10 @@ g_tls_operations_thread_base_handshake (GTlsOperationsThreadBase *self,
auth_mode,
timeout,
cancellable);
- return execute_op (self, g_steal_pointer (&op), NULL, error);
+ status = execute_op (self, g_steal_pointer (&op), NULL, error);
+ *negotiated_protocol = g_steal_pointer (&op->negotiated_protocol);
+ *accepted_cas = g_steal_pointer (&op->accepted_cas);
+ return status;
}
GTlsConnectionBaseStatus
@@ -907,6 +920,8 @@ process_op (GAsyncQueue *queue,
(const gchar **)op->advertised_protocols,
op->auth_mode,
op->timeout,
+ &op->negotiated_protocol,
+ &op->accepted_cas,
op->cancellable,
&op->error);
break;
@@ -1015,9 +1030,7 @@ tls_op_thread (gpointer data)
g_main_loop_run (main_loop);
- /* FIXME FIXME: what happens if there are still ops in progress?
- * They should be cancelled somehow. Figure out how.
- */
+ g_assert (!queue_has_pending_op (priv->queue));
g_main_context_pop_thread_default (priv->op_thread_context);
diff --git a/tls/base/gtlsoperationsthread-base.h b/tls/base/gtlsoperationsthread-base.h
index 9e61055..5980b41 100644
--- a/tls/base/gtlsoperationsthread-base.h
+++ b/tls/base/gtlsoperationsthread-base.h
@@ -47,6 +47,8 @@ struct _GTlsOperationsThreadBaseClass
const gchar **advertised_protocols,
GTlsAuthenticationMode auth_mode,
gint64 timeout,
+ gchar **negotiated_protocol,
+ GList **accepted_cas,
GCancellable *cancellable,
GError **error);
@@ -109,6 +111,8 @@ GTlsConnectionBaseStatus g_tls_operations_thread_base_handshake
const gchar
**advertised_protocols,
GTlsAuthenticationMode
auth_mode,
gint64
timeout,
+ gchar
**negotiated_protocol,
+ GList
**accepted_cas,
GCancellable
*cancellable,
GError
**error);
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 0a8a7f0..96d2893 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -54,7 +54,7 @@ struct _GTlsClientConnectionGnutls
GSocketConnectable *server_identity;
gboolean use_ssl3;
- GPtrArray *accepted_cas;
+ GList *accepted_cas;
};
static void g_tls_client_connection_gnutls_initable_interface_init (GInitableIface *iface);
@@ -94,7 +94,12 @@ g_tls_client_connection_gnutls_finalize (GObject *object)
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
g_clear_object (&gnutls->server_identity);
- g_clear_pointer (&gnutls->accepted_cas, g_ptr_array_unref);
+
+ if (gnutls->accepted_cas)
+ {
+ g_list_free_full (gnutls->accepted_cas, (GDestroyNotify)g_byte_array_unref);
+ gnutls->accepted_cas = NULL;
+ }
G_OBJECT_CLASS (g_tls_client_connection_gnutls_parent_class)->finalize (object);
}
@@ -125,8 +130,6 @@ g_tls_client_connection_gnutls_get_property (GObject *object,
GParamSpec *pspec)
{
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
- GList *accepted_cas;
- gint i;
switch (prop_id)
{
@@ -143,16 +146,7 @@ g_tls_client_connection_gnutls_get_property (GObject *object,
break;
case PROP_ACCEPTED_CAS:
- accepted_cas = NULL;
- if (gnutls->accepted_cas)
- {
- for (i = 0; i < gnutls->accepted_cas->len; ++i)
- {
- accepted_cas = g_list_prepend (accepted_cas, g_byte_array_ref
(gnutls->accepted_cas->pdata[i]));
- }
- accepted_cas = g_list_reverse (accepted_cas);
- }
- g_value_set_pointer (value, accepted_cas);
+ g_value_set_pointer (value, g_list_copy (gnutls->accepted_cas));
break;
default:
@@ -200,19 +194,15 @@ g_tls_client_connection_gnutls_set_property (GObject *object,
}
static void
-g_tls_client_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
- gchar **negotiated_protocol,
- GError **error)
+g_tls_client_connection_gnutls_set_accepted_cas (GTlsConnectionBase *tls,
+ GList *accepted_cas)
{
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (tls);
- G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_gnutls_parent_class)->complete_handshake (tls,
negotiated_protocol, error);
+ if (gnutls->accepted_cas)
+ g_list_free_full (gnutls->accepted_cas, (GDestroyNotify)g_byte_array_unref);
- /* It may have changed during the handshake, but we have to wait until here
- * because we can't emit notifies on the handshake thread.
- */
- if (gnutls->accepted_cas_changed)
- g_object_notify (G_OBJECT (gnutls), "accepted-cas");
+ gnutls->accepted_cas = g_steal_pointer (&accepted_cas);
}
static void
@@ -235,7 +225,7 @@ 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->complete_handshake = g_tls_client_connection_gnutls_complete_handshake;
+ base_class->set_accepted_cas = g_tls_client_connection_gnutls_set_accepted_cas;
g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 3be6fed..6b8f88f 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -58,13 +58,10 @@ static GInitableIface *g_tls_connection_gnutls_parent_initable_iface;
static void g_tls_connection_gnutls_initable_iface_init (GInitableIface *iface);
-static gnutls_priority_t priority;
-
typedef struct
{
gnutls_session_t session; /* FIXME: should be used only by GTlsOperationsThreadGnutls */
- gchar *interaction_id;
- GCancellable *cancellable;
+
} GTlsConnectionGnutlsPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GTlsConnectionGnutls, g_tls_connection_gnutls, G_TYPE_TLS_CONNECTION_BASE,
@@ -73,18 +70,9 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GTlsConnectionGnutls, g_tls_connection_gnutls,
g_tls_connection_gnutls_initable_iface_init);
);
-static gint unique_interaction_id = 0;
-
static void
g_tls_connection_gnutls_init (GTlsConnectionGnutls *gnutls)
{
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- int unique_id;
-
- unique_id = g_atomic_int_add (&unique_interaction_id, 1);
- priv->interaction_id = g_strdup_printf ("gtls:%d", unique_id);
-
- priv->cancellable = g_cancellable_new ();
}
static gboolean
@@ -104,120 +92,6 @@ g_tls_connection_gnutls_initable_init (GInitable *initable,
return TRUE;
}
-static void
-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->cancellable)
- {
- g_cancellable_cancel (priv->cancellable);
- g_clear_object (&priv->cancellable);
- }
-
- g_free (priv->interaction_id);
-
- G_OBJECT_CLASS (g_tls_connection_gnutls_parent_class)->finalize (object);
-}
-
-static int
-on_pin_request (void *userdata,
- int attempt,
- const char *token_url,
- const char *token_label,
- unsigned int callback_flags,
- char *pin,
- size_t pin_max)
-{
- GTlsConnection *connection = G_TLS_CONNECTION (userdata);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (G_TLS_CONNECTION_GNUTLS
(connection));
- GTlsInteraction *interaction = g_tls_connection_get_interaction (connection);
- GTlsInteractionResult result;
- GTlsPassword *password;
- GTlsPasswordFlags password_flags = 0;
- GError *error = NULL;
- gchar *description;
- int ret = -1;
-
- if (!interaction)
- return -1;
-
- if (callback_flags & GNUTLS_PIN_WRONG)
- password_flags |= G_TLS_PASSWORD_RETRY;
- if (callback_flags & GNUTLS_PIN_COUNT_LOW)
- password_flags |= G_TLS_PASSWORD_MANY_TRIES;
- if (callback_flags & GNUTLS_PIN_FINAL_TRY || attempt > 5) /* Give up at some point */
- password_flags |= G_TLS_PASSWORD_FINAL_TRY;
-
- description = g_strdup_printf (" %s (%s)", token_label, token_url);
- password = g_tls_password_new (password_flags, description);
- result = g_tls_interaction_invoke_ask_password (interaction, password,
- priv->cancellable,
- &error);
- g_free (description);
-
- switch (result)
- {
- case G_TLS_INTERACTION_FAILED:
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Error getting PIN: %s", error->message);
- g_error_free (error);
- break;
- case G_TLS_INTERACTION_UNHANDLED:
- break;
- case G_TLS_INTERACTION_HANDLED:
- {
- gsize password_size;
- const guchar *password_data = g_tls_password_get_value (password, &password_size);
- if (password_size > pin_max)
- g_warning ("PIN is larger than max PIN size");
-
- memcpy (pin, password_data, MIN (password_size, pin_max));
- ret = GNUTLS_E_SUCCESS;
- break;
- }
- default:
- g_assert_not_reached ();
- }
-
- g_object_unref (password);
-
- return ret;
-}
-
-void
-g_tls_connection_gnutls_handshake_thread_get_certificate (GTlsConnectionGnutls *gnutls,
- gnutls_pcert_st **pcert,
- unsigned int *pcert_length,
- gnutls_privkey_t *pkey)
-{
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- GTlsCertificate *cert;
-
- cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (gnutls));
-
- if (cert)
- {
- /* Send along a pre-initialized privkey so we can handle the callback here. */
- /* FIXME: this was never safe, we're not on the right thread here */
- gnutls_privkey_t privkey;
- gnutls_privkey_init (&privkey);
- gnutls_privkey_set_pin_function (privkey, on_pin_request, gnutls);
-
- g_tls_certificate_gnutls_copy (G_TLS_CERTIFICATE_GNUTLS (cert),
- priv->interaction_id,
- pcert, pcert_length, &privkey);
- *pkey = privkey;
- }
- else
- {
- *pcert = NULL;
- *pcert_length = 0;
- *pkey = NULL;
- }
-}
-
static GTlsOperationsThreadBase *
g_tls_connection_gnutls_create_op_thread (GTlsConnectionBase *tls)
{
@@ -272,22 +146,6 @@ g_tls_connection_gnutls_retrieve_peer_certificate (GTlsConnectionBase *tls)
return G_TLS_CERTIFICATE (chain);
}
-static void
-g_tls_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
- gchar **negotiated_protocol,
- GError **error)
-{
- GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (tls);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- gnutls_datum_t protocol;
-
- if (gnutls_alpn_get_selected_protocol (priv->session, &protocol) == 0 && protocol.size > 0)
- {
- g_assert (!*negotiated_protocol);
- *negotiated_protocol = g_strndup ((gchar *)protocol.data, protocol.size);
- }
-}
-
static gboolean
g_tls_connection_gnutls_is_session_resumed (GTlsConnectionBase *tls)
{
@@ -303,11 +161,8 @@ g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
- gobject_class->finalize = g_tls_connection_gnutls_finalize;
-
base_class->create_op_thread = g_tls_connection_gnutls_create_op_thread;
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/gtlsoperationsthread-gnutls.c b/tls/gnutls/gtlsoperationsthread-gnutls.c
index 6688d58..aa98265 100644
--- a/tls/gnutls/gtlsoperationsthread-gnutls.c
+++ b/tls/gnutls/gtlsoperationsthread-gnutls.c
@@ -52,8 +52,6 @@ struct _GTlsOperationsThreadGnutls {
GBytes *session_data;
gboolean session_data_override; /* FIXME: sort this all out */
- gchar *server_identity;
-
gnutls_session_t session;
GIOStream *base_iostream;
@@ -71,8 +69,13 @@ struct _GTlsOperationsThreadGnutls {
unsigned int pcert_length;
gnutls_privkey_t pkey;
- GPtrArray *accepted_cas;
- gboolean accepted_cas_changed;
+ GList *accepted_cas;
+
+ gchar *server_identity;
+
+ gchar *interaction_id;
+
+ GByteArray *application_data_buffer;
};
enum
@@ -531,12 +534,15 @@ g_tls_operations_thread_gnutls_handshake (GTlsOperationsThreadBase *base,
const gchar **advertised_protocols,
GTlsAuthenticationMode auth_mode,
gint64 timeout,
+ gchar **negotiated_protocol,
+ GList **accepted_cas,
GCancellable *cancellable,
GError **error)
{
GTlsOperationsThreadGnutls *self = G_TLS_OPERATIONS_THREAD_GNUTLS (base);
GTlsConnectionBase *tls;
GTlsConnectionBaseStatus status;
+ gnutls_datum_t protocol;
int ret;
tls = g_tls_operations_thread_base_get_connection (base);
@@ -568,8 +574,9 @@ 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, don't use GTlsConnectionBase */
- g_tls_connection_base_handshake_thread_buffer_application_data (tls, buf, ret);
+ if (!self->application_data_buffer)
+ self->application_data_buffer = g_byte_array_new ();
+ g_byte_array_append (self->application_data_buffer, buf, ret);
ret = GNUTLS_E_AGAIN;
}
}
@@ -579,6 +586,11 @@ g_tls_operations_thread_gnutls_handshake (GTlsOperationsThreadBase *base,
self->handshaking = FALSE;
self->ever_handshaked = TRUE;
+ if (gnutls_alpn_get_selected_protocol (self->session, &protocol) == 0 && protocol.size > 0)
+ *negotiated_protocol = g_strndup ((gchar *)protocol.data, protocol.size);
+
+ *accepted_cas = g_list_copy (self->accepted_cas);
+
return status;
}
@@ -594,6 +606,17 @@ g_tls_operations_thread_gnutls_read (GTlsOperationsThreadBase *base,
GTlsConnectionBaseStatus status;
gssize ret;
+ if (self->application_data_buffer)
+ {
+ *nread = MIN (size, self->application_data_buffer->len);
+ memcpy (buffer, self->application_data_buffer->data, nread);
+ if (*nread == self->application_data_buffer->len)
+ g_clear_pointer (&self->application_data_buffer, g_byte_array_unref);
+ else
+ g_byte_array_remove_range (self->application_data_buffer, 0, *nread);
+ return G_TLS_CONNECTION_BASE_OK;
+ }
+
BEGIN_GNUTLS_IO (self, G_IO_IN, cancellable);
ret = gnutls_record_recv (self->session, buffer, size);
END_GNUTLS_IO (self, G_IO_IN, ret, status, _("Error reading data from TLS socket"), error);
@@ -640,6 +663,28 @@ g_tls_operations_thread_gnutls_read_message (GTlsOperationsThreadBase *base,
gssize ret;
gnutls_packet_t packet = { 0, };
+ /* Copy data out of the app data buffer first. */
+ if (self->application_data_buffer)
+ {
+ *nread = 0;
+
+ for (guint i = 0; i < num_vectors; i++)
+ {
+ gsize count;
+ GInputVector *vec = &vectors[i];
+
+ count = MIN (vec->size, self->application_data_buffer->len);
+ *nread += count;
+
+ memcpy (vec->buffer, self->application_data_buffer->data, count);
+ if (count == self->application_data_buffer->len)
+ g_clear_pointer (&self->application_data_buffer, g_byte_array_unref);
+ else
+ g_byte_array_remove_range (self->application_data_buffer, 0, count);
+ return G_TLS_CONNECTION_BASE_OK;
+ }
+ }
+
BEGIN_GNUTLS_IO (self, G_IO_IN, cancellable);
/* Receive the entire datagram (zero-copy). */
@@ -1045,6 +1090,70 @@ verify_certificate_cb (gnutls_session_t session)
return !g_tls_connection_base_handshake_thread_verify_certificate (tls);
}
+static int
+pin_request_cb (void *userdata,
+ int attempt,
+ const char *token_url,
+ const char *token_label,
+ unsigned int callback_flags,
+ char *pin,
+ size_t pin_max)
+{
+ GTlsOperationsThreadGnutls *self = G_TLS_OPERATIONS_THREAD_GNUTLS (userdata);
+ GTlsInteraction *interaction = g_tls_connection_get_interaction (connection);
+ GTlsInteractionResult result;
+ GTlsPassword *password;
+ GTlsPasswordFlags password_flags = 0;
+ GError *error = NULL;
+ gchar *description;
+ int ret = -1;
+
+ if (!interaction)
+ return -1;
+
+ if (callback_flags & GNUTLS_PIN_WRONG)
+ password_flags |= G_TLS_PASSWORD_RETRY;
+ if (callback_flags & GNUTLS_PIN_COUNT_LOW)
+ password_flags |= G_TLS_PASSWORD_MANY_TRIES;
+ if (callback_flags & GNUTLS_PIN_FINAL_TRY || attempt > 5) /* Give up at some point */
+ password_flags |= G_TLS_PASSWORD_FINAL_TRY;
+
+ description = g_strdup_printf (" %s (%s)", token_label, token_url);
+ password = g_tls_password_new (password_flags, description);
+ result = g_tls_interaction_invoke_ask_password (interaction, password,
+ self->op_cancellable,
+ &error);
+ g_free (description);
+
+ switch (result)
+ {
+ case G_TLS_INTERACTION_FAILED:
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Error getting PIN: %s", error->message);
+ g_error_free (error);
+ break;
+ case G_TLS_INTERACTION_UNHANDLED:
+ break;
+ case G_TLS_INTERACTION_HANDLED:
+ {
+ gsize password_size;
+ const guchar *password_data = g_tls_password_get_value (password, &password_size);
+ if (password_size > pin_max)
+ g_warning ("PIN is larger than max PIN size");
+
+ memcpy (pin, password_data, MIN (password_size, pin_max));
+ ret = GNUTLS_E_SUCCESS;
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+
+ g_object_unref (password);
+
+ return ret;
+}
+
static void
clear_gnutls_certificate_copy (GTlsOperationsThreadGnutls *self)
{
@@ -1055,6 +1164,41 @@ clear_gnutls_certificate_copy (GTlsOperationsThreadGnutls *self)
self->pkey = NULL;
}
+static void
+get_own_certificate (GTlsOperationsThreadGnutls *self,
+ gnutls_pcert_st **pcert,
+ unsigned int *pcert_length,
+ gnutls_privkey_t *pkey)
+{
+ char *pem;
+ GTlsCertificate *cert = NULL;
+
+ pem = g_tls_operations_thread_base_get_own_certificate_pem (G_TLS_OPERATIONS_THREAD_BASE (self));
+ if (pem)
+ {
+ cert = g_tls_certificate_new_from_pem (pem, -1, NULL);
+ g_free (pem);
+ }
+
+ if (cert)
+ {
+ gnutls_privkey_t privkey;
+ gnutls_privkey_init (&privkey);
+ gnutls_privkey_set_pin_function (privkey, pin_request_cb, self);
+
+ g_tls_certificate_gnutls_copy (G_TLS_CERTIFICATE_GNUTLS (cert),
+ self->interaction_id,
+ pcert, pcert_length, &privkey);
+ *pkey = privkey;
+ }
+ else
+ {
+ *pcert = NULL;
+ *pcert_length = 0;
+ *pkey = NULL;
+ }
+}
+
static int
retrieve_certificate_cb (gnutls_session_t session,
const gnutls_datum_t *req_ca_rdn,
@@ -1066,7 +1210,6 @@ retrieve_certificate_cb (gnutls_session_t session,
gnutls_privkey_t *pkey)
{
GTlsOperationsThreadGnutls *self = gnutls_transport_get_ptr (session);
- gboolean had_accepted_cas;
GByteArray *dn;
int i;
@@ -1076,22 +1219,24 @@ retrieve_certificate_cb (gnutls_session_t session,
if (is_client (self))
{
- had_accepted_cas = self->accepted_cas && self->accepted_cas->len != 0;
+ if (self->accepted_cas)
+ {
+ g_list_free_full (self->accepted_cas, (GDestroyNotify)g_byte_array_unref);
+ self->accepted_cas = NULL;
+ }
- g_clear_pointer (&self->accepted_cas, g_ptr_array_unref);
- self->accepted_cas = g_ptr_array_new_with_free_func ((GDestroyNotify)g_byte_array_unref);
for (i = 0; i < nreqs; i++)
{
dn = g_byte_array_new ();
g_byte_array_append (dn, req_ca_rdn[i].data, req_ca_rdn[i].size);
- g_ptr_array_add (self->accepted_cas, dn);
+ self->accepted_cas = g_list_prepend (self->accepted_cas, dn);
}
- self->accepted_cas_changed = self->accepted_cas || had_accepted_cas;
+ self->accepted_cas = g_list_reverse (self->accepted_cas);
}
clear_gnutls_certificate_copy (self);
- g_tls_connection_gnutls_handshake_thread_get_certificate (conn, pcert, pcert_length, pkey);
+ get_own_certificate (self, pcert, pcert_length, pkey);
if (is_client (self))
{
@@ -1100,7 +1245,7 @@ retrieve_certificate_cb (gnutls_session_t session,
g_tls_certificate_gnutls_copy_free (*pcert, *pcert_length, *pkey);
if (g_tls_connection_base_handshake_thread_request_certificate (tls))
- g_tls_connection_gnutls_handshake_thread_get_certificate (conn, pcert, pcert_length, pkey);
+ get_own_certificate (self, pcert, pcert_length, pkey);
if (*pcert_length == 0)
{
@@ -1226,15 +1371,21 @@ g_tls_operations_thread_gnutls_finalize (GObject *object)
g_clear_pointer (&self->creds, gnutls_certificate_free_credentials);
g_clear_pointer (&self->session_id, g_bytes_unref);
g_clear_pointer (&self->session_data, g_bytes_unref);
-
+ g_clear_pointer (&self->application_data_buffer, g_byte_array_unref);
g_clear_pointer (&self->server_identity, g_free);
- g_clear_pointer (&self->accepted_cas, g_ptr_array_unref);
+ g_clear_pointer (&self->interaction_id, g_free);
g_clear_object (&self->base_iostream);
g_clear_object (&self->base_socket);
clear_gnutls_certificate_copy (self);
+ if (self->accepted_cas)
+ {
+ g_list_free_full (self->accepted_cas, (GDestroyNotify)g_byte_array_unref);
+ self->accepted_cas = NULL;
+ }
+
g_assert (!self->op_cancellable);
g_assert (!self->op_error);
@@ -1310,6 +1461,9 @@ g_tls_operations_thread_gnutls_constructed (GObject *object)
static void
g_tls_operations_thread_gnutls_init (GTlsOperationsThreadGnutls *self)
{
+ static int unique_interaction_id = 0;
+
+ self->interaction_id = g_strdup_printf ("gtls:%d", unique_interaction_id++);
}
static void
diff --git a/tls/gnutls/gtlsserverconnection-gnutls.c b/tls/gnutls/gtlsserverconnection-gnutls.c
index 7f54c84..1d834ca 100644
--- a/tls/gnutls/gtlsserverconnection-gnutls.c
+++ b/tls/gnutls/gtlsserverconnection-gnutls.c
@@ -73,7 +73,6 @@ g_tls_server_connection_gnutls_initable_init (GInitable *initable,
GError **error)
{
GTlsCertificate *cert;
- gnutls_certificate_credentials_t creds;
if (!g_tls_server_connection_gnutls_parent_initable_iface->init (initable, cancellable, error))
return FALSE;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]