summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Kramlich <grim@reaperworld.com>2017-03-08 22:28:29 -0600
committerGary Kramlich <grim@reaperworld.com>2017-03-08 22:28:29 -0600
commitff2531cebc99ea944f892368fc5e1cf599a51efc (patch)
treed6c0ded58ca5bc58a46cda250c32682cdf4b940a
parent0ce6d2b3cbd42cd08bb56c9e8f6314e37170dd37 (diff)
parent35959ccef5a6f96ffac8ac7ef72d4f86599a81fc (diff)
downloadpidgin-ff2531cebc99ea944f892368fc5e1cf599a51efc.tar.gz
Merge the pubilc code
-rw-r--r--ChangeLog1
-rw-r--r--ChangeLog.API2
-rw-r--r--libpurple/certificate.c27
-rw-r--r--libpurple/certificate.h24
-rw-r--r--libpurple/plugins/ssl/ssl-gnutls.c41
-rw-r--r--libpurple/plugins/ssl/ssl-nss.c1
6 files changed, 96 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 9b0999be25..06f8540f90 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -29,6 +29,7 @@ version 2.12.0 (03/10/2017):
ended April 30th, 2015. A new protocol plugin has been written,
using a different method, to support Facebook. It can be found at
https://github.com/dequis/purple-facebook/wiki
+ * Fixed gnutls certificate validation errors that mainly affected google (Dequis)
General
* Replaced instances of d.pidgin.im with developer.pidgin.im and updated the
diff --git a/ChangeLog.API b/ChangeLog.API
index 2fff1c8182..44d18bc452 100644
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -6,7 +6,9 @@ version 2.12.0:
* PURPLE_MESSAGE_REMOTE_SEND in PurpleMessageFlags, to specify
messages like _SEND that were sent from another location.
* purple_certificate_get_fingerprint_sha256
+ * purple_certificate_compare_pubkeys
* PurpleCertificateScheme.get_fingerprint_sha256
+ * PurpleCertificateScheme.compare_pubkeys
* PURPLE_CERTIFICATE_SCHEME_HAS_FUNC
version 2.11.0:
diff --git a/libpurple/certificate.c b/libpurple/certificate.c
index 75ab93f6cf..f240b26ca1 100644
--- a/libpurple/certificate.c
+++ b/libpurple/certificate.c
@@ -508,6 +508,24 @@ purple_certificate_get_times(PurpleCertificate *crt, time_t *activation, time_t
return (scheme->get_times)(crt, activation, expiration);
}
+gboolean
+purple_certificate_compare_pubkeys(PurpleCertificate *crt1, PurpleCertificate *crt2)
+{
+ PurpleCertificateScheme *scheme;
+
+ g_return_val_if_fail(crt1 && crt2, FALSE);
+ g_return_val_if_fail(crt1->scheme && crt2->scheme, FALSE);
+ g_return_val_if_fail(crt1->scheme == crt2->scheme, FALSE);
+
+ scheme = crt1->scheme;
+
+ if (!(PURPLE_CERTIFICATE_SCHEME_HAS_FUNC(scheme, compare_pubkeys))) {
+ return FALSE;
+ }
+
+ return (scheme->compare_pubkeys)(crt1, crt2);
+}
+
gchar *
purple_certificate_pool_mkpath(PurpleCertificatePool *pool, const gchar *id)
{
@@ -1746,11 +1764,17 @@ x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq,
* signature.
*/
last_fpr = purple_certificate_get_fingerprint_sha256(end_crt, TRUE);
+
+ ca_id = purple_certificate_get_unique_id(end_crt);
+
for (cur = ca_crts; cur; cur = cur->next) {
ca_crt = cur->data;
ca_fpr = purple_certificate_get_fingerprint_sha256(ca_crt, TRUE);
+ ca2_id = purple_certificate_get_unique_id(ca_crt);
if ( byte_arrays_equal(last_fpr, ca_fpr) ||
+ (purple_strequal(ca_id, ca2_id) &&
+ purple_certificate_compare_pubkeys(end_crt, ca_crt)) ||
purple_certificate_signed_by(end_crt, ca_crt) )
{
/* TODO: If signed_by ever returns a reason, maybe mention
@@ -1760,11 +1784,14 @@ x509_tls_cached_unknown_peer(PurpleCertificateVerificationRequest *vrq,
user's poor, leaky eyes. */
valid = TRUE;
g_byte_array_free(ca_fpr, TRUE);
+ g_free(ca2_id);
break;
}
g_byte_array_free(ca_fpr, TRUE);
+ g_free(ca2_id);
}
+ g_free(ca_id);
if (valid == FALSE)
flags |= PURPLE_CERTIFICATE_INVALID_CHAIN;
diff --git a/libpurple/certificate.h b/libpurple/certificate.h
index 2ec9dc78fa..08b4bad323 100644
--- a/libpurple/certificate.h
+++ b/libpurple/certificate.h
@@ -332,6 +332,16 @@ struct _PurpleCertificateScheme
* @since 2.12.0
*/
GByteArray * (* get_fingerprint_sha256)(PurpleCertificate *crt);
+
+ /**
+ * Compares the public keys of two certificates
+ *
+ * @param crt1 A certificate instance
+ * @param crt2 Another certificate instance
+ * @return TRUE if both certificates have the same key, otherwise FALSE
+ * @since 2.12.0
+ */
+ gboolean (* compare_pubkeys)(PurpleCertificate *crt1, PurpleCertificate *crt2);
};
#define PURPLE_CERTIFICATE_SCHEME_HAS_FUNC(obj, member) \
@@ -674,6 +684,20 @@ purple_certificate_check_subject_name(PurpleCertificate *crt, const gchar *name)
gboolean
purple_certificate_get_times(PurpleCertificate *crt, time_t *activation, time_t *expiration);
+/**
+ * Compares the public keys of two certificates.
+ *
+ * If the SSL backend does not implement this function, it may return FALSE
+ * every time. This is the case with the NSS plugin, which doesn't need it.
+ *
+ * @param crt1 A certificate instance
+ * @param crt2 Another certificate instance
+ * @return TRUE if both certificates have the same key, otherwise FALSE
+ * @since 2.12.0
+ */
+gboolean
+purple_certificate_compare_pubkeys(PurpleCertificate *crt1, PurpleCertificate *crt2);
+
/*@}*/
/*****************************************************************************/
diff --git a/libpurple/plugins/ssl/ssl-gnutls.c b/libpurple/plugins/ssl/ssl-gnutls.c
index 86bdbb5fb8..54a6a23a62 100644
--- a/libpurple/plugins/ssl/ssl-gnutls.c
+++ b/libpurple/plugins/ssl/ssl-gnutls.c
@@ -1232,6 +1232,46 @@ x509_times (PurpleCertificate *crt, time_t *activation, time_t *expiration)
return success;
}
+/* GNUTLS_KEYID_USE_BEST_KNOWN was added in gnutls 3.4.1, but can't ifdef it
+ * because it's an enum member. Older versions will ignore it, which means
+ * using SHA1 instead of SHA256 to compare pubkeys. But hey, not my fault. */
+#if GNUTLS_VERSION_NUMBER < 0x030401
+#define KEYID_FLAG (1<<30)
+#else
+#define KEYID_FLAG GNUTLS_KEYID_USE_BEST_KNOWN
+#endif
+
+static gboolean
+x509_compare_pubkeys (PurpleCertificate *crt1, PurpleCertificate *crt2)
+{
+ gnutls_x509_crt_t crt_dat1, crt_dat2;
+ unsigned char buffer1[64], buffer2[64];
+ size_t size1, size2;
+ size1 = size2 = sizeof(buffer1);
+
+ g_return_val_if_fail(crt1 && crt2, FALSE);
+ g_return_val_if_fail(crt1->scheme == &x509_gnutls, FALSE);
+ g_return_val_if_fail(crt2->scheme == &x509_gnutls, FALSE);
+
+ crt_dat1 = X509_GET_GNUTLS_DATA(crt1);
+
+ if (gnutls_x509_crt_get_key_id(crt_dat1, KEYID_FLAG, buffer1, &size1) != 0) {
+ return FALSE;
+ }
+
+ crt_dat2 = X509_GET_GNUTLS_DATA(crt2);
+
+ if (gnutls_x509_crt_get_key_id(crt_dat2, KEYID_FLAG, buffer2, &size2) != 0) {
+ return FALSE;
+ }
+
+ if (size1 != size2) {
+ return FALSE;
+ }
+
+ return memcmp(buffer1, buffer2, size1) == 0;
+}
+
/* X.509 certificate operations provided by this plugin */
static PurpleCertificateScheme x509_gnutls = {
"x509", /* Scheme name */
@@ -1253,6 +1293,7 @@ static PurpleCertificateScheme x509_gnutls = {
NULL,
sizeof(PurpleCertificateScheme), /* struct_size */
x509_sha256sum, /* SHA256 fingerprint */
+ x509_compare_pubkeys, /* Compare public keys */
};
static PurpleSslOps ssl_ops =
diff --git a/libpurple/plugins/ssl/ssl-nss.c b/libpurple/plugins/ssl/ssl-nss.c
index 88f87abdf7..9501dbe410 100644
--- a/libpurple/plugins/ssl/ssl-nss.c
+++ b/libpurple/plugins/ssl/ssl-nss.c
@@ -1225,6 +1225,7 @@ static PurpleCertificateScheme x509_nss = {
x509_verify_cert, /* Verify that the specified cert chain is trusted */
sizeof(PurpleCertificateScheme), /* struct_size */
x509_sha256sum, /* SHA256 fingerprint */
+ NULL,
};
static PurpleSslOps ssl_ops =