pidgin: 9fa808b5: A better solution for verifying certific...

darkrain42 at pidgin.im darkrain42 at pidgin.im
Wed Jul 22 03:36:08 EDT 2009


-----------------------------------------------------------------
Revision: 9fa808b57669d76c0989b16c2568cb7a7047511e
Ancestor: 7c0f8ebeda0f59bd50e8e1692886616f302badcf
Author: darkrain42 at pidgin.im
Date: 2009-07-22T06:03:31
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/9fa808b57669d76c0989b16c2568cb7a7047511e

Modified files:
        libpurple/certificate.c

ChangeLog: 

A better solution for verifying certificate chains with NSS 3.12.3.

Instead of allowing weak certificate algorithms all over the place,
which is what the NSS flag we are enabling, short-circuit a verification
a step early if the fingerprint of the last-checked certificate matches
its signer's certificate (retrieved from the trusted CA pool).

Closes #9360.

-------------- next part --------------
============================================================
--- libpurple/certificate.c	5c07a25d7df9b5505c21df968c1898031ca4931b
+++ libpurple/certificate.c	8646af2653a15c831619b6e2660b3898fd7b5504
@@ -293,6 +293,16 @@ purple_certificate_export(const gchar *f
 	return (scheme->export_certificate)(filename, crt);
 }
 
+static gboolean
+byte_arrays_equal(const GByteArray *array1, const GByteArray *array2)
+{
+	g_return_val_if_fail(array1 != NULL, FALSE);
+	g_return_val_if_fail(array2 != NULL, FALSE);
+
+	return (array1->len == array2->len) &&
+		(0 == memcmp(array1->data, array2->data, array1->len));
+}
+	
 GByteArray *
 purple_certificate_get_fingerprint_sha1(PurpleCertificate *crt)
 {
@@ -1306,6 +1316,7 @@ x509_tls_cached_unknown_peer(PurpleCerti
 	GList *chain = vrq->cert_chain;
 	GList *last;
 	gchar *ca_id;
+	GByteArray *last_fingerprint, *ca_fingerprint;
 
 	peer_crt = (PurpleCertificate *) chain->data;
 
@@ -1399,8 +1410,26 @@ x509_tls_cached_unknown_peer(PurpleCerti
 
 	g_free(ca_id);
 
-	/* Check the signature */
-	if ( !purple_certificate_signed_by(end_crt, ca_crt) ) {
+	/*
+	 * Check the fingerprints; if they match, then this certificate *is* one
+	 * of the designated "trusted roots", and we don't need to verify the
+	 * signature. This is good because some of the older roots are self-signed
+	 * with bad hash algorithms that we don't want to allow in any other
+	 * circumstances (one of Verisign's root CAs is self-signed with MD2).
+	 *
+	 * If the fingerprints don't match, we'll fall back to checking the
+	 * signature.
+	 *
+	 * GnuTLS doesn't seem to include the final root in the verification
+	 * list, so this check will never succeed.  NSS *does* include it in
+	 * the list, so here we are.
+	 */
+	last_fingerprint = purple_certificate_get_fingerprint_sha1(end_crt);
+	ca_fingerprint   = purple_certificate_get_fingerprint_sha1(ca_crt);
+
+	if ( !byte_arrays_equal(last_fingerprint, ca_fingerprint) &&
+			!purple_certificate_signed_by(end_crt, ca_crt) )
+	{
 		/* TODO: If signed_by ever returns a reason, maybe mention
 		   that, too. */
 		/* TODO: Also mention the CA involved. While I could do this
@@ -1425,9 +1454,15 @@ x509_tls_cached_unknown_peer(PurpleCerti
 		/* Signal "bad cert" */
 		purple_certificate_verify_complete(vrq,
 						   PURPLE_CERTIFICATE_INVALID);
+
+		g_byte_array_free(ca_fingerprint, TRUE);
+		g_byte_array_free(last_fingerprint, TRUE);
 		return;
 	} /* if (CA signature not good) */
 
+	g_byte_array_free(ca_fingerprint, TRUE);
+	g_byte_array_free(last_fingerprint, TRUE);
+
 	/* Last, check that the hostname matches */
 	if ( ! purple_certificate_check_subject_name(peer_crt,
 						     vrq->subject_name) ) {


More information about the Commits mailing list