]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Detail SSL handshake failures
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Tue, 8 Nov 2011 13:40:26 +0000 (15:40 +0200)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Tue, 8 Nov 2011 13:40:26 +0000 (15:40 +0200)
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.

1  2 
errors/templates/error-details.txt
src/forward.cc
src/ssl/ErrorDetail.cc
src/ssl/ErrorDetail.h
src/ssl/support.h

index c4a11b77251e636a725504898e07caa0bb7d70b5,c4a11b77251e636a725504898e07caa0bb7d70b5..dc1d3b47b395c6699c31e45eab4474e4ac84e88e
@@@ -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 5e24d333b11ada802b08f72e48474d79a8de2da0,5e24d333b11ada802b08f72e48474d79a8de2da0..e647de2287d275ff593c8de92aec04f2407ff1b1
@@@ -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) {
  
              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) {
                  // 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);
  
index a748b45fb1360c4d970f0a95f4ee035c7bbe74cb,a748b45fb1360c4d970f0a95f4ee035c7bbe74cb..09612fdbbc6e7c428784baf6f6281aa09810ec6a
@@@ -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<Ssl::ssl_error_t, const SslErrorEntry *> 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;
  }
index ecef450003b477614aecb086e51656dd56543f36,ecef450003b477614aecb086e51656dd56543f36..94c84072bfd8d324ded5d70f58425ade20e34b5f
@@@ -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;
      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;
index e2df0bdddeb5f755f640fa593d44408dd9c59a78,e2df0bdddeb5f755f640fa593d44408dd9c59a78..beeb87928ac6e08e2e3160fd4d8b7ac49784b713
   */
  
  // 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