summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server-tls-channel.c308
-rw-r--r--src/server-tls-channel.h71
-rw-r--r--src/server-tls-manager.c585
-rw-r--r--src/server-tls-manager.h74
-rw-r--r--src/tls-certificate.c344
-rw-r--r--src/tls-certificate.h66
6 files changed, 1448 insertions, 0 deletions
diff --git a/src/server-tls-channel.c b/src/server-tls-channel.c
new file mode 100644
index 0000000..552b315
--- /dev/null
+++ b/src/server-tls-channel.c
@@ -0,0 +1,308 @@
+/*
+ * server-tls-channel.c - Source for IdleServerTLSChannel
+ * Copyright (C) 2010 Collabora Ltd.
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "server-tls-channel.h"
+
+#include <telepathy-glib/telepathy-glib.h>
+#include <telepathy-glib/telepathy-glib-dbus.h>
+
+#include <wocky/wocky.h>
+
+#define DEBUG_FLAG IDLE_DEBUG_TLS
+#include "debug.h"
+#include "connection.h"
+#include "tls-certificate.h"
+
+G_DEFINE_TYPE_WITH_CODE (IdleServerTLSChannel, idle_server_tls_channel,
+ TP_TYPE_BASE_CHANNEL,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_SERVER_TLS_CONNECTION,
+ NULL));
+
+static void idle_server_tls_channel_close (TpBaseChannel *base);
+
+enum {
+ /* server TLS channel iface */
+ PROP_SERVER_CERTIFICATE = 1,
+ PROP_HOSTNAME,
+ PROP_REFERENCE_IDENTITIES,
+
+ /* not exported */
+ PROP_TLS_SESSION,
+
+ NUM_PROPERTIES
+};
+
+struct _IdleServerTLSChannelPrivate {
+ WockyTLSSession *tls_session;
+
+ IdleTLSCertificate *server_cert;
+ gchar *server_cert_path;
+ gchar *hostname;
+ GStrv reference_identities;
+
+ gboolean dispose_has_run;
+};
+
+static void
+idle_server_tls_channel_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdleServerTLSChannel *self = IDLE_SERVER_TLS_CHANNEL (object);
+
+ switch (property_id)
+ {
+ case PROP_SERVER_CERTIFICATE:
+ g_value_set_boxed (value, self->priv->server_cert_path);
+ break;
+ case PROP_HOSTNAME:
+ g_value_set_string (value, self->priv->hostname);
+ break;
+ case PROP_REFERENCE_IDENTITIES:
+ g_value_set_boxed (value, self->priv->reference_identities);
+ break;
+ case PROP_TLS_SESSION:
+ g_value_set_object (value, self->priv->tls_session);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+idle_server_tls_channel_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdleServerTLSChannel *self = IDLE_SERVER_TLS_CHANNEL (object);
+
+ switch (property_id)
+ {
+ case PROP_TLS_SESSION:
+ self->priv->tls_session = g_value_dup_object (value);
+ break;
+ case PROP_HOSTNAME:
+ self->priv->hostname = g_value_dup_string (value);
+ break;
+ case PROP_REFERENCE_IDENTITIES:
+ self->priv->reference_identities = g_value_dup_boxed (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+idle_server_tls_channel_finalize (GObject *object)
+{
+ IdleServerTLSChannel *self = IDLE_SERVER_TLS_CHANNEL (object);
+
+ DEBUG ("Finalize TLS channel");
+
+ g_free (self->priv->server_cert_path);
+ g_free (self->priv->hostname);
+ g_strfreev (self->priv->reference_identities);
+
+ G_OBJECT_CLASS (idle_server_tls_channel_parent_class)->finalize (object);
+}
+
+static void
+idle_server_tls_channel_dispose (GObject *object)
+{
+ IdleServerTLSChannel *self = IDLE_SERVER_TLS_CHANNEL (object);
+
+ if (self->priv->dispose_has_run)
+ return;
+
+ DEBUG ("Dispose TLS channel");
+
+ self->priv->dispose_has_run = TRUE;
+
+ tp_clear_object (&self->priv->server_cert);
+ tp_clear_object (&self->priv->tls_session);
+
+ G_OBJECT_CLASS (idle_server_tls_channel_parent_class)->dispose (object);
+}
+
+static const gchar *
+cert_type_to_str (WockyTLSCertType type)
+{
+ const gchar *retval = NULL;
+
+ switch (type)
+ {
+ case WOCKY_TLS_CERT_TYPE_X509:
+ retval = "x509";
+ break;
+ case WOCKY_TLS_CERT_TYPE_OPENPGP:
+ retval = "pgp";
+ break;
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+static void
+idle_server_tls_channel_constructed (GObject *object)
+{
+ IdleServerTLSChannel *self = IDLE_SERVER_TLS_CHANNEL (object);
+ TpBaseChannel *base = TP_BASE_CHANNEL (self);
+ TpBaseConnection *base_conn = tp_base_channel_get_connection (base);
+ void (*chain_up) (GObject *) =
+ G_OBJECT_CLASS (idle_server_tls_channel_parent_class)->constructed;
+ WockyTLSCertType cert_type;
+ const gchar *path;
+ gchar *cert_object_path;
+ GPtrArray *certificates;
+
+ if (chain_up != NULL)
+ chain_up (object);
+
+ tp_base_channel_register (base);
+
+ /* create the TLS certificate object */
+ path = tp_base_channel_get_object_path (base);
+ cert_object_path = g_strdup_printf ("%s/TLSCertificateObject", path);
+ certificates = wocky_tls_session_get_peers_certificate (
+ self->priv->tls_session, &cert_type);
+
+ self->priv->server_cert = g_object_new (IDLE_TYPE_TLS_CERTIFICATE,
+ "object-path", cert_object_path,
+ "certificate-chain-data", certificates,
+ "certificate-type", cert_type_to_str (cert_type),
+ "dbus-daemon", IDLE_CONNECTION (base_conn)->daemon,
+ NULL);
+ self->priv->server_cert_path = cert_object_path;
+
+ DEBUG ("Server TLS channel constructed at %s", path);
+}
+
+static void
+idle_server_tls_channel_fill_immutable_properties (
+ TpBaseChannel *chan,
+ GHashTable *properties)
+{
+ TP_BASE_CHANNEL_CLASS (idle_server_tls_channel_parent_class)
+ ->fill_immutable_properties (chan, properties);
+
+ tp_dbus_properties_mixin_fill_properties_hash (
+ G_OBJECT (chan), properties,
+ TP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION, "ServerCertificate",
+ TP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION, "Hostname",
+ TP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION, "ReferenceIdentities",
+ NULL);
+}
+
+static gchar *
+idle_server_tls_channel_get_object_path_suffix (TpBaseChannel *base)
+{
+ static guint count = 0;
+
+ return g_strdup_printf ("ServerTLSChannel%u", ++count);
+}
+
+static void
+idle_server_tls_channel_init (IdleServerTLSChannel *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ IDLE_TYPE_SERVER_TLS_CHANNEL, IdleServerTLSChannelPrivate);
+}
+
+static void
+idle_server_tls_channel_class_init (IdleServerTLSChannelClass *klass)
+{
+ static TpDBusPropertiesMixinPropImpl server_tls_props[] = {
+ { "ServerCertificate", "server-certificate", NULL },
+ { "Hostname", "hostname", NULL },
+ { "ReferenceIdentities", "reference-identities", NULL },
+ { NULL }
+ };
+
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (IdleServerTLSChannelPrivate));
+
+ oclass->get_property = idle_server_tls_channel_get_property;
+ oclass->set_property = idle_server_tls_channel_set_property;
+ oclass->dispose = idle_server_tls_channel_dispose;
+ oclass->finalize = idle_server_tls_channel_finalize;
+ oclass->constructed = idle_server_tls_channel_constructed;
+
+ base_class->channel_type = TP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION;
+ base_class->target_handle_type = TP_HANDLE_TYPE_NONE;
+ base_class->fill_immutable_properties =
+ idle_server_tls_channel_fill_immutable_properties;
+ base_class->get_object_path_suffix =
+ idle_server_tls_channel_get_object_path_suffix;
+ base_class->close = idle_server_tls_channel_close;
+
+ pspec = g_param_spec_boxed ("server-certificate", "Server certificate path",
+ "The object path of the server certificate.",
+ DBUS_TYPE_G_OBJECT_PATH,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_SERVER_CERTIFICATE, pspec);
+
+ pspec = g_param_spec_string ("hostname", "The hostname to be verified",
+ "The hostname which should be certified by the server certificate.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_HOSTNAME, pspec);
+
+ pspec = g_param_spec_boxed ("reference-identities",
+ "The various identities to check the certificate against",
+ "The server certificate identity should match one of these identities.",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_REFERENCE_IDENTITIES, pspec);
+
+ pspec = g_param_spec_object ("tls-session", "The WockyTLSSession",
+ "The WockyTLSSession object containing the TLS information",
+ WOCKY_TYPE_TLS_SESSION,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_TLS_SESSION, pspec);
+
+ tp_dbus_properties_mixin_implement_interface (oclass,
+ TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION,
+ tp_dbus_properties_mixin_getter_gobject_properties, NULL,
+ server_tls_props);
+}
+
+static void
+idle_server_tls_channel_close (TpBaseChannel *base)
+{
+ DEBUG ("Close() called on the TLS channel %p", base);
+ tp_base_channel_destroyed (base);
+}
+
+IdleTLSCertificate *
+idle_server_tls_channel_get_certificate (IdleServerTLSChannel *self)
+{
+ return self->priv->server_cert;
+}
diff --git a/src/server-tls-channel.h b/src/server-tls-channel.h
new file mode 100644
index 0000000..47b8474
--- /dev/null
+++ b/src/server-tls-channel.h
@@ -0,0 +1,71 @@
+/*
+ * server-tls-channel.h - Header for IdleServerTLSChannel
+ * Copyright (C) 2010 Collabora Ltd.
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __IDLE_SERVER_TLS_CHANNEL_H__
+#define __IDLE_SERVER_TLS_CHANNEL_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+#include <extensions/extensions.h>
+
+#include "tls-certificate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _IdleServerTLSChannelPrivate IdleServerTLSChannelPrivate;
+typedef struct _IdleServerTLSChannelClass IdleServerTLSChannelClass;
+typedef struct _IdleServerTLSChannel IdleServerTLSChannel;
+
+struct _IdleServerTLSChannelClass {
+ TpBaseChannelClass base_class;
+};
+
+struct _IdleServerTLSChannel {
+ TpBaseChannel parent;
+
+ IdleServerTLSChannelPrivate *priv;
+};
+
+GType idle_server_tls_channel_get_type (void);
+
+#define IDLE_TYPE_SERVER_TLS_CHANNEL \
+ (idle_server_tls_channel_get_type ())
+#define IDLE_SERVER_TLS_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), IDLE_TYPE_SERVER_TLS_CHANNEL, \
+ IdleServerTLSChannel))
+#define IDLE_SERVER_TLS_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), IDLE_TYPE_SERVER_TLS_CHANNEL, \
+ IdleServerTLSChannelClass))
+#define IDLE_IS_SERVER_TLS_CHANNEL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), IDLE_TYPE_SERVER_TLS_CHANNEL))
+#define IDLE_IS_SERVER_TLS_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), IDLE_TYPE_SERVER_TLS_CHANNEL))
+#define IDLE_SERVER_TLS_CHANNEL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), IDLE_TYPE_SERVER_TLS_CHANNEL,\
+ IdleServerTLSChannelClass))
+
+IdleTLSCertificate * idle_server_tls_channel_get_certificate (
+ IdleServerTLSChannel *self);
+
+G_END_DECLS
+
+#endif /* #ifndef __IDLE_SERVER_TLS_CHANNEL_H__*/
diff --git a/src/server-tls-manager.c b/src/server-tls-manager.c
new file mode 100644
index 0000000..e32c991
--- /dev/null
+++ b/src/server-tls-manager.c
@@ -0,0 +1,585 @@
+/*
+ * server-tls-manager.c - Source for IdleServerTLSManager
+ * Copyright (C) 2010 Collabora Ltd.
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "server-tls-manager.h"
+
+#include <telepathy-glib/telepathy-glib.h>
+#include <telepathy-glib/telepathy-glib-dbus.h>
+
+#define DEBUG_FLAG IDLE_DEBUG_TLS
+#include "debug.h"
+#include "gabble/caps-channel-manager.h"
+#include "connection.h"
+#include "server-tls-channel.h"
+#include "util.h"
+
+#include "extensions/extensions.h"
+
+#include <wocky/wocky.h>
+
+static void channel_manager_iface_init (gpointer, gpointer);
+
+G_DEFINE_TYPE_WITH_CODE (IdleServerTLSManager, idle_server_tls_manager,
+ WOCKY_TYPE_TLS_HANDLER,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER,
+ channel_manager_iface_init);
+ G_IMPLEMENT_INTERFACE (IDLE_TYPE_CAPS_CHANNEL_MANAGER,
+ NULL));
+
+enum {
+ PROP_CONNECTION = 1,
+ PROP_INTERACTIVE_TLS,
+ NUM_PROPERTIES
+};
+
+struct _IdleServerTLSManagerPrivate {
+ /* Properties */
+ IdleConnection *connection;
+ gboolean interactive_tls;
+
+ /* Current operation data */
+ gchar *peername;
+ GStrv reference_identities;
+ WockyTLSSession *tls_session;
+ IdleServerTLSChannel *channel;
+ GSimpleAsyncResult *async_result;
+
+ /* List of owned TpBaseChannel not yet closed by the client */
+ GList *completed_channels;
+
+ gboolean dispose_has_run;
+};
+
+#define chainup ((WockyTLSHandlerClass *) \
+ idle_server_tls_manager_parent_class)
+
+static void
+idle_server_tls_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ g_value_set_object (value, self->priv->connection);
+ break;
+ case PROP_INTERACTIVE_TLS:
+ g_value_set_boolean (value, self->priv->interactive_tls);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+idle_server_tls_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
+
+ switch (property_id)
+ {
+ case PROP_CONNECTION:
+ self->priv->connection = g_value_dup_object (value);
+ break;
+ case PROP_INTERACTIVE_TLS:
+ self->priv->interactive_tls = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+close_all (IdleServerTLSManager *self)
+{
+ GList *l;
+
+ if (self->priv->channel != NULL)
+ tp_base_channel_close (TP_BASE_CHANNEL (self->priv->channel));
+
+ l = self->priv->completed_channels;
+ while (l != NULL)
+ {
+ /* use a temporary variable as the ::closed callback will delete
+ * the link from the list. */
+ GList *next = l->next;
+
+ tp_base_channel_close (l->data);
+
+ l = next;
+ }
+}
+
+static void
+connection_status_changed_cb (IdleConnection *conn,
+ guint status,
+ guint reason,
+ gpointer user_data)
+{
+ IdleServerTLSManager *self = user_data;
+
+ DEBUG ("Connection status changed, now %d", status);
+
+ if (status == TP_CONNECTION_STATUS_DISCONNECTED)
+ {
+ close_all (self);
+ tp_clear_object (&self->priv->connection);
+ }
+}
+
+static void
+complete_verify (IdleServerTLSManager *self)
+{
+ /* Move channel to a list until a client Close() it */
+ if (self->priv->channel != NULL)
+ {
+ self->priv->completed_channels = g_list_prepend (
+ self->priv->completed_channels,
+ g_object_ref (self->priv->channel));
+ }
+
+ g_simple_async_result_complete (self->priv->async_result);
+
+ /* Reset to initial state */
+ tp_clear_pointer (&self->priv->peername, g_free);
+ tp_clear_pointer (&self->priv->reference_identities, g_strfreev);
+ g_clear_object (&self->priv->tls_session);
+ g_clear_object (&self->priv->channel);
+ g_clear_object (&self->priv->async_result);
+}
+
+static void
+verify_fallback_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdleServerTLSManager *self = (IdleServerTLSManager *) source;
+ GError *error = NULL;
+
+ if (!chainup->verify_finish_func (WOCKY_TLS_HANDLER (self), result, &error))
+ g_simple_async_result_take_error (self->priv->async_result, error);
+
+ complete_verify (self);
+}
+
+static void
+server_tls_channel_closed_cb (IdleServerTLSChannel *channel,
+ gpointer user_data)
+{
+ IdleServerTLSManager *self = user_data;
+
+ DEBUG ("Server TLS channel closed.");
+
+ if (channel == self->priv->channel)
+ {
+ /* fallback to the old-style non interactive TLS verification */
+ DEBUG ("Channel closed, but unhandled, falling back...");
+
+ chainup->verify_async_func (WOCKY_TLS_HANDLER (self),
+ self->priv->tls_session, self->priv->peername,
+ self->priv->reference_identities, verify_fallback_cb, NULL);
+
+ self->priv->channel = NULL;
+ }
+ else
+ {
+ GList *l;
+
+ l = g_list_find (self->priv->completed_channels, channel);
+ g_assert (l != NULL);
+
+ self->priv->completed_channels = g_list_delete_link (
+ self->priv->completed_channels, l);
+ }
+
+ tp_channel_manager_emit_channel_closed_for_object (self,
+ TP_EXPORTABLE_CHANNEL (channel));
+ g_object_unref (channel);
+}
+
+GQuark
+idle_server_tls_error_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (!quark)
+ quark = g_quark_from_static_string ("server-tls-error");
+
+ return quark;
+}
+
+static void
+tls_certificate_accepted_cb (IdleTLSCertificate *certificate,
+ gpointer user_data)
+{
+ IdleServerTLSManager *self = user_data;
+
+ DEBUG ("TLS certificate accepted");
+
+ complete_verify (self);
+}
+
+static void
+tls_certificate_rejected_cb (IdleTLSCertificate *certificate,
+ GPtrArray *rejections,
+ gpointer user_data)
+{
+ IdleServerTLSManager *self = user_data;
+
+ DEBUG ("TLS certificate rejected with rejections %p, length %u.",
+ rejections, rejections->len);
+
+ g_simple_async_result_set_error (self->priv->async_result,
+ IDLE_SERVER_TLS_ERROR, 0, "TLS certificate rejected");
+
+ complete_verify (self);
+}
+
+static void
+extend_string_ptr_array (GPtrArray *array,
+ GStrv new_elements)
+{
+ gint i;
+
+ if (new_elements != NULL)
+ {
+ for (i = 0; new_elements[i] != NULL; i++)
+ {
+ if (!tp_str_empty (new_elements[i]))
+ g_ptr_array_add (array, g_strdup (new_elements[i]));
+ }
+ }
+}
+
+static void
+fill_reference_identities (IdleServerTLSManager *self,
+ const gchar *peername,
+ GStrv original_extra_identities)
+{
+ GPtrArray *identities;
+ gchar *connect_server = NULL;
+ gchar *explicit_server = NULL;
+ GStrv extra_certificate_identities = NULL;
+
+ g_return_if_fail (self->priv->reference_identities == NULL);
+
+ g_object_get (self->priv->connection,
+ "connect-server", &connect_server,
+ "explicit-server", &explicit_server,
+ "extra-certificate-identities", &extra_certificate_identities,
+ NULL);
+
+ identities = g_ptr_array_new ();
+
+ /* The peer name, i.e, the domain part of the JID */
+ g_ptr_array_add (identities, g_strdup (peername));
+
+ /* The extra identities that the caller of verify_async() passed */
+ extend_string_ptr_array (identities, original_extra_identities);
+
+ /* The explicitly overridden server (if in use) */
+ if (!tp_str_empty (explicit_server) &&
+ !tp_strdiff (connect_server, explicit_server))
+ {
+ g_ptr_array_add (identities, g_strdup (explicit_server));
+ }
+
+ /* Extra identities added to the account as a result of user choices */
+ extend_string_ptr_array (identities, extra_certificate_identities);
+
+ /* Null terminate, since this is a gchar** */
+ g_ptr_array_add (identities, NULL);
+
+ self->priv->reference_identities = (GStrv) g_ptr_array_free (identities,
+ FALSE);
+
+ g_strfreev (extra_certificate_identities);
+ g_free (explicit_server);
+ g_free (connect_server);
+}
+
+static void
+idle_server_tls_manager_verify_async (WockyTLSHandler *handler,
+ WockyTLSSession *tls_session,
+ const gchar *peername,
+ GStrv extra_identities,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (handler);
+ IdleTLSCertificate *certificate;
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (self->priv->async_result == NULL);
+
+ DEBUG ("verify_async() called on the IdleServerTLSManager.");
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback, user_data, idle_server_tls_manager_verify_async);
+
+ if (self->priv->connection == NULL)
+ {
+ DEBUG ("connection already went away; failing immediately");
+ g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_CANCELLED,
+ "The Telepathy connection has already been disconnected");
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+ return;
+ }
+
+ self->priv->async_result = result;
+
+ fill_reference_identities (self, peername, extra_identities);
+
+ if (!self->priv->interactive_tls)
+ {
+ DEBUG ("ignore-ssl-errors is set, fallback to non-interactive "
+ "verification.");
+
+ chainup->verify_async_func (WOCKY_TLS_HANDLER (self), tls_session,
+ peername, self->priv->reference_identities, verify_fallback_cb, NULL);
+
+ return;
+ }
+
+ self->priv->tls_session = g_object_ref (tls_session);
+ self->priv->peername = g_strdup (peername);
+
+ self->priv->channel = g_object_new (IDLE_TYPE_SERVER_TLS_CHANNEL,
+ "connection", self->priv->connection,
+ "tls-session", tls_session,
+ "hostname", peername,
+ "reference-identities", self->priv->reference_identities,
+ NULL);
+
+ g_signal_connect (self->priv->channel, "closed",
+ G_CALLBACK (server_tls_channel_closed_cb), self);
+
+ certificate = idle_server_tls_channel_get_certificate (self->priv->channel);
+
+ g_signal_connect (certificate, "accepted",
+ G_CALLBACK (tls_certificate_accepted_cb), self);
+ g_signal_connect (certificate, "rejected",
+ G_CALLBACK (tls_certificate_rejected_cb), self);
+
+ /* emit NewChannel on the ChannelManager iface */
+ tp_channel_manager_emit_new_channel (self,
+ (TpExportableChannel *) self->priv->channel, NULL);
+}
+
+static gboolean
+idle_server_tls_manager_verify_finish (WockyTLSHandler *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ wocky_implement_finish_void (self, idle_server_tls_manager_verify_async);
+}
+
+static void
+idle_server_tls_manager_init (IdleServerTLSManager *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ IDLE_TYPE_SERVER_TLS_MANAGER, IdleServerTLSManagerPrivate);
+}
+
+static void
+idle_server_tls_manager_dispose (GObject *object)
+{
+ IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
+
+ DEBUG ("%p", self);
+
+ if (self->priv->dispose_has_run)
+ return;
+
+ self->priv->dispose_has_run = TRUE;
+
+ tp_clear_object (&self->priv->tls_session);
+ tp_clear_object (&self->priv->connection);
+
+ G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->dispose (object);
+}
+
+static void
+idle_server_tls_manager_finalize (GObject *object)
+{
+ IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
+
+ DEBUG ("%p", self);
+
+ close_all (self);
+
+ g_free (self->priv->peername);
+ g_strfreev (self->priv->reference_identities);
+
+ G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->finalize (object);
+}
+
+static void
+idle_server_tls_manager_constructed (GObject *object)
+{
+ IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (object);
+ void (*chain_up) (GObject *) =
+ G_OBJECT_CLASS (idle_server_tls_manager_parent_class)->constructed;
+
+ if (chain_up != NULL)
+ chain_up (object);
+
+ DEBUG ("Server TLS Manager constructed");
+
+ idle_signal_connect_weak (self->priv->connection, "status-changed",
+ G_CALLBACK (connection_status_changed_cb), object);
+}
+
+static void
+idle_server_tls_manager_class_init (IdleServerTLSManagerClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ WockyTLSHandlerClass *hclass = WOCKY_TLS_HANDLER_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (IdleServerTLSManagerPrivate));
+
+ oclass->dispose = idle_server_tls_manager_dispose;
+ oclass->finalize = idle_server_tls_manager_finalize;
+ oclass->constructed = idle_server_tls_manager_constructed;
+ oclass->set_property = idle_server_tls_manager_set_property;
+ oclass->get_property = idle_server_tls_manager_get_property;
+
+ hclass->verify_async_func = idle_server_tls_manager_verify_async;
+ hclass->verify_finish_func = idle_server_tls_manager_verify_finish;
+
+ pspec = g_param_spec_object ("connection", "IdleConnection object",
+ "Idle connection object that owns this manager.",
+ IDLE_TYPE_CONNECTION,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_CONNECTION, pspec);
+
+ pspec = g_param_spec_boolean ("interactive-tls", "Interactive TLS setting",
+ "Whether interactive TLS certificate verification is enabled.",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_INTERACTIVE_TLS, pspec);
+}
+
+static void
+idle_server_tls_manager_foreach_channel (TpChannelManager *manager,
+ TpExportableChannelFunc func,
+ gpointer user_data)
+{
+ IdleServerTLSManager *self = IDLE_SERVER_TLS_MANAGER (manager);
+ GList *l;
+
+ if (self->priv->channel != NULL)
+ func (TP_EXPORTABLE_CHANNEL (self->priv->channel), user_data);
+
+ for (l = self->priv->completed_channels; l != NULL; l = l->next)
+ {
+ func (l->data, user_data);
+ }
+}
+
+static void
+channel_manager_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpChannelManagerIface *iface = g_iface;
+
+ iface->foreach_channel = idle_server_tls_manager_foreach_channel;
+
+ /* these channels are not requestable. */
+ iface->ensure_channel = NULL;
+ iface->create_channel = NULL;
+ iface->request_channel = NULL;
+ iface->foreach_channel_class = NULL;
+}
+
+static TpConnectionStatusReason
+cert_reject_reason_to_conn_reason (TpTLSCertificateRejectReason tls_reason)
+{
+ #define EASY_CASE(x) \
+ case TP_TLS_CERTIFICATE_REJECT_REASON_ ## x: \
+ return TP_CONNECTION_STATUS_REASON_CERT_ ## x;
+
+ switch (tls_reason)
+ {
+ EASY_CASE (UNTRUSTED);
+ EASY_CASE (EXPIRED);
+ EASY_CASE (NOT_ACTIVATED);
+ EASY_CASE (FINGERPRINT_MISMATCH);
+ EASY_CASE (HOSTNAME_MISMATCH);
+ EASY_CASE (SELF_SIGNED);
+ EASY_CASE (REVOKED);
+ EASY_CASE (INSECURE);
+ EASY_CASE (LIMIT_EXCEEDED);
+
+ case TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN:
+ default:
+ return TP_CONNECTION_STATUS_REASON_CERT_OTHER_ERROR;
+ }
+
+ #undef EASY_CASE
+}
+
+void
+idle_server_tls_manager_get_rejection_details (IdleServerTLSManager *self,
+ gchar **dbus_error,
+ GHashTable **details,
+ TpConnectionStatusReason *reason)
+{
+ IdleTLSCertificate *certificate;
+ GPtrArray *rejections;
+ GValueArray *rejection;
+ TpTLSCertificateRejectReason tls_reason;
+
+ /* We probably want the rejection details of last completed operation */
+ g_return_if_fail (self->priv->completed_channels != NULL);
+
+ certificate = idle_server_tls_channel_get_certificate (
+ self->priv->completed_channels->data);
+ g_object_get (certificate,
+ "rejections", &rejections,
+ NULL);
+
+ /* we return 'Invalid_Argument' if Reject() is called with zero
+ * reasons, so if this fails something bad happened.
+ */
+ g_assert (rejections->len >= 1);
+
+ rejection = g_ptr_array_index (rejections, 0);
+
+ tls_reason = g_value_get_uint (g_value_array_get_nth (rejection, 0));
+ *dbus_error = g_value_dup_string (g_value_array_get_nth (rejection, 1));
+ *details = g_value_dup_boxed (g_value_array_get_nth (rejection, 2));
+
+ *reason = cert_reject_reason_to_conn_reason (tls_reason);
+
+ tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ &rejections);
+}
diff --git a/src/server-tls-manager.h b/src/server-tls-manager.h
new file mode 100644
index 0000000..a584e9f
--- /dev/null
+++ b/src/server-tls-manager.h
@@ -0,0 +1,74 @@
+/*
+ * server-tls-manager.h - Header for IdleServerTLSManager
+ * Copyright (C) 2010 Collabora Ltd.
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __IDLE_SERVER_TLS_MANAGER_H__
+#define __IDLE_SERVER_TLS_MANAGER_H__
+
+#include <glib-object.h>
+#include <wocky/wocky.h>
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "extensions/extensions.h"
+
+G_BEGIN_DECLS
+
+typedef struct _IdleServerTLSManager IdleServerTLSManager;
+typedef struct _IdleServerTLSManagerClass IdleServerTLSManagerClass;
+typedef struct _IdleServerTLSManagerPrivate IdleServerTLSManagerPrivate;
+
+struct _IdleServerTLSManagerClass {
+ WockyTLSHandlerClass parent_class;
+};
+
+struct _IdleServerTLSManager {
+ WockyTLSHandler parent;
+ IdleServerTLSManagerPrivate *priv;
+};
+
+GType idle_server_tls_manager_get_type (void);
+
+#define IDLE_TYPE_SERVER_TLS_MANAGER \
+ (idle_server_tls_manager_get_type ())
+#define IDLE_SERVER_TLS_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), IDLE_TYPE_SERVER_TLS_MANAGER, \
+ IdleServerTLSManager))
+#define IDLE_SERVER_TLS_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), IDLE_TYPE_SERVER_TLS_MANAGER, \
+ IdleServerTLSManagerClass))
+#define IDLE_IS_SERVER_TLS_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), IDLE_TYPE_SERVER_TLS_MANAGER))
+#define IDLE_IS_SERVER_TLS_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), IDLE_TYPE_SERVER_TLS_MANAGER))
+#define IDLE_SERVER_TLS_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), IDLE_TYPE_SERVER_TLS_MANAGER, \
+ IdleServerTLSManagerClass))
+
+#define IDLE_SERVER_TLS_ERROR idle_server_tls_error_quark ()
+GQuark idle_server_tls_error_quark (void);
+
+void idle_server_tls_manager_get_rejection_details (
+ IdleServerTLSManager *self,
+ gchar **dbus_error,
+ GHashTable **details,
+ TpConnectionStatusReason *reason);
+
+G_END_DECLS
+
+#endif /* #ifndef __IDLE_SERVER_TLS_MANAGER_H__ */
diff --git a/src/tls-certificate.c b/src/tls-certificate.c
new file mode 100644
index 0000000..a0abfa6
--- /dev/null
+++ b/src/tls-certificate.c
@@ -0,0 +1,344 @@
+/*
+ * tls-certificate.c - Source for IdleTLSCertificate
+ * Copyright (C) 2010 Collabora Ltd.
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "tls-certificate.h"
+
+#include <telepathy-glib/telepathy-glib.h>
+#include <telepathy-glib/telepathy-glib-dbus.h>
+
+#define DEBUG_FLAG IDLE_DEBUG_TLS
+#include "debug.h"
+
+static void
+tls_certificate_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (IdleTLSCertificate,
+ idle_tls_certificate,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_AUTHENTICATION_TLS_CERTIFICATE,
+ tls_certificate_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+ tp_dbus_properties_mixin_iface_init);)
+
+struct _IdleTLSCertificatePrivate {
+ gchar *object_path;
+
+ gchar *cert_type;
+ TpTLSCertificateState cert_state;
+
+ GPtrArray *rejections;
+ GPtrArray *cert_data;
+
+ TpDBusDaemon *daemon;
+
+ gboolean dispose_has_run;
+};
+
+enum {
+ PROP_OBJECT_PATH = 1,
+ PROP_STATE,
+ PROP_REJECTIONS,
+ PROP_CERTIFICATE_TYPE,
+ PROP_CERTIFICATE_CHAIN_DATA,
+
+ /* not exported */
+ PROP_DBUS_DAEMON,
+
+ NUM_PROPERTIES
+};
+
+static void
+idle_tls_certificate_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdleTLSCertificate *self = IDLE_TLS_CERTIFICATE (object);
+
+ switch (property_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, self->priv->object_path);
+ break;
+ case PROP_STATE:
+ g_value_set_uint (value, self->priv->cert_state);
+ break;
+ case PROP_REJECTIONS:
+ g_value_set_boxed (value, self->priv->rejections);
+ break;
+ case PROP_CERTIFICATE_TYPE:
+ g_value_set_string (value, self->priv->cert_type);
+ break;
+ case PROP_CERTIFICATE_CHAIN_DATA:
+ g_value_set_boxed (value, self->priv->cert_data);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+idle_tls_certificate_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdleTLSCertificate *self = IDLE_TLS_CERTIFICATE (object);
+
+ switch (property_id)
+ {
+ case PROP_OBJECT_PATH:
+ self->priv->object_path = g_value_dup_string (value);
+ break;
+ case PROP_CERTIFICATE_TYPE:
+ self->priv->cert_type = g_value_dup_string (value);
+ break;
+ case PROP_CERTIFICATE_CHAIN_DATA:
+ self->priv->cert_data = g_value_dup_boxed (value);
+ break;
+ case PROP_DBUS_DAEMON:
+ self->priv->daemon = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, value);
+ break;
+ }
+}
+
+static void
+idle_tls_certificate_finalize (GObject *object)
+{
+ IdleTLSCertificate *self = IDLE_TLS_CERTIFICATE (object);
+
+ tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ &self->priv->rejections);
+
+ g_free (self->priv->object_path);
+ g_free (self->priv->cert_type);
+ g_ptr_array_unref (self->priv->cert_data);
+
+ G_OBJECT_CLASS (idle_tls_certificate_parent_class)->finalize (object);
+}
+
+static void
+idle_tls_certificate_dispose (GObject *object)
+{
+ IdleTLSCertificate *self = IDLE_TLS_CERTIFICATE (object);
+
+ if (self->priv->dispose_has_run)
+ return;
+
+ self->priv->dispose_has_run = TRUE;
+
+ tp_clear_object (&self->priv->daemon);
+
+ G_OBJECT_CLASS (idle_tls_certificate_parent_class)->dispose (object);
+}
+
+static void
+idle_tls_certificate_constructed (GObject *object)
+{
+ IdleTLSCertificate *self = IDLE_TLS_CERTIFICATE (object);
+ void (*chain_up) (GObject *) =
+ G_OBJECT_CLASS (idle_tls_certificate_parent_class)->constructed;
+
+ if (chain_up != NULL)
+ chain_up (object);
+
+ /* register the certificate on the bus */
+ tp_dbus_daemon_register_object (self->priv->daemon,
+ self->priv->object_path, self);
+}
+
+static void
+idle_tls_certificate_init (IdleTLSCertificate *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ IDLE_TYPE_TLS_CERTIFICATE, IdleTLSCertificatePrivate);
+ self->priv->rejections = g_ptr_array_new ();
+}
+
+static void
+idle_tls_certificate_class_init (IdleTLSCertificateClass *klass)
+{
+ static TpDBusPropertiesMixinPropImpl object_props[] = {
+ { "State", "state", NULL },
+ { "Rejections", "rejections", NULL },
+ { "CertificateType", "certificate-type", NULL },
+ { "CertificateChainData", "certificate-chain-data", NULL },
+ { NULL }
+ };
+ static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+ { TP_IFACE_AUTHENTICATION_TLS_CERTIFICATE,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ object_props,
+ },
+ { NULL }
+ };
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (IdleTLSCertificatePrivate));
+
+ oclass->finalize = idle_tls_certificate_finalize;
+ oclass->dispose = idle_tls_certificate_dispose;
+ oclass->set_property = idle_tls_certificate_set_property;
+ oclass->get_property = idle_tls_certificate_get_property;
+ oclass->constructed = idle_tls_certificate_constructed;
+
+ pspec = g_param_spec_string ("object-path",
+ "D-Bus object path",
+ "The D-Bus object path used for this object on the bus.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_OBJECT_PATH, pspec);
+
+ pspec = g_param_spec_uint ("state",
+ "State of this certificate",
+ "The state of this TLS certificate.",
+ 0, NUM_TP_TLS_CERTIFICATE_STATES - 1,
+ TP_TLS_CERTIFICATE_STATE_PENDING,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_STATE, pspec);
+
+ pspec = g_param_spec_boxed ("rejections",
+ "The reject reasons",
+ "The reasons why this TLS certificate has been rejected",
+ TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_REJECTIONS, pspec);
+
+ pspec = g_param_spec_string ("certificate-type",
+ "The certificate type",
+ "The type of this certificate.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_CERTIFICATE_TYPE, pspec);
+
+ pspec = g_param_spec_boxed ("certificate-chain-data",
+ "The certificate chain data",
+ "The raw PEM-encoded trust chain of this certificate.",
+ TP_ARRAY_TYPE_UCHAR_ARRAY_LIST,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_CERTIFICATE_CHAIN_DATA, pspec);
+
+ pspec = g_param_spec_object ("dbus-daemon",
+ "The DBus daemon connection",
+ "The connection to the DBus daemon owning the CM",
+ TP_TYPE_DBUS_DAEMON,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_DBUS_DAEMON, pspec);
+
+ klass->dbus_props_class.interfaces = prop_interfaces;
+ tp_dbus_properties_mixin_class_init (oclass,
+ G_STRUCT_OFFSET (IdleTLSCertificateClass, dbus_props_class));
+}
+
+static void
+idle_tls_certificate_accept (TpSvcAuthenticationTLSCertificate *cert,
+ DBusGMethodInvocation *context)
+{
+ IdleTLSCertificate *self = IDLE_TLS_CERTIFICATE (cert);
+
+ DEBUG ("Accept() called on the TLS certificate; current state %u",
+ self->priv->cert_state);
+
+ if (self->priv->cert_state != TP_TLS_CERTIFICATE_STATE_PENDING)
+ {
+ GError error =
+ { TP_ERROR,
+ TP_ERROR_INVALID_ARGUMENT,
+ "Calling Accept() on a certificate with state != PENDING "
+ "doesn't make sense."
+ };
+
+ dbus_g_method_return_error (context, &error);
+ return;
+ }
+
+ self->priv->cert_state = TP_TLS_CERTIFICATE_STATE_ACCEPTED;
+ tp_svc_authentication_tls_certificate_emit_accepted (self);
+
+ tp_svc_authentication_tls_certificate_return_from_accept (context);
+}
+
+static void
+idle_tls_certificate_reject (TpSvcAuthenticationTLSCertificate *cert,
+ const GPtrArray *rejections,
+ DBusGMethodInvocation *context)
+{
+ IdleTLSCertificate *self = IDLE_TLS_CERTIFICATE (cert);
+
+ DEBUG ("Reject() called on the TLS certificate with rejections %p, "
+ "length %u; current state %u", rejections, rejections->len,
+ self->priv->cert_state);
+
+ if (rejections->len < 1)
+ {
+ GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Calling Reject() with a zero-length rejection list." };
+
+ dbus_g_method_return_error (context, &error);
+ return;
+ }
+
+ if (self->priv->cert_state != TP_TLS_CERTIFICATE_STATE_PENDING)
+ {
+ GError error =
+ { TP_ERROR,
+ TP_ERROR_INVALID_ARGUMENT,
+ "Calling Reject() on a certificate with state != PENDING "
+ "doesn't make sense."
+ };
+
+ dbus_g_method_return_error (context, &error);
+ return;
+ }
+
+ tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ &self->priv->rejections);
+
+ self->priv->rejections =
+ g_boxed_copy (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ rejections);
+ self->priv->cert_state = TP_TLS_CERTIFICATE_STATE_REJECTED;
+
+ tp_svc_authentication_tls_certificate_emit_rejected (
+ self, self->priv->rejections);
+
+ tp_svc_authentication_tls_certificate_return_from_reject (context);
+}
+
+static void
+tls_certificate_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcAuthenticationTLSCertificateClass *klass = g_iface;
+
+#define IMPLEMENT(x) \
+ tp_svc_authentication_tls_certificate_implement_##x ( \
+ klass, idle_tls_certificate_##x)
+ IMPLEMENT (accept);
+ IMPLEMENT (reject);
+#undef IMPLEMENT
+}
diff --git a/src/tls-certificate.h b/src/tls-certificate.h
new file mode 100644
index 0000000..52ea684
--- /dev/null
+++ b/src/tls-certificate.h
@@ -0,0 +1,66 @@
+/*
+ * tls-certificate.h - Header for IdleTLSCertificate
+ * Copyright (C) 2010 Collabora Ltd.
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __IDLE_TLS_CERTIFICATE_H__
+#define __IDLE_TLS_CERTIFICATE_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _IdleTLSCertificate IdleTLSCertificate;
+typedef struct _IdleTLSCertificateClass IdleTLSCertificateClass;
+typedef struct _IdleTLSCertificatePrivate IdleTLSCertificatePrivate;
+
+struct _IdleTLSCertificateClass {
+ GObjectClass parent_class;
+
+ TpDBusPropertiesMixinClass dbus_props_class;
+};
+
+struct _IdleTLSCertificate {
+ GObject parent;
+
+ IdleTLSCertificatePrivate *priv;
+};
+
+GType idle_tls_certificate_get_type (void);
+
+#define IDLE_TYPE_TLS_CERTIFICATE \
+ (idle_tls_certificate_get_type ())
+#define IDLE_TLS_CERTIFICATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), IDLE_TYPE_TLS_CERTIFICATE, \
+ IdleTLSCertificate))
+#define IDLE_TLS_CERTIFICATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), IDLE_TYPE_TLS_CERTIFICATE, \
+ IdleTLSCertificateClass))
+#define IDLE_IS_TLS_CERTIFICATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), IDLE_TYPE_TLS_CERTIFICATE))
+#define IDLE_IS_TLS_CERTIFICATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), IDLE_TYPE_TLS_CERTIFICATE))
+#define IDLE_TLS_CERTIFICATE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), IDLE_TYPE_TLS_CERTIFICATE, \
+ IdleTLSCertificateClass))
+
+G_END_DECLS
+
+#endif /* #ifndef __IDLE_TLS_CERTIFICATE_H__*/