--- a/libpurple/plugins/ssl/ssl-gnutls.c Tue Oct 07 00:57:07 2014 +0530 +++ b/libpurple/plugins/ssl/ssl-gnutls.c Wed Nov 26 16:01:25 2014 +0530 @@ -118,6 +118,9 @@ static GHashTable *host_priorities = NULL; #endif +static gchar *x509_cert_dn(PurpleCertificate *crt); +static gchar *x509_issuer_dn(PurpleCertificate *crt); + static void ssl_gnutls_log(int level, const char *str) { @@ -1024,7 +1027,7 @@ crt_dat = X509_GET_GNUTLS_DATA(crt); issuer_dat = X509_GET_GNUTLS_DATA(issuer); - /* First, let's check that crt.issuer is actually issuer */ + /* Ensure crt issuer matches the name on the issuer cert. */ ret = gnutls_x509_crt_check_issuer(crt_dat, issuer_dat); if (ret <= 0) { @@ -1034,10 +1037,9 @@ ret); } else { gchar *crt_id, *issuer_id, *crt_issuer_id; - crt_id = purple_certificate_get_unique_id(crt); - issuer_id = purple_certificate_get_unique_id(issuer); - crt_issuer_id = - purple_certificate_get_issuer_unique_id(crt); + crt_id = x509_cert_dn(crt); + issuer_id = x509_cert_dn(issuer); + crt_issuer_id = x509_issuer_dn(crt); purple_debug_info("gnutls/x509", "Certificate %s is issued by " "%s, which does not match %s.\n", @@ -1053,6 +1055,41 @@ return FALSE; } + /* Check basic constraints extension (if it exists then the CA flag must + be set to true, and it must exist for certs with version 3 or higher. */ + ret = gnutls_x509_crt_get_basic_constraints(issuer_dat, NULL, NULL, NULL); + if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + if (gnutls_x509_crt_get_version(issuer_dat) >= 3) { + /* Reject cert (no basic constraints and cert version is >= 3). */ + gchar *issuer_id = x509_cert_dn(issuer); + purple_debug_info("gnutls/x509", "Rejecting cert because the " + "basic constraints extension is missing from issuer cert " + "for %s. The basic constraints extension is required on " + "all version 3 or higher certs (this cert is version %d).", + issuer_id ? issuer_id : "(null)", + gnutls_x509_crt_get_version(issuer_dat)); + g_free(issuer_id); + return FALSE; + } else { + /* Allow cert (no basic constraints and cert version is < 3). */ + purple_debug_info("gnutls/x509", "Basic constraint extension is " + "missing from issuer cert for %s. Allowing this because " + "the cert is version %d and the basic constraints " + "extension is only required for version 3 or higher " + "certs.", issuer_id ? issuer_id : "(null)", + gnutls_x509_crt_get_version(issuer_dat)); + } + } else if (ret <= 0) { + /* Reject cert (CA flag is false in basic constraints). */ + gchar *issuer_id = x509_cert_dn(issuer); + purple_debug_info("gnutls/x509", "Rejecting cert because the CA flag " + "is set to false in the basic constraints extension for " + "issuer cert %s. ret=%d\n", + issuer_id ? issuer_id : "(null)", ret); + g_free(issuer_id); + return FALSE; + } + /* Now, check the signature */ /* The second argument is a ptr to an array of "trusted" issuer certs, but we're only using one trusted one */ @@ -1078,8 +1115,8 @@ * perfectly clear as soon as someone looks at the debug log is * generated. */ - crt_id = purple_certificate_get_unique_id(crt); - issuer_id = purple_certificate_get_issuer_unique_id(crt); + crt_id = x509_cert_dn(crt); + issuer_id = x509_issuer_dn(crt); purple_debug_warning("gnutls/x509", "Insecure hash algorithm used by %s to sign %s\n", issuer_id, crt_id); @@ -1090,9 +1127,9 @@ /* Signature didn't check out, but at least there were no errors*/ if (!crt_id) - crt_id = purple_certificate_get_unique_id(crt); + crt_id = x509_cert_dn(crt); if (!issuer_id) - issuer_id = purple_certificate_get_issuer_unique_id(crt); + issuer_id = x509_issuer_dn(crt); purple_debug_error("gnutls/x509", "Bad signature from %s on %s\n", issuer_id, crt_id); @@ -1338,8 +1375,11 @@ x509_times, /* Activation/Expiration time */ x509_importcerts_from_file, /* Multiple certificates import function */ x509_get_der_data, /* Binary DER data */ - - NULL + NULL, /* register_trusted_tls_cert */ + NULL, /* verify_cert */ + NULL, /* _purple_reserved1 */ + NULL, /* _purple_reserved2 */ + NULL /* _purple_reserved3 */ };