--- a/ChangeLog Fri Jun 27 01:07:11 2014 +0530
+++ b/ChangeLog Wed Jul 09 11:42:34 2014 +0530
@@ -107,6 +107,9 @@
* Fix Facebook XMPP roster quirks. (#15041, #15957)
+ * Fix login when using the GnuTLS library for TLS connections. (#16172) version 2.10.9 (2/2/2014):
* Fix problems logging into some servers including jabber.org and
--- a/libpurple/certificate.c Fri Jun 27 01:07:11 2014 +0530
+++ b/libpurple/certificate.c Wed Jul 09 11:42:34 2014 +0530
@@ -491,21 +491,79 @@
purple_certificate_get_display_string(PurpleCertificate *crt)
- PurpleCertificateScheme *scheme;
+ gint64 activation, expiration; + gchar *activ_str, *expir_str; +#if GLIB_CHECK_VERSION(2,26,0) + GDateTime *act_dt, *exp_dt; g_return_val_if_fail(crt, NULL);
- g_return_val_if_fail(crt->scheme, NULL);
+ /* Pull out the SHA1 checksum */ + sha_bin = purple_certificate_get_fingerprint_sha1(crt); + g_return_val_if_fail(sha_bin != NULL, NULL); + sha_asc = purple_base16_encode_chunked(sha_bin->data, sha_bin->len); + /* Get the cert Common Name */ + /* TODO: Will break on CA certs */ + cn = purple_certificate_get_subject_name(crt); + issuer_id = purple_certificate_get_issuer_unique_id(crt);
+ /* Get the certificate times */ + /* TODO: Check the times against localtime */ + /* TODO: errorcheck? */ + if (!purple_certificate_get_times(crt, &activation, &expiration)) { + purple_debug_error("certificate", + "Failed to get certificate times!\n"); + activation = expiration = 0; +#if GLIB_CHECK_VERSION(2,26,0) + act_dt = g_date_time_new_from_unix_local(activation); + activ_str = g_date_time_format(act_dt, "%c"); + g_date_time_unref(act_dt); - g_return_val_if_fail(scheme->get_display_string, NULL);
+ exp_dt = g_date_time_new_from_unix_local(expiration); + expir_str = g_date_time_format(exp_dt, "%c"); + g_date_time_unref(exp_dt); + activ_str = g_strdup(ctime(&activation)); + expir_str = g_strdup(ctime(&expiration)); + self_signed = purple_certificate_signed_by(crt, crt); - str = (scheme->get_display_string)(crt);
+ text = g_strdup_printf( + _("Common name: %s\n\n" + "Fingerprint (SHA1): %s\n\n" + "Activation date: %s\n" + "Expiration date: %s\n"), + self_signed ? _("(self-signed)") : (issuer_id ? issuer_id : "(null)"), + sha_asc ? sha_asc : "(null)", + activ_str ? activ_str : "(null)", + expir_str ? expir_str : "(null)");
+ g_byte_array_free(sha_bin, TRUE); purple_certificate_get_type(void)
--- a/libpurple/certificate.h Fri Jun 27 01:07:11 2014 +0530
+++ b/libpurple/certificate.h Wed Jul 09 11:42:34 2014 +0530
@@ -236,12 +236,6 @@
* <sbr/>@crt: Certificate instance
* <sbr/>Returns: Binary DER representation of certificate - must
* be freed using g_byte_array_free().
- * @get_display_string: Retrieves a string representation of the certificate
- * <sbr/>@crt: Certificate instance
- * <sbr/>Returns: User-displayable string representation of
- * certificate - must be freed using
@@ -275,8 +269,6 @@
GSList * (* import_certificates)(const gchar * filename);
GByteArray * (* get_der_data)(PurpleCertificate *crt);
- gchar * (* get_display_string)(PurpleCertificate *crt);
void (*_purple_reserved1)(void);
@@ -697,7 +689,8 @@
* Retrieve a certificate from a pool.
- * Returns: Retrieved certificate, or NULL if it wasn't there
+ * Returns: Retrieved certificate (to be freed with + * purple_certificate_destroy), or NULL if it wasn't there purple_certificate_pool_retrieve(PurpleCertificatePool *pool, const gchar *id);
--- a/libpurple/plugins/ssl/ssl-gnutls.c Fri Jun 27 01:07:11 2014 +0530
+++ b/libpurple/plugins/ssl/ssl-gnutls.c Wed Jul 09 11:42:34 2014 +0530
@@ -473,11 +473,59 @@
if(s == GNUTLS_E_AGAIN || s == GNUTLS_E_INTERRUPTED) {
#ifdef GNUTLS_E_PREMATURE_TERMINATION
} else if (s == GNUTLS_E_PREMATURE_TERMINATION) {
- purple_debug_warning("gnutls", "premature termination\n");
+ purple_debug_warning("gnutls", "Received a FIN on the TCP socket " + "for %s. This either means that the remote server closed " + "the socket without sending us a Close Notify alert or a " + "man-in-the-middle injected a FIN into the TCP stream. " + "Assuming it's the former.\n", gsc->host); + } else if (s == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) { + purple_debug_warning("gnutls", "Received packet of unexpected " + "length on the TCP socket for %s. Among other " + "possibilities this might mean that the remote server " + "closed the socket without sending us a Close Notify alert. " + "Assuming that's the case for compatibility, however, note " + "that it's quite possible that we're incorrectly ignoing " + "a real error.\n", gsc->host); + * Always treat a closed TCP connection as if the remote server cleanly + * terminated the SSL session. + * Most TLS servers send a Close Notify alert before sending TCP FIN + * when closing a session. This informs us at the TLS layer that the + * connection is being cleanly closed. Without this it's more + * difficult for us to determine whether the session was closed + * cleanly (we would need to resort to having the application layer + * perform this check, e.g. by looking at the Content-Length HTTP + * header for HTTP connections). + * There ARE servers that don't send Close Notify and we want to be + * compatible with them. And so we don't require Close Notify. This + * seems to match the behavior of libnss. This is a slightly + * unfortunate situation. It means a malicious MITM can inject a FIN + * into our TCP stream and cause our encrypted session to termiate + * and we won't indicate any problem to the user. + * GnuTLS < 3.0.0 returned the UNEXPECTED_PACKET_LENGTH error on EOF. + * GnuTLS >= 3.0.0 added the PREMATURE_TERMINATION error to allow us + * to detect the problem more specifically. + * For historical discussion see: + * https://developer.pidgin.im/ticket/16172 + * http://trac.adiumx.com/intertrac/ticket%3A16678 + * https://bugzilla.mozilla.org/show_bug.cgi?id=508698#c4 + * http://lists.gnu.org/archive/html/gnutls-devel/2008-03/msg00058.html + * Or search for GNUTLS_E_UNEXPECTED_PACKET_LENGTH or + * GNUTLS_E_PREMATURE_TERMINATION
purple_debug_error("gnutls", "receive failed: %s\n",
@@ -1179,70 +1227,6 @@
-x509_display_string(PurpleCertificate *crt)
- gint64 activation, expiration;
- gchar *activ_str, *expir_str;
-#if GLIB_CHECK_VERSION(2,26,0)
- GDateTime *act_dt, *exp_dt;
- /* Pull out the SHA1 checksum */
- sha_bin = x509_sha1sum(crt);
- g_return_val_if_fail(sha_bin != NULL, NULL);
- sha_asc = purple_base16_encode_chunked(sha_bin->data, sha_bin->len);
- /* Get the cert Common Name */
- /* TODO: Will break on CA certs */
- cn = x509_common_name(crt);
- /* Get the certificate times */
- /* TODO: Check the times against localtime */
- /* TODO: errorcheck? */
- if (!x509_times(crt, &activation, &expiration)) {
- purple_debug_error("certificate",
- "Failed to get certificate times!\n");
- activation = expiration = 0;
-#if GLIB_CHECK_VERSION(2,26,0)
- act_dt = g_date_time_new_from_unix_local(activation);
- activ_str = g_date_time_format(act_dt, "%c");
- g_date_time_unref(act_dt);
- exp_dt = g_date_time_new_from_unix_local(expiration);
- expir_str = g_date_time_format(exp_dt, "%c");
- g_date_time_unref(exp_dt);
- activ_str = g_strdup(ctime(&activation));
- expir_str = g_strdup(ctime(&expiration));
- text = g_strdup_printf(_("Common name: %s\n\n"
- "Fingerprint (SHA1): %s\n\n"
- "Activation date: %s\n"
- "Expiration date: %s\n"),
- sha_asc ? sha_asc : "(null)",
- activ_str ? activ_str : "(null)",
- expir_str ? expir_str : "(null)");
- g_byte_array_free(sha_bin, TRUE);
/* X.509 certificate operations provided by this plugin */
static PurpleCertificateScheme x509_gnutls = {
"x509", /* Scheme name */
@@ -1260,7 +1244,6 @@
x509_times, /* Activation/Expiration time */
x509_importcerts_from_file, /* Multiple certificates import function */
x509_get_der_data, /* Binary DER data */
- x509_display_string, /* Display representation */
--- a/libpurple/plugins/ssl/ssl-nss.c Fri Jun 27 01:07:11 2014 +0530
+++ b/libpurple/plugins/ssl/ssl-nss.c Wed Jul 09 11:42:34 2014 +0530
@@ -946,68 +946,6 @@
-x509_display_string(PurpleCertificate *crt)
- gint64 activation, expiration;
- gchar *activ_str, *expir_str;
-#if GLIB_CHECK_VERSION(2,26,0)
- GDateTime *act_dt, *exp_dt;
- /* Pull out the SHA1 checksum */
- sha_bin = x509_sha1sum(crt);
- sha_asc = purple_base16_encode_chunked(sha_bin->data, sha_bin->len);
- /* Get the cert Common Name */
- /* TODO: Will break on CA certs */
- cn = x509_common_name(crt);
- /* Get the certificate times */
- /* TODO: Check the times against localtime */
- /* TODO: errorcheck? */
- if (!x509_times(crt, &activation, &expiration)) {
- purple_debug_error("certificate",
- "Failed to get certificate times!\n");
- activation = expiration = 0;
-#if GLIB_CHECK_VERSION(2,26,0)
- act_dt = g_date_time_new_from_unix_local(activation);
- activ_str = g_date_time_format(act_dt, "%c");
- g_date_time_unref(act_dt);
- exp_dt = g_date_time_new_from_unix_local(expiration);
- expir_str = g_date_time_format(exp_dt, "%c");
- g_date_time_unref(exp_dt);
- activ_str = g_strdup(ctime(&activation));
- expir_str = g_strdup(ctime(&expiration));
- text = g_strdup_printf(_("Common name: %s\n\n"
- "Fingerprint (SHA1): %s\n\n"
- "Activation date: %s\n"
- "Expiration date: %s\n"),
- sha_asc ? sha_asc : "(null)",
- activ_str ? activ_str : "(null)",
- expir_str ? expir_str : "(null)");
- g_byte_array_free(sha_bin, TRUE);
static PurpleCertificateScheme x509_nss = {
"x509", /* Scheme name */
N_("X.509 Certificates"), /* User-visible scheme name */
@@ -1024,7 +962,6 @@
x509_times, /* Activation/Expiration time */
x509_importcerts_from_file, /* Multiple certificate import function */
x509_get_der_data, /* Binary DER data */
- x509_display_string, /* Display representation */
--- a/libpurple/protocols/jabber/iq.c Fri Jun 27 01:07:11 2014 +0530
+++ b/libpurple/protocols/jabber/iq.c Wed Jul 09 11:42:34 2014 +0530
@@ -290,17 +290,19 @@
* be a valid match if any of the following is true:
* - Request 'to' matches reply 'from' (including the case where
- * - Request 'to' was empty and reply 'from' is server JID.
+ * - Request 'to' was my JID (bare or full) and reply 'from' is empty. * - Request 'to' was empty and reply 'from' is my JID. The spec says
* we should only allow bare JID, but we also allow full JID for
* compatibility with some servers.
+ * - Request 'to' was empty and reply 'from' is server JID. Not allowed by + * any spec, but for compatibility with some servers. * These rules should allow valid IQ replies while preventing spoofed
* For more discussion see the "Spoofing of iq ids and misbehaving
* servers" email thread from January 2014 on the jdev and security
+ * mailing lists. Also see https://developer.pidgin.im/ticket/15879 * @return TRUE if this reply is valid for the given request.
@@ -311,6 +313,12 @@
+ if (!from && purple_strequal(to->node, js->user->node) + && purple_strequal(to->domain, js->user->domain)) { + /* Request 'to' was my JID (bare or full) and reply 'from' is empty */ if (!to && purple_strequal(from->domain, js->user->domain)) {
/* Request 'to' is empty and reply 'from' domain matches our domain */