changeset 30959:43af903bd816

NSS will not return invalid or irrelevant intermediate certificates that the server presented as part of the certificate chain. GnuTLS, however, will return them, which breaks our certificate validation when the server is mis-configured. This fixes our GnuTLS SSL plugin to discard any certificate (and subsequent certs) in the chain if it did not sign the previous certificate. This allows GnuTLS users to connect to omega.contacts.msn.com while it is still misconfigured.
author Stu Tomlinson <stu@nosnilmot.com>
date Tue, 23 Nov 2010 01:50:30 +0000
parents a467e55ec3c7
children 27c56e6b5fa6
files libpurple/plugins/ssl/ssl-gnutls.c
diffstat 1 files changed, 18 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/plugins/ssl/ssl-gnutls.c	Mon Nov 22 10:50:32 2010 +0000
+++ b/libpurple/plugins/ssl/ssl-gnutls.c	Tue Nov 23 01:50:30 2010 +0000
@@ -520,11 +520,18 @@
 /* Forward declarations are fun! */
 static PurpleCertificate *
 x509_import_from_datum(const gnutls_datum dt, gnutls_x509_crt_fmt mode);
+/* indeed! */
+static gboolean
+x509_certificate_signed_by(PurpleCertificate * crt,
+			   PurpleCertificate * issuer);
+static void
+x509_destroy_certificate(PurpleCertificate * crt);
 
 static GList *
 ssl_gnutls_get_peer_certificates(PurpleSslConnection * gsc)
 {
 	PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc);
+	PurpleCertificate *prvcrt = NULL;
 
 	/* List of Certificate instances to return */
 	GList * peer_certs = NULL;
@@ -550,7 +557,17 @@
 		/* Append is somewhat inefficient on linked lists, but is easy
 		   to read. If someone complains, I'll change it.
 		   TODO: Is anyone complaining? (Maybe elb?) */
-		peer_certs = g_list_append(peer_certs, newcrt);
+		/* only append if previous cert was actually signed by this one.
+		 * Thanks Microsoft. */
+		if ((prvcrt == NULL) || x509_certificate_signed_by(prvcrt, newcrt)) {
+			peer_certs = g_list_append(peer_certs, newcrt);
+			prvcrt = newcrt;
+		} else {
+			x509_destroy_certificate(newcrt);
+			purple_debug_error("gnutls", "Dropping further peer certificates "
+			                             "because the chain is broken!\n");
+			break;
+		}
 	}
 
 	/* cert_list doesn't need free()-ing */