pidgin/pidgin

Merge the pubilc code
release-2.x.y
2017-03-08, Gary Kramlich
d49ec3c44a2e
Merge the pubilc code
--- a/ChangeLog Wed Mar 08 22:26:46 2017 -0600
+++ b/ChangeLog Wed Mar 08 22:28:29 2017 -0600
@@ -29,6 +29,7 @@
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
--- a/ChangeLog.API Wed Mar 08 22:26:46 2017 -0600
+++ b/ChangeLog.API Wed Mar 08 22:28:29 2017 -0600
@@ -6,7 +6,9 @@
* 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:
--- a/libpurple/certificate.c Wed Mar 08 22:26:46 2017 -0600
+++ b/libpurple/certificate.c Wed Mar 08 22:28:29 2017 -0600
@@ -508,6 +508,24 @@
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 @@
* 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 @@
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;
--- a/libpurple/certificate.h Wed Mar 08 22:26:46 2017 -0600
+++ b/libpurple/certificate.h Wed Mar 08 22:28:29 2017 -0600
@@ -332,6 +332,16 @@
* @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 @@
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);
+
/*@}*/
/*****************************************************************************/
--- a/libpurple/plugins/ssl/ssl-gnutls.c Wed Mar 08 22:26:46 2017 -0600
+++ b/libpurple/plugins/ssl/ssl-gnutls.c Wed Mar 08 22:28:29 2017 -0600
@@ -1232,6 +1232,46 @@
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 @@
NULL,
sizeof(PurpleCertificateScheme), /* struct_size */
x509_sha256sum, /* SHA256 fingerprint */
+ x509_compare_pubkeys, /* Compare public keys */
};
static PurpleSslOps ssl_ops =
--- a/libpurple/plugins/ssl/ssl-nss.c Wed Mar 08 22:26:46 2017 -0600
+++ b/libpurple/plugins/ssl/ssl-nss.c Wed Mar 08 22:28:29 2017 -0600
@@ -1225,6 +1225,7 @@
x509_verify_cert, /* Verify that the specified cert chain is trusted */
sizeof(PurpleCertificateScheme), /* struct_size */
x509_sha256sum, /* SHA256 fingerprint */
+ NULL,
};
static PurpleSslOps ssl_ops =