From: Christos Tsantilas Date: Tue, 18 Jun 2013 10:23:41 +0000 (+0300) Subject: Sending root certificate for validation X-Git-Tag: SQUID_3_4_0_1~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4747ea4c85cdc60e5668592f2915528c4af563b9;p=thirdparty%2Fsquid.git Sending root certificate for validation This patch modify squid cert validation subsystem to sent to cert validator helper the complete certificates chain, not only the certificates sent by web server. This is may not be possible in all cases, for example in cases where the root certificate is not stored localy. Also this patch includes a small optimization, it checks for domain mismatch error only when the checked (current) certificate is the server certificate. This is a Measurement Factory project --- diff --git a/src/globals.h b/src/globals.h index 2967d45eaf..8ce56aa10d 100644 --- a/src/globals.h +++ b/src/globals.h @@ -136,6 +136,7 @@ extern int ssl_ex_index_cert_error_check; /* -1 */ extern int ssl_ex_index_ssl_error_detail; /* -1 */ extern int ssl_ex_index_ssl_peeked_cert; /* -1 */ extern int ssl_ex_index_ssl_errors; /* -1 */ +extern int ssl_ex_index_ssl_cert_chain; /* -1 */ extern const char *external_acl_message; /* NULL */ extern int opt_send_signal; /* -1 */ diff --git a/src/ssl/cert_validate_message.cc b/src/ssl/cert_validate_message.cc index 15e5213354..18ede8297d 100644 --- a/src/ssl/cert_validate_message.cc +++ b/src/ssl/cert_validate_message.cc @@ -1,5 +1,6 @@ #include "squid.h" #include "acl/FilledChecklist.h" +#include "globals.h" #include "helper.h" #include "ssl/support.h" #include "ssl/cert_validate_message.h" @@ -10,7 +11,11 @@ Ssl::CertValidationMsg::composeRequest(CertValidationRequest const &vcert) { body.clear(); body += Ssl::CertValidationMsg::param_host + "=" + vcert.domainName; - STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(vcert.ssl); + STACK_OF(X509) *peerCerts = static_cast(SSL_get_ex_data(vcert.ssl, ssl_ex_index_ssl_cert_chain)); + + if (!peerCerts) + peerCerts = SSL_get_peer_cert_chain(vcert.ssl); + if (peerCerts) { Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem())); for (int i = 0; i < sk_X509_num(peerCerts); ++i) { diff --git a/src/ssl/support.cc b/src/ssl/support.cc index ebdbc634a8..8ccb139832 100644 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@ -242,7 +242,8 @@ ssl_verify_cb(int ok, X509_STORE_CTX * ctx) if (ok) { debugs(83, 5, "SSL Certificate signature OK: " << buffer); - if (server) { + // Check for domain mismatch only if the current certificate is the peer certificate. + if (server && peer_cert == X509_STORE_CTX_get_current_cert(ctx)) { if (!Ssl::checkX509ServerValidity(peer_cert, server)) { debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << buffer << " does not match domainname " << server); ok = 0; @@ -298,8 +299,15 @@ ssl_verify_cb(int ok, X509_STORE_CTX * ctx) } // If the certificate validator is used then we need to allow all errors and // pass them to certficate validator for more processing - else if (Ssl::TheConfig.ssl_crt_validator) + else if (Ssl::TheConfig.ssl_crt_validator) { ok = 1; + // Check if we have stored certificates chain. Store if not. + if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_cert_chain)) { + STACK_OF(X509) *certStack = X509_STORE_CTX_get1_chain(ctx); + if (certStack && !SSL_set_ex_data(ssl, ssl_ex_index_ssl_cert_chain, certStack)) + sk_X509_pop_free(certStack, X509_free); + } + } } if (!dont_verify_domain && server) {} @@ -643,6 +651,17 @@ ssl_free_SslErrors(void *, void *ptr, CRYPTO_EX_DATA *, delete errs; } +/// \ingroup ServerProtocolSSLInternal +/// Callback handler function to release STACK_OF(X509) "ex" data stored +/// in an SSL object. +static void +ssl_free_CertChain(void *, void *ptr, CRYPTO_EX_DATA *, + int, long, void *) +{ + STACK_OF(X509) *certsChain = static_cast (ptr); + sk_X509_pop_free(certsChain,X509_free); +} + // "free" function for X509 certificates static void ssl_free_X509(void *, void *ptr, CRYPTO_EX_DATA *, @@ -693,6 +712,7 @@ ssl_initialize(void) ssl_ex_index_ssl_error_detail = SSL_get_ex_new_index(0, (void *) "ssl_error_detail", NULL, NULL, &ssl_free_ErrorDetail); ssl_ex_index_ssl_peeked_cert = SSL_get_ex_new_index(0, (void *) "ssl_peeked_cert", NULL, NULL, &ssl_free_X509); ssl_ex_index_ssl_errors = SSL_get_ex_new_index(0, (void *) "ssl_errors", NULL, NULL, &ssl_free_SslErrors); + ssl_ex_index_ssl_cert_chain = SSL_get_ex_new_index(0, (void *) "ssl_cert_chain", NULL, NULL, &ssl_free_CertChain); } /// \ingroup ServerProtocolSSLInternal