libpurple/plugins/ssl/ssl-gnutls.c

branch
soc.2013.gobjectification.plugins
changeset 37157
87898632ad06
parent 37156
5902dd574c6e
parent 36156
2fe784e7e985
child 37158
96b5ab42da00
equal deleted inserted replaced
37156:5902dd574c6e 37157:87898632ad06
42 #define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data) 42 #define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data)
43 43
44 static gnutls_certificate_client_credentials xcred = NULL; 44 static gnutls_certificate_client_credentials xcred = NULL;
45 45
46 #ifdef HAVE_GNUTLS_PRIORITY_FUNCS 46 #ifdef HAVE_GNUTLS_PRIORITY_FUNCS
47 /* Priority strings. The default one is, well, the default (and is always 47
48 /**
49 * This string tells GnuTLS the list of ciphers we're ok with using. The goal
50 * is to disable weaker ciphers while remaining compatible with almost all
51 * servers.
52 *
53 * Ideally this is something we wouldn't do. Ideally the system-wide GnuTLS
54 * library would use good defaults. But for now I think we can safely be more
55 * restrictive than the GnuTLS defaults. --Mark Doliner
56 *
57 * You can test the priority string using this command:
58 * > gnutls-cli --priority "<SIGNATURE STRING>" <HOSTNAME>
59 * Note that on Ubuntu 14.04 gnutls-cli is linked against the older GnuTLS
60 * 2.12.23, which might be different than what Pidgin is linked against.
61 *
62 * Rationale for this string:
63 * - Start with the SECURE192 keyword and add the SECURE128 keyword. This
64 * includes both 128 and 192 bit ciphers, giving priority to the 192 bit
65 * ciphers. We're not too picky about the order... people generally think
66 * 128 bit ciphers are sufficient for now and 192 bit ciphers are overkill
67 * (and slower), but the speed impact shouldn't matter much for us and we
68 * prefer to be resilient into the distant future.
69 *
70 * - Remove and re-add RSA ciphers. This gives them a lower priority. We do
71 * this because they don't support perfect forward secrecy (PFS) and we want
72 * ciphers that DO support PFS to have a higher priority. An alternate way
73 * to do this is to add +PFS to the front of the string, but the PFS keyword
74 * was only added in 3.2.4 and attempting to use it with older GnuTLS causes
75 * the entire priority string to be discarded.
76 *
77 * - Add SIGN-RSA-SHA1. SHA-1 is a weaker hashing algorithm that's not
78 * included in SECURE128. We'd prefer not to include it, but unfortunately
79 * as of 2014-09-10 it is required by login.live.com (used by the MSN PRPL).
80 *
81 * - Remove DHE-DSS ciphers. This is kind of arbitrary. We think maybe nobody
82 * uses these and all things being equal a shorter cipher list is preferred.
83 *
84 * - Disable SSL 3.0. Everyone should be using at least TLS 1.0 by now.
85 *
86 * We only use this string for GnuTLS 3.2.2 and newer. For older versions we
87 * use NORMAL. Over time the GnuTLS library has changed how it parses priority
88 * strings and there are some unfortunate quirks:
89 * - 128 bit ciphers stopped being included in the SECURE256 keyword in 3.0.9.
90 * - 256 bit ciphers started being included in the SECURE128 keyword in 3.0.12.
91 * - Support for combining priority string keywords wasn't added until 3.1.0.
92 * - Adding/removing items from the priority string using plus and minus is
93 * buggy in GnuTLS 3.2.2 and older. See this commit for details:
94 * https://gitorious.org/gnutls/gnutls/commit/913f03ccfafc37277f0a88287d02cdbb9bbfb652
95 *
96 * These quirks make it difficult to find a single priority string that works
97 * well for all versions of GnuTLS that enables 128 and 256 bit ciphers while
98 * disabling less secure ciphers. In fact it's difficult to come up with ANY
99 * string that accomplishes this for 3.0.9, 3.0.10, and 3.0.11. And the bug
100 * with adding/removing items from the priority string means we might get
101 * unexpected results when using a complicated string, and so we're better off
102 * just sticking with the default.
103 *
104 * For more discussion about this change see bug #8061.
105 */
106 #define GNUTLS_DEFAULT_PRIORITY "SECURE192:+SECURE128:-RSA:+RSA:+SIGN-RSA-SHA1:-DHE-DSS:-VERS-SSL3.0"
107
108 /*
109 * Priority strings. The default one is, well, the default (and is always
48 * set). The hash table is of the form hostname => priority (both 110 * set). The hash table is of the form hostname => priority (both
49 * char *). 111 * char *).
50 * 112 *
51 * We only use a gnutls_priority_t for the default on the assumption that 113 * We only use a gnutls_priority_t for the default on the assumption that
52 * that's the more common case. Improvement patches (like matching on 114 * that's the more common case. Improvement patches (like matching on
59 static void 121 static void
60 ssl_gnutls_log(int level, const char *str) 122 ssl_gnutls_log(int level, const char *str)
61 { 123 {
62 /* GnuTLS log messages include the '\n' */ 124 /* GnuTLS log messages include the '\n' */
63 purple_debug_misc("gnutls", "lvl %d: %s", level, str); 125 purple_debug_misc("gnutls", "lvl %d: %s", level, str);
126 }
127
128 /**
129 * set_cipher_priorities:
130 * @priority_cache: A pointer to a gnutls_priority_t. This will be initialized
131 * using the given priorities.
132 * @priorities: A GnuTLS priority string.
133 *
134 * A simple convenience wrapper around gnutls_priority_init(). The wrapper
135 * does a few things:
136 * - Logs a helpful message if initialization fails.
137 * - Frees priority_cache if needed if initialization fails.
138 * - Set priority_cache to NULL if needed if initialization fails.
139 */
140 static void
141 set_cipher_priorities(gnutls_priority_t *priority_cache, const char *priorities)
142 {
143 int ret;
144
145 ret = gnutls_priority_init(priority_cache, priorities, NULL);
146 if (ret != GNUTLS_E_SUCCESS) {
147 purple_debug_warning("gnutls", "Unable to set cipher priorities to %s. "
148 "Error code %d: %s\n", priorities, ret, gnutls_strerror(ret));
149
150 /* Versions of GnuTLS before 2.9.10 allocate but don't free priority_cache
151 if there's an error. We free it here to avoid a mem leak. */
152 if (!gnutls_check_version("2.9.10")) {
153 gnutls_free(*priority_cache);
154 }
155
156 /* Versions of GnuTLS before 3.2.9 leave priority_cache pointing to
157 freed memory if there's an error. We want our callers to be able to
158 depend on this being NULL, so set it to NULL ourselves. */
159 if (!gnutls_check_version("3.2.9")) {
160 *priority_cache = NULL;
161 }
162 }
64 } 163 }
65 164
66 static void 165 static void
67 ssl_gnutls_init_gnutls(void) 166 ssl_gnutls_init_gnutls(void)
68 { 167 {
141 } 240 }
142 } 241 }
143 } 242 }
144 243
145 if (default_priority_str) { 244 if (default_priority_str) {
146 if (gnutls_priority_init(&default_priority, default_priority_str, NULL)) { 245 /* Note: If the string is invalid then this call will fail and
147 purple_debug_warning("gnutls", "Unable to set default priority to %s\n", 246 we'll try again with our default priority string later. */
148 default_priority_str); 247 set_cipher_priorities(&default_priority, default_priority_str);
149 /* Versions of GnuTLS as of 2.8.6 (2010-03-31) don't free/NULL
150 * this on error.
151 */
152 gnutls_free(default_priority);
153 default_priority = NULL;
154 }
155
156 g_free(default_priority_str); 248 g_free(default_priority_str);
157 } 249 }
158 250
159 g_strfreev(entries); 251 g_strfreev(entries);
160 #endif /* HAVE_GNUTLS_PRIORITY_FUNCS */ 252 #endif /* HAVE_GNUTLS_PRIORITY_FUNCS */
161 } 253 }
162 254
163 #ifdef HAVE_GNUTLS_PRIORITY_FUNCS 255 #ifdef HAVE_GNUTLS_PRIORITY_FUNCS
164 /* Make sure we set have a default priority! */ 256 /* Set a default priority string if we didn't do it above */
165 if (!default_priority) { 257 if (!default_priority) {
166 if (gnutls_priority_init(&default_priority, "NORMAL:%SSL3_RECORD_VERSION", NULL)) { 258 if (gnutls_check_version("3.2.2")) {
167 /* See comment above about memory leak */ 259 set_cipher_priorities(&default_priority, GNUTLS_DEFAULT_PRIORITY);
168 gnutls_free(default_priority); 260 }
169 gnutls_priority_init(&default_priority, "NORMAL", NULL); 261 if (!default_priority) {
262 /* Try again with an extremely simple priority string. */
263 set_cipher_priorities(&default_priority, "NORMAL");
170 } 264 }
171 } 265 }
172 #endif /* HAVE_GNUTLS_PRIORITY_FUNCS */ 266 #endif /* HAVE_GNUTLS_PRIORITY_FUNCS */
173 267
174 gnutls_global_init(); 268 gnutls_global_init();
240 334
241 purple_input_remove(gnutls_data->handshake_handler); 335 purple_input_remove(gnutls_data->handshake_handler);
242 gnutls_data->handshake_handler = 0; 336 gnutls_data->handshake_handler = 0;
243 337
244 if(ret != 0) { 338 if(ret != 0) {
245 purple_debug_error("gnutls", "Handshake failed. Error %s\n", 339 purple_debug_error("gnutls", "Handshake failed: %s\n",
246 gnutls_strerror(ret)); 340 gnutls_strerror(ret));
247 341
248 if(gsc->error_cb != NULL) 342 if(gsc->error_cb != NULL)
249 gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, 343 gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED,
250 gsc->connect_cb_data); 344 gsc->connect_cb_data);
251 345
252 purple_ssl_close(gsc); 346 purple_ssl_close(gsc);
253 } else { 347 } else {
254 /* Now we are cooking with gas! */ 348 /* Now we are cooking with gas! */
255 PurpleSslOps *ops = purple_ssl_get_ops(); 349 PurpleSslOps *ops = purple_ssl_get_ops();

mercurial