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