pidgin: dfecabe4: gnutls: Allow overriding (per-host) of G...
darkrain42 at pidgin.im
darkrain42 at pidgin.im
Thu Apr 1 02:42:13 EDT 2010
-----------------------------------------------------------------
Revision: dfecabe492257b96e1cdc59323c35a3605a9f68c
Ancestor: 1b206e64e678d46bf6bea552500d2cd15375ed82
Author: darkrain42 at pidgin.im
Date: 2010-04-01T04:09:05
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/dfecabe492257b96e1cdc59323c35a3605a9f68c
Modified files:
libpurple/plugins/ssl/ssl-gnutls.c
ChangeLog:
gnutls: Allow overriding (per-host) of GnuTLS priorities via env. Fixes #11616
This allows a site to add workarounds for connecting to specific servers
(like the reporter's) which are horribly broken when it comes to TLS 1.0+.
The format (to be documented in the ChangeLog) is host=priority pairs
delimited by semicolons (also pending a confirmation that
gnutls_priority_init's documentation is wrong about semicolon vs. colon).
-------------- next part --------------
============================================================
--- libpurple/plugins/ssl/ssl-gnutls.c 1526683b3f6f214b78c819b849f80cab5ac2a5c1
+++ libpurple/plugins/ssl/ssl-gnutls.c 9857f9843f5fcd823db5632fab9ac824e89f1ccb
@@ -40,8 +40,16 @@ typedef struct
#define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data)
-static gnutls_certificate_client_credentials xcred;
+static gnutls_certificate_client_credentials xcred = NULL;
+#ifdef HAVE_GNUTLS_PRIORITY_FUNCS
+/* Priority strings. The default one is, well, the default (and is always set).
+ * The hash table is of the form hostname => priority (both char *)
+ */
+static char *default_priority = NULL;
+static GHashTable *host_priorities = NULL;
+#endif
+
static void
ssl_gnutls_log(int level, const char *str)
{
@@ -53,6 +61,7 @@ ssl_gnutls_init_gnutls(void)
ssl_gnutls_init_gnutls(void)
{
const char *debug_level;
+ const char *host_priorities_str;
/* Configure GnuTLS to use glib memory management */
/* I expect that this isn't really necessary, but it may prevent
@@ -82,6 +91,60 @@ ssl_gnutls_init_gnutls(void)
gnutls_global_set_log_function(ssl_gnutls_log);
}
+ /* Expected format: host=priority;host2=priority;*=priority
+ * where "*" is used to override the default priority string for
+ * libpurple.
+ */
+ host_priorities_str = g_getenv("PURPLE_GNUTLS_PRIORITIES");
+ if (host_priorities_str) {
+#ifndef HAVE_GNUTLS_PRIORITY_FUNCS
+ purple_debug_warning("gnutls", "Warning, PURPLE_GNUTLS_PRIORITIES "
+ "environment variable set, but we were built "
+ "against an older GnuTLS that doesn't support "
+ "this. :-(");
+#else /* HAVE_GNUTLS_PRIORITY_FUNCS */
+ char **entries = g_strsplit(host_priorities_str, ";", -1);
+ guint i;
+
+ host_priorities = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+
+ for (i = 0; entries[i]; ++i) {
+ char *host = entries[i];
+ char *equals = strchr(host, '=');
+ char *prio_str;
+
+ if (equals) {
+ *equals = '\0';
+ prio_str = equals + 1;
+
+ /* Empty? */
+ if (*prio_str == '\0') {
+ purple_debug_warning("gnutls", "Ignoring empty priority "
+ "string for %s\n", host);
+ } else {
+ /* TODO: Validate each of these and complain */
+ if (g_str_equal(host, "*")) {
+ /* Override the default priority */
+ g_free(default_priority);
+ default_priority = g_strdup(prio_str);
+ } else
+ g_hash_table_insert(host_priorities, g_strdup(host),
+ g_strdup(prio_str));
+ }
+ }
+ }
+
+ g_strfreev(entries);
+#endif /* HAVE_GNUTLS_PRIORITY_FUNCS */
+ }
+
+#ifdef HAVE_GNUTLS_PRIORITY_FUNCS
+ /* Make sure we set have a default priority! */
+ if (!default_priority)
+ default_priority = g_strdup("NORMAL:%SSL3_RECORD_VERSION");
+#endif /* HAVE_GNUTLS_PRIORITY_FUNCS */
+
gnutls_global_init();
gnutls_certificate_allocate_credentials(&xcred);
@@ -103,6 +166,17 @@ ssl_gnutls_uninit(void)
gnutls_global_deinit();
gnutls_certificate_free_credentials(xcred);
+ xcred = NULL;
+
+#ifdef HAVE_GNUTLS_PRIORITY_FUNCS
+ if (host_priorities) {
+ g_hash_table_destroy(host_priorities);
+ host_priorities = NULL;
+ }
+
+ g_free(default_priority);
+ default_priority = NULL;
+#endif
}
static void
@@ -280,9 +354,27 @@ ssl_gnutls_connect(PurpleSslConnection *
gnutls_init(&gnutls_data->session, GNUTLS_CLIENT);
#ifdef HAVE_GNUTLS_PRIORITY_FUNCS
- if (gnutls_priority_set_direct(gnutls_data->session,
- "NORMAL:%SSL3_RECORD_VERSION", NULL))
- gnutls_priority_set_direct(gnutls_data->session, "NORMAL", NULL);
+ {
+ const char *prio_str = NULL;
+
+ /* Let's see if someone has specified a specific priority */
+ if (gsc->host && host_priorities)
+ prio_str = g_hash_table_lookup(host_priorities, gsc->host);
+
+ /* If not, let's use the default! */
+ if (!prio_str)
+ prio_str = default_priority;
+
+ /* TODO: Use a gnutls_priority_t cache, so this doesn't require three levels! */
+ /* The logic here is to try the specified string, fall back to the default
+ * (which may also be user-specified), and if *that* doesn't work, fall back
+ * to the default default (which I'm not sure is necessary, but whatever).
+ */
+ if (gnutls_priority_set_direct(gnutls_data->session,
+ prio_str, NULL))
+ if (gnutls_priority_set_direct(gnutls_data->session, default_priority, NULL))
+ gnutls_priority_set_direct(gnutls_data->session, "NORMAL", NULL);
+ }
#else
gnutls_set_default_priority(gnutls_data->session);
#endif
More information about the Commits
mailing list