From 03fb66fe4c58613b1ea84ac3221defb347b48d34 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Sun, 21 Apr 2013 19:48:19 +0300 Subject: [PATCH] telepathy: add TLS channel class One channel per TLS certificate user interaction. --- src/telepathy/telepathy-connection.c | 6 +- src/telepathy/telepathy-private.h | 11 +- src/telepathy/telepathy-tls.c | 281 ++++++++++++++++++++++++++++++++++- src/telepathy/telepathy-transport.c | 17 +++ 4 files changed, 309 insertions(+), 6 deletions(-) diff --git a/src/telepathy/telepathy-connection.c b/src/telepathy/telepathy-connection.c index 09e9fbf2..4a364aec 100644 --- a/src/telepathy/telepathy-connection.c +++ b/src/telepathy/telepathy-connection.c @@ -62,6 +62,7 @@ typedef struct _SipeConnection { /* channel managers */ TpSimplePasswordManager *password_manager; struct _SipeContactList *contact_list; + struct _SipeTLSManager *tls_manager; struct sipe_backend_private private; gchar *account; @@ -192,6 +193,7 @@ static gboolean connect_to_core(SipeConnection *self, self->account, NULL); telepathy_private->message = NULL; + telepathy_private->tls_manager = self->tls_manager; telepathy_private->transport = NULL; telepathy_private->ipaddress = NULL; @@ -373,7 +375,9 @@ static GPtrArray *create_channel_managers(TpBaseConnection *base) g_ptr_array_add(channel_managers, self->password_manager); g_ptr_array_add(channel_managers, sipe_telepathy_search_new(base)); - g_ptr_array_add(channel_managers, sipe_telepathy_tls_new(base)); + + self->tls_manager = sipe_telepathy_tls_new(base); + g_ptr_array_add(channel_managers, self->tls_manager); return(channel_managers); } diff --git a/src/telepathy/telepathy-private.h b/src/telepathy/telepathy-private.h index 02798c9b..3c11a619 100644 --- a/src/telepathy/telepathy-private.h +++ b/src/telepathy/telepathy-private.h @@ -25,6 +25,7 @@ struct _GObject; struct _GObjectClass; struct _SipeConnection; struct _SipeContactList; +struct _SipeTLSManager; struct _TpBaseConnection; struct _TpBaseConnectionManager; struct _TpBaseProtocol; @@ -49,6 +50,9 @@ struct sipe_backend_private { guint activity; gchar *message; + /* TLS certificate verification */ + struct _SipeTLSManager *tls_manager; + /* transport */ struct sipe_transport_telepathy *transport; gchar *ipaddress; @@ -102,7 +106,12 @@ void sipe_telepathy_status_init(struct _GObjectClass *object_class, gsize struct_offset); /* TLS certificate verification */ -GObject *sipe_telepathy_tls_new(struct _TpBaseConnection *connection); +struct _SipeTLSManager *sipe_telepathy_tls_new(struct _TpBaseConnection *connection); +void sipe_telepathy_tls_verify_async(struct _GObject *connection, + const gchar *hostname, + const gchar **reference_identities, + GAsyncReadyCallback callback, + gpointer user_data); /* Local Variables: diff --git a/src/telepathy/telepathy-tls.c b/src/telepathy/telepathy-tls.c index 08e7dbdd..b86070e7 100644 --- a/src/telepathy/telepathy-tls.c +++ b/src/telepathy/telepathy-tls.c @@ -43,6 +43,8 @@ typedef struct _SipeTLSManager { GObject parent; GObject *connection; + + GSList *channels; } SipeTLSManager; /* @@ -55,6 +57,32 @@ static GType sipe_tls_manager_get_type(void); (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_TLS_MANAGER, \ SipeTLSManager)) +/* + * TLS Channel class - data structures + */ +typedef struct _SipeTLSChannelClass { + TpBaseChannelClass parent_class; +} SipeTLSChannelClass; + +typedef struct _SipeTLSChannel { + TpBaseChannel parent; + + gchar *server_cert_path; + gchar *hostname; + GStrv reference_identities; + + GSimpleAsyncResult *result; +} SipeTLSChannel; + +/* + * TLS Channel class - type macros + */ +static GType sipe_tls_channel_get_type(void) G_GNUC_CONST; +#define SIPE_TYPE_TLS_CHANNEL \ + (sipe_tls_channel_get_type()) +#define SIPE_TLS_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_TLS_CHANNEL, \ + SipeTLSChannel)) G_END_DECLS /* @@ -69,6 +97,16 @@ G_DEFINE_TYPE_WITH_CODE(SipeTLSManager, ) /* + * TLS Channel class - type definition + */ +G_DEFINE_TYPE_WITH_CODE(SipeTLSChannel, + sipe_tls_channel, + TP_TYPE_BASE_CHANNEL, + G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CHANNEL_TYPE_SERVER_TLS_CONNECTION, + NULL); +) + +/* * TLS Manager class - instance methods */ static void sipe_tls_manager_constructed(GObject *object) @@ -79,8 +117,7 @@ static void sipe_tls_manager_constructed(GObject *object) if (chain_up) chain_up(object); - /* @TODO */ - (void)self; + self->channels = NULL; } static void sipe_tls_manager_dispose(GObject *object) @@ -94,6 +131,27 @@ static void sipe_tls_manager_dispose(GObject *object) chain_up(object); } +static void sipe_tls_manager_finalize(GObject *object) +{ + SipeTLSManager *self = SIPE_TLS_MANAGER(object); + void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_tls_manager_parent_class)->constructed; + GSList *entry = self->channels; + + /* close channels */ + while (entry) { + GSList *next = entry->next; + /* removes entry from list */ + tp_base_channel_close(entry->data); + entry = next; + } + + tp_clear_object(&self->connection); + + if (chain_up) + chain_up(object); +} + + /* * TLS Manager class - type implementation */ @@ -105,6 +163,7 @@ static void sipe_tls_manager_class_init(SipeTLSManagerClass *klass) object_class->constructed = sipe_tls_manager_constructed; object_class->dispose = sipe_tls_manager_dispose; + object_class->finalize = sipe_tls_manager_finalize; } static void sipe_tls_manager_init(SIPE_UNUSED_PARAMETER SipeTLSManager *self) @@ -147,11 +206,225 @@ static void channel_manager_iface_init(gpointer g_iface, } /* create new TLS manager object */ -GObject *sipe_telepathy_tls_new(TpBaseConnection *connection) +SipeTLSManager *sipe_telepathy_tls_new(TpBaseConnection *connection) { SipeTLSManager *self = g_object_new(SIPE_TYPE_TLS_MANAGER, NULL); self->connection = g_object_ref(connection); - return(G_OBJECT(self)); + return(self); +} + +static void channel_closed_cb(SipeTLSChannel *channel, + SipeTLSManager *self) +{ + self->channels = g_slist_remove(self->channels, channel); + tp_channel_manager_emit_channel_closed_for_object(self, + TP_EXPORTABLE_CHANNEL(channel)); + g_object_unref(channel); +} + +static void manager_new_channel(SipeTLSManager *self, + SipeTLSChannel *channel) +{ + self->channels = g_slist_prepend(self->channels, + g_object_ref(channel)); + + g_signal_connect(channel, + "closed", + G_CALLBACK(channel_closed_cb), + self); + + /* emit NewChannel on the ChannelManager iface */ + tp_channel_manager_emit_new_channel(self, + TP_EXPORTABLE_CHANNEL(channel), + NULL); + +} + +/* + * TLS Channel class - instance methods + */ +enum { + CHANNEL_PROP_SERVER_CERTIFICATE = 1, + CHANNEL_PROP_HOSTNAME, + CHANNEL_PROP_REFERENCE_IDENTITIES, + CHANNEL_LAST_PROP +}; + +static void get_property(GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + SipeTLSChannel *self = SIPE_TLS_CHANNEL(object); + + switch (property_id) { + case CHANNEL_PROP_SERVER_CERTIFICATE: + g_value_set_boxed(value, self->server_cert_path); + break; + case CHANNEL_PROP_HOSTNAME: + g_value_set_string(value, self->hostname); + break; + case CHANNEL_PROP_REFERENCE_IDENTITIES: + g_value_set_boxed(value, self->reference_identities); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void fill_immutable_properties(TpBaseChannel *channel, + GHashTable *properties) +{ + TP_BASE_CHANNEL_CLASS(sipe_tls_channel_parent_class)->fill_immutable_properties(channel, + properties); + tp_dbus_properties_mixin_fill_properties_hash(G_OBJECT(channel), + 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 *get_object_path_suffix(TpBaseChannel *base) +{ + return(g_strdup_printf("TLSChannel_%p", base)); +} + +static void sipe_tls_channel_constructed(GObject *object) +{ + SipeTLSChannel *self = SIPE_TLS_CHANNEL(object); + void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_tls_channel_parent_class)->constructed; + + if (chain_up) + chain_up(object); + + /* @TODO */ + (void)self; +} + +static void sipe_tls_channel_finalize(GObject *object) +{ + SipeTLSChannel *self = SIPE_TLS_CHANNEL(object); + + SIPE_DEBUG_INFO_NOFORMAT("SipeTLSChannel::finalize"); + + g_simple_async_result_complete(self->result); + g_clear_object(&self->result); + + g_free(self->server_cert_path); + g_free(self->hostname); + g_strfreev(self->reference_identities); + + G_OBJECT_CLASS(sipe_tls_channel_parent_class)->finalize(object); +} + +/* + * TLS Channel class - type implementation + */ +static void sipe_tls_channel_class_init(SipeTLSChannelClass *klass) +{ + static TpDBusPropertiesMixinPropImpl props[] = { + { + .name = "ServerCertificate", + .getter_data = "server-certificate", + .setter_data = NULL + }, + { + .name = "Hostname", + .getter_data = "hostname", + .setter_data = NULL + }, + { + .name = "ReferenceIdentities", + .getter_data = "reference-identities", + .setter_data = NULL + }, + { + .name = NULL + } + }; + GObjectClass *object_class = G_OBJECT_CLASS(klass); + TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS(klass); + GParamSpec *ps; + + SIPE_DEBUG_INFO_NOFORMAT("SipeTLSChannel::class_init"); + + object_class->constructed = sipe_tls_channel_constructed; + object_class->finalize = sipe_tls_channel_finalize; + object_class->get_property = get_property; + + 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 = fill_immutable_properties; + base_class->get_object_path_suffix = get_object_path_suffix; + base_class->interfaces = NULL; + base_class->close = tp_base_channel_destroyed; + + ps = 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(object_class, + CHANNEL_PROP_SERVER_CERTIFICATE, + ps); + + ps = g_param_spec_string("hostname", + "The hostname to be verified", + "The hostname which should be certified by the server certificate.", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property(object_class, + CHANNEL_PROP_HOSTNAME, + ps); + + ps = 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_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property(object_class, + CHANNEL_PROP_REFERENCE_IDENTITIES, + ps); + + tp_dbus_properties_mixin_implement_interface(object_class, + TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION, + tp_dbus_properties_mixin_getter_gobject_properties, + NULL, + props); +} + +static void sipe_tls_channel_init(SIPE_UNUSED_PARAMETER SipeTLSChannel *self) +{ + SIPE_DEBUG_INFO_NOFORMAT("SipeTLSChannel::init"); +} + +/* create new tls channel object */ +void sipe_telepathy_tls_verify_async(GObject *connection, + const gchar *hostname, + const gchar **reference_identities, + GAsyncReadyCallback callback, + gpointer user_data) +{ + struct sipe_backend_private *telepathy_private = sipe_telepathy_connection_private(connection); + + /* property "connection" required by TpBaseChannel */ + SipeTLSChannel *self = g_object_new(SIPE_TYPE_TLS_CHANNEL, + "connection", connection, + NULL); + + self->hostname = g_strdup(hostname); + self->reference_identities = g_boxed_copy(G_TYPE_STRV, reference_identities); + + self->result = g_simple_async_result_new(G_OBJECT(self), + callback, + user_data, + sipe_telepathy_tls_verify_async); + + tp_base_channel_register(TP_BASE_CHANNEL(self)); + + manager_new_channel(telepathy_private->tls_manager, self); } /* diff --git a/src/telepathy/telepathy-transport.c b/src/telepathy/telepathy-transport.c index d643aa19..2fa59812 100644 --- a/src/telepathy/telepathy-transport.c +++ b/src/telepathy/telepathy-transport.c @@ -183,6 +183,17 @@ static void socket_connected(GObject *client, } } +static void certificate_result(SIPE_UNUSED_PARAMETER GObject *unused, + SIPE_UNUSED_PARAMETER GAsyncResult *res, + gpointer data) +{ + struct sipe_transport_telepathy *transport = data; + + SIPE_DEBUG_INFO("certificate_result: %p", transport); + + /* @TODO: take action based on result */ +} + static gboolean accept_certificate_signal(GTlsConnection *tls, SIPE_UNUSED_PARAMETER GTlsCertificate *peer_cert, SIPE_UNUSED_PARAMETER GTlsCertificateFlags errors, @@ -200,6 +211,12 @@ static gboolean accept_certificate_signal(GTlsConnection *tls, } else { /* retry after user accepted certificate */ transport->wait_for_user = TRUE; + /* @TODO: set up correct parameters */ + sipe_telepathy_tls_verify_async(G_OBJECT(transport->private->connection), + "", + NULL, + certificate_result, + transport); return(FALSE); } } -- 2.11.4.GIT