summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSjoerd Simons <sjoerd@luon.net>2013-04-28 20:21:12 +0200
committerSjoerd Simons <sjoerd@luon.net>2013-04-28 21:30:30 +0200
commitadb98f54dfe035c8a58726bdfe706f07c0ae0169 (patch)
tree18fbb25a673a29f99d90326af0502a014cc64dc3
parentda178c9dbd46c0c067e9d44355687080939678a1 (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.c10
-rw-r--r--src/idle-server-connection.c85
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