diff options
author | Sjoerd Simons <sjoerd@luon.net> | 2013-04-28 20:21:12 +0200 |
---|---|---|
committer | Sjoerd Simons <sjoerd@luon.net> | 2013-04-28 21:30:30 +0200 |
commit | adb98f54dfe035c8a58726bdfe706f07c0ae0169 (patch) | |
tree | 18fbb25a673a29f99d90326af0502a014cc64dc3 | |
parent | da178c9dbd46c0c067e9d44355687080939678a1 (diff) |
Add support for interactive TLS certificate checking
With the pieces now in place, hook up the TLS channnel manager and pass
it to the server connection so it can request interactive certificate
checking.
-rw-r--r-- | src/idle-connection.c | 10 | ||||
-rw-r--r-- | src/idle-server-connection.c | 85 |
2 files changed, 93 insertions, 2 deletions
diff --git a/src/idle-connection.c b/src/idle-connection.c index 6a655b1..0e7e05c 100644 --- a/src/idle-connection.c +++ b/src/idle-connection.c @@ -48,6 +48,7 @@ #include "idle-roomlist-manager.h" #include "idle-parser.h" #include "idle-server-connection.h" +#include "server-tls-manager.h" #include "extensions/extensions.h" /* Renaming */ @@ -199,6 +200,9 @@ struct _IdleConnectionPrivate { /* so we can pop up a SASL channel asking for the password */ TpSimplePasswordManager *password_manager; + + /* TLS channel */ + IdleServerTLSManager *tls_manager; }; static void _iface_create_handle_repos(TpBaseConnection *self, TpHandleRepoIface **repos); @@ -533,6 +537,10 @@ static GPtrArray *_iface_create_channel_managers(TpBaseConnection *base) { manager = g_object_new(IDLE_TYPE_ROOMLIST_MANAGER, "connection", self, NULL); g_ptr_array_add(managers, manager); + priv->tls_manager = g_object_new (IDLE_TYPE_SERVER_TLS_MANAGER, + "connection", self, NULL); + g_ptr_array_add(managers, priv->tls_manager); + return managers; } @@ -742,7 +750,7 @@ static void _start_connecting_continue(IdleConnection *conn) { priv->username = g_strdup(g_get_user_name()); } - sconn = g_object_new(IDLE_TYPE_SERVER_CONNECTION, "host", priv->server, "port", priv->port, NULL); + sconn = g_object_new(IDLE_TYPE_SERVER_CONNECTION, "host", priv->server, "port", priv->port, "tls-manager", priv->tls_manager, NULL); if (priv->use_ssl) idle_server_connection_set_tls(sconn, TRUE); diff --git a/src/idle-server-connection.c b/src/idle-server-connection.c index 1605b61..d6b8250 100644 --- a/src/idle-server-connection.c +++ b/src/idle-server-connection.c @@ -31,6 +31,7 @@ #define IDLE_DEBUG_FLAG IDLE_DEBUG_NETWORK #include "idle-connection.h" +#include "server-tls-manager.h" #include "idle-debug.h" typedef struct _IdleServerConnectionPrivate IdleServerConnectionPrivate; @@ -47,7 +48,8 @@ enum { enum { PROP_HOST = 1, - PROP_PORT + PROP_PORT, + PROP_TLS_MANAGER }; struct _IdleServerConnectionPrivate { @@ -66,6 +68,8 @@ struct _IdleServerConnectionPrivate { GCancellable *cancellable; IdleServerConnectionState state; + IdleServerTLSManager *tls_manager; + GAsyncQueue *certificate_queue; }; static GObject *idle_server_connection_constructor(GType type, guint n_props, GObjectConstructParam *props); @@ -81,6 +85,7 @@ static void idle_server_connection_init(IdleServerConnection *conn) { priv->socket_client = g_socket_client_new(); priv->state = SERVER_CONNECTION_STATE_NOT_CONNECTED; + priv->certificate_queue = g_async_queue_new (); } static GObject *idle_server_connection_constructor(GType type, guint n_props, GObjectConstructParam *props) { @@ -105,6 +110,7 @@ static void idle_server_connection_finalize(GObject *obj) { IdleServerConnection *conn = IDLE_SERVER_CONNECTION(obj); IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn); + g_async_queue_unref (priv->certificate_queue); g_free(priv->host); } @@ -121,6 +127,10 @@ static void idle_server_connection_get_property(GObject *obj, guint prop_id, GV g_value_set_uint(value, priv->port); break; + case PROP_TLS_MANAGER: + g_value_set_object(value, priv->tls_manager); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); break; @@ -144,6 +154,10 @@ static void idle_server_connection_set_property(GObject *obj, priv->port = (guint16) g_value_get_uint(value); break; + case PROP_TLS_MANAGER: + priv->tls_manager = g_value_dup_object(value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec); break; @@ -183,6 +197,16 @@ static void idle_server_connection_class_init(IdleServerConnectionClass *klass) g_object_class_install_property(object_class, PROP_PORT, pspec); + pspec = g_param_spec_object("tls-manager", "TLS Manager", + "TLS manager for interactive certificate checking", + IDLE_TYPE_SERVER_TLS_MANAGER, + G_PARAM_READABLE| + G_PARAM_WRITABLE| + G_PARAM_STATIC_NICK| + G_PARAM_STATIC_BLURB); + + g_object_class_install_property(object_class, PROP_TLS_MANAGER, pspec); + signals[STATUS_CHANGED] = g_signal_new("status-changed", G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, @@ -293,14 +317,73 @@ cleanup: g_object_unref(result); } + +#define CERT_ACCEPTED 1 +#define CERT_REJECTED 2 +struct CertData { + IdleServerConnection *self; + GTlsCertificate *certificate; +}; + +static void _certificate_verified (GObject *source, GAsyncResult *res, gpointer user_data) +{ + IdleServerConnection *self = user_data; + IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(self); + gboolean ret; + + ret = idle_server_tls_manager_verify_finish (IDLE_SERVER_TLS_MANAGER (source), res, NULL); + g_async_queue_push (priv->certificate_queue, GINT_TO_POINTER (ret ? CERT_ACCEPTED : CERT_REJECTED)); +} + +static gboolean +_check_certificate_interactively (gpointer data) { + struct CertData *d = data; + IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(d->self); + + idle_server_tls_manager_verify_async (priv->tls_manager, d->certificate, priv->host, _certificate_verified, d->self); + return FALSE; +} + +static gboolean _accept_certificate_request (GTlsConnection *tls_connection, GTlsCertificate *peer_cert, GTlsCertificateFlags errors, IdleServerConnection *conn) +{ + IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn); + struct CertData d; + gpointer result; + + /* Requested to check the extra errors from an ssl certificate, + * Need to bounce this back into the main thread so we can ask the UI + * on dbus */ + IDLE_DEBUG ("Requested to validate certificate"); + + d.self = conn; + d.certificate = peer_cert; + + g_idle_add (_check_certificate_interactively, &d); + result = g_async_queue_pop (priv->certificate_queue); + + return GPOINTER_TO_INT (result) == CERT_ACCEPTED; +} + +static void _connect_event_cb (GSocketClient *client, GSocketClientEvent event, GSocketConnectable *connectable, GIOStream *connection, gpointer user_data) +{ + if (event != G_SOCKET_CLIENT_TLS_HANDSHAKING) + return; + + g_signal_connect (connection, "accept-certificate", G_CALLBACK (_accept_certificate_request), user_data); +} + static void _connect_in_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { IdleServerConnection *conn = source_object; IdleServerConnectionPrivate *priv = IDLE_SERVER_CONNECTION_GET_PRIVATE(conn); GError *error = NULL; GSocketConnection *socket_connection; + gulong event_id; + event_id = g_signal_connect (priv->socket_client, "event", + G_CALLBACK (_connect_event_cb), conn); socket_connection = g_socket_client_connect_to_host (priv->socket_client, priv->host, priv->port, cancellable, &error); + g_signal_handler_disconnect (priv->socket_client, event_id); if (socket_connection != NULL) g_task_return_pointer (task, socket_connection, NULL); else |