From: Christos Tsantilas Date: Tue, 8 Nov 2011 13:40:26 +0000 (+0200) Subject: Detail SSL handshake failures X-Git-Tag: BumpSslServerFirst.take01~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8e9bae996d43eb5703ec0bf2fa1aa8bb37872dd1;p=thirdparty%2Fsquid.git Detail SSL handshake failures This patch allows Squid to provide details for the %D macro on the secure connect failed error page when an SSL handshake with the origin server fails. The default %D text is "Handshake with SSL server failed: XYZ" where XYZ is the corresponding error string/description returned by OpenSSL if there is any. This is a Measurement Factory project. --- 8e9bae996d43eb5703ec0bf2fa1aa8bb37872dd1 diff --cc errors/templates/error-details.txt index c4a11b7725,c4a11b7725..dc1d3b47b3 --- a/errors/templates/error-details.txt +++ b/errors/templates/error-details.txt @@@ -1,3 -1,3 +1,7 @@@ ++name: SQUID_ERR_SSL_HANDSHAKE ++detail: "%ssl_error_descr: %ssl_lib_error" ++descr: "Handshake with SSL server failed" ++ name: SQUID_X509_V_ERR_DOMAIN_MISMATCH detail: "%ssl_error_descr: %ssl_subject" descr: "Certificate does not match domainname" diff --cc src/forward.cc index 5e24d333b1,5e24d333b1..e647de2287 --- a/src/forward.cc +++ b/src/forward.cc @@@ -581,11 -581,11 +581,17 @@@ FwdState::handleUnregisteredServerEnd( void FwdState::negotiateSSL(int fd) { ++ unsigned long ssl_lib_error = SSL_ERROR_NONE; SSL *ssl = fd_table[fd].ssl; int ret; if ((ret = SSL_connect(ssl)) <= 0) { int ssl_error = SSL_get_error(ssl, ret); ++#ifdef EPROTO ++ int sysErrNo = EPROTO; ++#else ++ int sysErrNo = EACCES; ++#endif switch (ssl_error) { @@@ -597,18 -597,18 +603,22 @@@ Comm::SetSelect(fd, COMM_SELECT_WRITE, fwdNegotiateSSLWrapper, this, 0); return; -- default: ++ case SSL_ERROR_SSL: ++ case SSL_ERROR_SYSCALL: ++ ssl_lib_error = ERR_get_error(); debugs(81, 1, "fwdNegotiateSSL: Error negotiating SSL connection on FD " << fd << -- ": " << ERR_error_string(ERR_get_error(), NULL) << " (" << ssl_error << ++ ": " << ERR_error_string(ssl_lib_error, NULL) << " (" << ssl_error << "/" << ret << "/" << errno << ")"); -- ErrorState *const anErr = makeConnectingError(ERR_SECURE_CONNECT_FAIL); --#ifdef EPROTO -- anErr->xerrno = EPROTO; --#else ++ // store/report errno when ssl_error is SSL_ERROR_SYSCALL, ssl_lib_error is 0, and ret is -1 ++ if (ssl_error == SSL_ERROR_SYSCALL && ret == -1 && ssl_lib_error == 0) ++ sysErrNo = errno; -- anErr->xerrno = EACCES; --#endif ++ // falling through to complete error handling ++ ++ default: ++ ErrorState *const anErr = makeConnectingError(ERR_SECURE_CONNECT_FAIL); ++ anErr->xerrno = sysErrNo; Ssl::ErrorDetail *errFromFailure = (Ssl::ErrorDetail *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail); if (errFromFailure != NULL) { @@@ -617,6 -617,6 +627,16 @@@ // Copy errFromFailure to a new Ssl::ErrorDetail object anErr->detail = new Ssl::ErrorDetail(*errFromFailure); } ++ else { ++ // clientCert can be be NULL ++ X509 *client_cert = SSL_get_peer_certificate(ssl); ++ anErr->detail = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, client_cert); ++ if (client_cert) ++ X509_free(client_cert); ++ } ++ ++ if (ssl_lib_error != SSL_ERROR_NONE) ++ anErr->detail->setLibError(ssl_lib_error); fail(anErr); diff --cc src/ssl/ErrorDetail.cc index a748b45fb1,a748b45fb1..09612fdbbc --- a/src/ssl/ErrorDetail.cc +++ b/src/ssl/ErrorDetail.cc @@@ -10,12 -10,12 +10,14 @@@ struct SslErrorEntry const char *name; }; --static const char *SslErrorDetailDefaultStr = "SSL certificate validation error (%err_name): %ssl_subject"; ++static const char *SslErrorDetailDefaultStr = "SSL handshake error (%err_name)"; //Use std::map to optimize search typedef std::map SslErrors; SslErrors TheSslErrors; static SslErrorEntry TheSslErrorArray[] = { ++ {SQUID_ERR_SSL_HANDSHAKE, ++ "SQUID_ERR_SSL_HANDSHAKE"}, {SQUID_X509_V_ERR_DOMAIN_MISMATCH, "SQUID_X509_V_ERR_DOMAIN_MISMATCH"}, {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, @@@ -149,6 -149,6 +151,7 @@@ Ssl::ErrorDetail::err_frm_code Ssl::Err {"ssl_notafter", &Ssl::ErrorDetail::notafter}, {"err_name", &Ssl::ErrorDetail::err_code}, {"ssl_error_descr", &Ssl::ErrorDetail::err_descr}, ++ {"ssl_lib_error", &Ssl::ErrorDetail::err_lib_error}, {NULL,NULL} }; @@@ -267,16 -267,16 +270,25 @@@ const char *Ssl::ErrorDetail::err_descr return "[Not available]"; } ++const char *Ssl::ErrorDetail::err_lib_error() const ++{ ++ if (lib_error_no != SSL_ERROR_NONE) ++ return ERR_error_string(lib_error_no, NULL); ++ else ++ return "[No Error]"; ++} ++ /** * It converts the code to a string value. Currently the following * formating codes are supported: -- * %err_name: The name of the SSL error ++ * %err_name: The name of a high-level SSL error (e.g., X509_V_ERR_*) * %ssl_error_descr: A short description of the SSL error * %ssl_cn: The comma-separated list of common and alternate names * %ssl_subject: The certificate subject * %ssl_ca_name: The certificate issuer name * %ssl_notbefore: The certificate "not before" field * %ssl_notafter: The certificate "not after" field ++ * %ssl_lib_error: human-readable low-level error string by ERR_error_string(3SSL) \retval the length of the code (the number of characters will be replaced by value) */ int Ssl::ErrorDetail::convert(const char *code, const char **value) const @@@ -337,9 -337,9 +349,11 @@@ const String &Ssl::ErrorDetail::toStrin CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509); peer_cert.reset(cert); */ --Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert): error_no (err_no) ++Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert): error_no (err_no), lib_error_no(SSL_ERROR_NONE) { -- peer_cert.reset(X509_dup(cert)); ++ if (cert) ++ peer_cert.reset(X509_dup(cert)); ++ detailEntry.error_no = SSL_ERROR_NONE; } @@@ -353,4 -353,4 +367,6 @@@ Ssl::ErrorDetail::ErrorDetail(Ssl::Erro } detailEntry = anErrDetail.detailEntry; ++ ++ lib_error_no = anErrDetail.lib_error_no; } diff --cc src/ssl/ErrorDetail.h index ecef450003,ecef450003..94c84072bf --- a/src/ssl/ErrorDetail.h +++ b/src/ssl/ErrorDetail.h @@@ -52,6 -52,6 +52,8 @@@ public void useRequest(HttpRequest *aRequest) { if (aRequest != NULL) request = aRequest;} /// The error name to embed in squid error pages const char *errorName() const {return err_code();} ++ ///Sets the low-level error returned by OpenSSL ERR_get_error() ++ void setLibError(unsigned long lib_err_no) {lib_error_no = lib_err_no;} private: typedef const char * (ErrorDetail::*fmt_action_t)() const; @@@ -73,12 -73,12 +75,14 @@@ const char *notafter() const; const char *err_code() const; const char *err_descr() const; ++ const char *err_lib_error() const; int convert(const char *code, const char **value) const; void buildDetail() const; mutable String errDetailStr; ///< Caches the error detail message ssl_error_t error_no; ///< The error code ++ unsigned long lib_error_no; ///< low-level error returned by OpenSSL ERR_get_error(3SSL) X509_Pointer peer_cert; ///< A pointer to the peer certificate mutable ErrorDetailEntry detailEntry; HttpRequest::Pointer request; diff --cc src/ssl/support.h index e2df0bddde,e2df0bddde..beeb87928a --- a/src/ssl/support.h +++ b/src/ssl/support.h @@@ -56,9 -56,9 +56,10 @@@ */ // Custom SSL errors; assumes all official errors are positive ++#define SQUID_ERR_SSL_HANDSHAKE -2 #define SQUID_X509_V_ERR_DOMAIN_MISMATCH -1 // All SSL errors range: from smallest (negative) custom to largest SSL error --#define SQUID_SSL_ERROR_MIN SQUID_X509_V_ERR_DOMAIN_MISMATCH ++#define SQUID_SSL_ERROR_MIN SQUID_ERR_SSL_HANDSHAKE #define SQUID_SSL_ERROR_MAX INT_MAX namespace Ssl