Add helper API for using Purple TLS subsystem with GTlsConnections purple-ssl-to-gio

Tue, 16 Feb 2016 17:48:03 -0600

author
Mike Ruprecht <cmaiku@gmail.com>
date
Tue, 16 Feb 2016 17:48:03 -0600
branch
purple-ssl-to-gio
changeset 37621
2a2f1068e0f0
parent 37620
5467197bd084
child 37622
14d1273cae74

Add helper API for using Purple TLS subsystem with GTlsConnections

The functions added by this patch allow easily connecting the Purple
TLS certificate subsystem to GTlsConnections. This handles validating
against manually trusted certificates, so TLS connections can continue.

libpurple/tls-certificate.c file | annotate | diff | comparison | revisions
libpurple/tls-certificate.h file | annotate | diff | comparison | revisions
--- a/libpurple/tls-certificate.c	Tue Feb 16 20:47:44 2016 -0600
+++ b/libpurple/tls-certificate.c	Tue Feb 16 17:48:03 2016 -0600
@@ -192,3 +192,88 @@
 	return ret;
 }
 
+/* Called when a GTlsConnection (which this handler has been connected to)
+ *   has an error validating its certificate.
+ * Returns TRUE if the certificate is already trusted, so the connection
+ *   can continue.
+ * Returns FALSE if the certificate is not trusted, causing the
+ *   connection's handshake to fail.
+ */
+static gboolean
+accept_certificate_cb(GTlsConnection *conn, GTlsCertificate *peer_cert,
+		GTlsCertificateFlags errors, gpointer user_data)
+{
+	GTlsCertificate *trusted_cert;
+	GSocketConnectable *connectable;
+	const gchar *identity;
+
+	g_return_val_if_fail(G_IS_TLS_CLIENT_CONNECTION(conn), FALSE);
+	g_return_val_if_fail(G_IS_TLS_CERTIFICATE(peer_cert), FALSE);
+
+	/* Get the certificate identity from the GTlsClientConnection */
+
+	connectable = g_tls_client_connection_get_server_identity(
+			G_TLS_CLIENT_CONNECTION(conn));
+
+	g_return_val_if_fail(G_IS_SOCKET_CONNECTABLE(connectable), FALSE);
+
+	/* identity is owned by the connectable */
+	if (G_IS_NETWORK_ADDRESS(connectable)) {
+		identity = g_network_address_get_hostname(
+				G_NETWORK_ADDRESS(connectable));
+	} else if (G_IS_NETWORK_SERVICE(connectable)) {
+		identity = g_network_service_get_domain(
+				G_NETWORK_SERVICE(connectable));
+	} else {
+		g_return_val_if_reached(FALSE);
+	}
+
+	/* See if a trusted certificate matching the peer certificate exists */
+
+	trusted_cert = purple_tls_certificate_new_from_id(identity, NULL);
+
+	if (trusted_cert != NULL &&
+			g_tls_certificate_is_same(peer_cert, trusted_cert)) {
+		/* It's manually trusted. Accept certificate */
+		g_object_unref(trusted_cert);
+		return TRUE;
+	}
+
+	/* Certificate failed and isn't trusted. Fail certificate */
+
+	g_clear_object(&trusted_cert);
+	return FALSE;
+}
+
+gpointer
+purple_tls_certificate_attach_to_tls_connection(GTlsConnection *conn)
+{
+	return g_object_connect(conn, "signal::accept-certificate",
+			accept_certificate_cb, NULL, NULL);
+}
+
+/* Called when GSocketClient signals an event.
+ * Calls purple_tls_certificate_attach_to_tls_connection() on the client's
+ * connection when it's about to handshake.
+ */
+static void
+socket_client_event_cb(GSocketClient *client, GSocketClientEvent event,
+		GSocketConnectable *connectable, GIOStream *connection,
+		gpointer user_data)
+{
+	if (event == G_SOCKET_CLIENT_TLS_HANDSHAKING) {
+		/* Attach libpurple's certificate subsystem to the
+		 * GTlsConnection right before it starts the handshake
+		 */
+		purple_tls_certificate_attach_to_tls_connection(
+				G_TLS_CONNECTION(connection));
+	}
+}
+
+gpointer
+purple_tls_certificate_attach_to_socket_client(GSocketClient *client)
+{
+	return g_object_connect(client, "signal::event",
+			socket_client_event_cb, NULL, NULL);
+}
+
--- a/libpurple/tls-certificate.h	Tue Feb 16 20:47:44 2016 -0600
+++ b/libpurple/tls-certificate.h	Tue Feb 16 17:48:03 2016 -0600
@@ -92,6 +92,32 @@
 gboolean
 purple_tls_certificate_distrust(const gchar *id, GError **error);
 
+
+/**
+ * purple_tls_certificate_attach_to_tls_connection:
+ * @conn: #GTlsConnection to connect to
+ *
+ * Connects the Purple TLS certificate subsystem to @conn so it will accept
+ * certificates trusted by purple_tls_certificate_trust() and friends.
+ *
+ * Returns: @conn, similar to g_object_connect()
+ */
+gpointer
+purple_tls_certificate_attach_to_tls_connection(GTlsConnection *conn);
+
+/**
+ * purple_tls_certificate_attach_to_socket_client:
+ * @client: #GSocketClient to connect to
+ *
+ * Connects the Purple TLS certificate subsystem to @client so any TLS
+ * connections it creates will accept certificates trusted by
+ * purple_tls_certificate_trust() and friends.
+ *
+ * Returns: @client, similar to g_object_connect()
+ */
+gpointer
+purple_tls_certificate_attach_to_socket_client(GSocketClient *client);
+
 G_END_DECLS
 
 #endif /* _PURPLE_TLS_CERTIFICATE_H */

mercurial