diff options
author | Gary Kramlich <grim@reaperworld.com> | 2017-03-08 22:28:29 -0600 |
---|---|---|
committer | Gary Kramlich <grim@reaperworld.com> | 2017-03-08 22:28:29 -0600 |
commit | ff2531cebc99ea944f892368fc5e1cf599a51efc (patch) | |
tree | d6c0ded58ca5bc58a46cda250c32682cdf4b940a | |
parent | 0ce6d2b3cbd42cd08bb56c9e8f6314e37170dd37 (diff) | |
parent | 35959ccef5a6f96ffac8ac7ef72d4f86599a81fc (diff) | |
download | pidgin-ff2531cebc99ea944f892368fc5e1cf599a51efc.tar.gz |
Merge the pubilc code
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | ChangeLog.API | 2 | ||||
-rw-r--r-- | libpurple/certificate.c | 27 | ||||
-rw-r--r-- | libpurple/certificate.h | 24 | ||||
-rw-r--r-- | libpurple/plugins/ssl/ssl-gnutls.c | 41 | ||||
-rw-r--r-- | libpurple/plugins/ssl/ssl-nss.c | 1 |
6 files changed, 96 insertions, 0 deletions
@@ -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 = |