]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
merge from trunk r12441
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Tue, 13 Nov 2012 18:13:50 +0000 (20:13 +0200)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Tue, 13 Nov 2012 18:13:50 +0000 (20:13 +0200)
12 files changed:
1  2 
configure.ac
src/cf.data.pre
src/forward.cc
src/forward.h
src/main.cc
src/ssl/Config.h
src/ssl/Makefile.am
src/ssl/cert_validate_message.h
src/ssl/crtd_message.h
src/ssl/helper.cc
src/ssl/helper.h
src/ssl/support.cc

diff --cc configure.ac
Simple merge
diff --cc src/cf.data.pre
Simple merge
diff --cc src/forward.cc
index 638bdbc68a983b6e56c019655b33ce9df17bc681,bb056dd83372d874e653cb98a37437d911901ecf..2cf3e81bcc09b392fbab11ba4fb4398d8c518735
  #include "neighbors.h"
  #include "pconn.h"
  #include "PeerSelectState.h"
- #include "protos.h"
+ #include "SquidConfig.h"
  #include "SquidTime.h"
  #include "Store.h"
+ #include "StoreClient.h"
+ #include "urn.h"
  #include "whois.h"
  #if USE_SSL
 +#include "ssl/cert_validate_message.h"
 +#include "ssl/Config.h"
 +#include "ssl/helper.h"
  #include "ssl/support.h"
  #include "ssl/ErrorDetail.h"
  #include "ssl/ServerBump.h"
@@@ -759,191 -739,9 +742,191 @@@ FwdState::negotiateSSL(int fd
          serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
      }
  
-             Ssl::CertValidationMsg requestMsg;
 +#if 1 // USE_SSL_CERT_VALIDATOR
 +    if (Ssl::TheConfig.ssl_crt_validator) {
 +        Ssl::CertValidationRequest validationRequest;
 +        // WARNING: The STACK_OF(*) OpenSSL objects does not support locking.
 +        // If we need to support locking we need to sk_X509_dup the STACK_OF(X509)
 +        // list and lock all of the X509 members of the list.
 +        // Currently we do not use any locking for any of the members of the
 +        // Ssl::CertValidationRequest class. If the ssl object gone, the value returned
 +        // from SSL_get_peer_cert_chain may not exist any more. In this code the
 +        // Ssl::CertValidationRequest object used only to pass data to
 +        // Ssl::CertValidationHelper::submit method.
 +        validationRequest.peerCerts = SSL_get_peer_cert_chain(ssl);
 +        validationRequest.domainName = request->GetHost();
 +        if (Ssl::Errors *errs = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
 +            // validationRequest disappears on return so no need to cbdataReference
 +            validationRequest.errors = errs;
 +        else
 +            validationRequest.errors = NULL;
 +        try {
 +            debugs(83, 5, HERE << "Sending SSL certificate for validation to ssl_crtvd.");
++            Ssl::CertValidationMsg requestMsg(Ssl::CrtdMessage::REQUEST);
 +            requestMsg.setCode(Ssl::CertValidationMsg::code_cert_validate);
 +            requestMsg.composeRequest(validationRequest);
 +            debugs(83, 5, HERE << "SSL crtvd request: " << requestMsg.compose().c_str());
 +            Ssl::CertValidationHelper::GetInstance()->sslSubmit(requestMsg, sslCrtvdHandleReplyWrapper, this);
 +            return;
 +        } catch (const std::exception &e) {
 +            debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
 +                   "request for " << validationRequest.domainName <<
 +                   " certificate: " << e.what() << "; will now block to " <<
 +                   "validate that certificate.");
 +            // fall through to do blocking in-process generation.
 +            ErrorState *anErr = new ErrorState(ERR_GATEWAY_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
 +            fail(anErr);
 +            if (serverConnection()->getPeer()) {
 +                peerConnectFailed(serverConnection()->getPeer());
 +            }
 +            serverConn->close();
 +            self = NULL;
 +            return;
 +        }
 +    }
 +#endif // USE_SSL_CERT_VALIDATOR
 +
      dispatch();
  }
  
- FwdState::sslCrtvdHandleReplyWrapper(void *data, char *reply)
 +#if 1 // USE_SSL_CERT_VALIDATOR
 +void
- FwdState::sslCrtvdHandleReply(const char *reply)
++FwdState::sslCrtvdHandleReplyWrapper(void *data, const HelperReply &reply)
 +{
 +    FwdState * fwd = (FwdState *)(data);
 +    fwd->sslCrtvdHandleReply(reply);
 +}
 +
 +void
-     if (!reply) {
++FwdState::sslCrtvdHandleReply(const HelperReply &reply)
 +{
 +    Ssl::Errors *errs = NULL;
 +    Ssl::ErrorDetail *errDetails = NULL;
 +    bool validatorFailed = false;
 +    if (!Comm::IsConnOpen(serverConnection())) {
 +        return;
 +    }
 +    SSL *ssl = fd_table[serverConnection()->fd].ssl;
 +
-         Ssl::CertValidationMsg replyMsg;
++    if (!reply.other().hasContent()) {
 +        debugs(83, 1, HERE << "\"ssl_crtvd\" helper return <NULL> reply");
 +        validatorFailed = true;
 +    } else {
-         if (replyMsg.parse(reply, strlen(reply)) != Ssl::CrtdMessage::OK ||
++        Ssl::CertValidationMsg replyMsg(Ssl::CrtdMessage::REPLY);
 +        Ssl::CertValidationResponse validationResponse;
 +        std::string error;
 +        STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(ssl);
-             if (replyMsg.getCode() == "OK") {
++        if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
 +                !replyMsg.parseResponse(validationResponse, peerCerts, error) ) {
 +            debugs(83, 5, HERE << "Reply from ssl_crtvd for " << request->GetHost() << " is incorrect");
 +            validatorFailed = true;
 +        } else {
-             } else if (replyMsg.getCode() == "ERR") {
++            if (reply.result == HelperReply::Okay) {
 +                debugs(83, 5, HERE << "Certificate for " << request->GetHost() << " was successfully validated from ssl_crtvd");
++            } else if (reply.result == HelperReply::Error) {
 +                debugs(83, 5, HERE << "Certificate for " << request->GetHost() << " found buggy by ssl_crtvd");
 +                errs = sslCrtvdCheckForErrors(validationResponse, errDetails);
 +            } else {
 +                debugs(83, 5, HERE << "Certificate for " << request->GetHost() << " cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
 +                validatorFailed = true;
 +            }
 +
 +            if (!errDetails && !validatorFailed) {
 +                dispatch();
 +                return;
 +            }
 +        }
 +    }
 +
 +    ErrorState *anErr = NULL;
 +    if (validatorFailed) {
 +        anErr = new ErrorState(ERR_GATEWAY_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
 +    }  else {
 +
 +        // Check the list error with
 +        if (errDetails && request->clientConnectionManager.valid()) {
 +            // remember the server certificate from the ErrorDetail object
 +            if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
 +                // remember validation errors, if any
 +                if (errs) {
 +                    if (serverBump->sslErrors)
 +                        cbdataReferenceDone(serverBump->sslErrors);
 +                    serverBump->sslErrors = cbdataReference(errs);
 +                }
 +            }
 +        }
 +
 +        anErr = makeConnectingError(ERR_SECURE_CONNECT_FAIL);
 +        anErr->detail = errDetails;
 +        /*anErr->xerrno= Should preserved*/
 +    }
 +
 +    fail(anErr);
 +    if (serverConnection()->getPeer()) {
 +        peerConnectFailed(serverConnection()->getPeer());
 +    }
 +    serverConn->close();
 +    self = NULL;
 +    return;
 +}
 +
 +/// Checks errors in the cert. validator response against sslproxy_cert_error.
 +/// The first honored error, if any, is returned via errDetails parameter.
 +/// The method returns all seen errors except SSL_ERROR_NONE as Ssl::Errors.
 +Ssl::Errors *
 +FwdState::sslCrtvdCheckForErrors(Ssl::CertValidationResponse &resp, Ssl::ErrorDetail *& errDetails)
 +{
 +    Ssl::Errors *errs = NULL;
 +
 +    ACLFilledChecklist *check = NULL;
 +    if (acl_access *acl = Config.ssl_client.cert_error)
 +        check = new ACLFilledChecklist(acl, request, dash_str);
 +
 +    SSL *ssl = fd_table[serverConnection()->fd].ssl;
 +    typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
 +    for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
 +        debugs(83, 7, "Error item: " << i->error_no << " " << i->error_reason);
 +
 +        if (i->error_no == SSL_ERROR_NONE)
 +            continue; //ignore????
 +
 +        if (!errDetails) {
 +            bool allowed = false;
 +            if (check) {
 +                check->sslErrors = new Ssl::Errors(i->error_no);
 +                if (check->fastCheck() == ACCESS_ALLOWED)
 +                    allowed = true;
 +            }
 +            // else the Config.ssl_client.cert_error access list is not defined
 +            // and the first error will cause the error page
 +
 +            if (allowed) {
 +                debugs(83, 3, "bypassing SSL error " << i->error_no << " in " << "buffer");
 +            } else {
 +                debugs(83, 5, "confirming SSL error " << i->error_no);
 +                X509 *brokenCert = i->cert;
 +                X509 *peerCert = SSL_get_peer_certificate(ssl);
 +                const char *aReason = i->error_reason.empty() ? NULL : i->error_reason.c_str();
 +                errDetails = new Ssl::ErrorDetail(i->error_no, peerCert, brokenCert, aReason);
 +                X509_free(peerCert);
 +            }
 +            delete check->sslErrors;
 +            check->sslErrors = NULL;
 +        }
 +
 +        if (!errs)
 +            errs = new Ssl::Errors(i->error_no);
 +        else
 +            errs->push_back_unique(i->error_no);
 +    }
 +    if (check)
 +        delete check;
 +
 +    return errs;
 +}
 +
 +#endif // USE_SSL_CERT_VALIDATOR
 +
  void
  FwdState::initiateSSL()
  {
              Ssl::setClientSNI(ssl, hostname);
      }
  
 -    // Create the ACL check list now, while we have access to more info.
 -    // The list is used in ssl_verify_cb() and is freed in ssl_free().
 -    if (acl_access *acl = Config.ssl_client.cert_error) {
 -        ACLFilledChecklist *check = new ACLFilledChecklist(acl, request, dash_str);
 -        SSL_set_ex_data(ssl, ssl_ex_index_cert_error_check, check);
 +#if 1 // USE_SSL_CERT_VALIDATOR
 +    // If CertValidation Helper used do not lookup checklist for errors,
 +    // but keep a list of errors to send it to CertValidator
 +    if (!Ssl::TheConfig.ssl_crt_validator) {
 +#endif
 +        // Create the ACL check list now, while we have access to more info.
 +        // The list is used in ssl_verify_cb() and is freed in ssl_free().
 +        if (acl_access *acl = Config.ssl_client.cert_error) {
 +            ACLFilledChecklist *check = new ACLFilledChecklist(acl, request, dash_str);
-             if (Comm::IsConnOpen(clientConn))
-                 check->fd(clientConn->fd);
 +            SSL_set_ex_data(ssl, ssl_ex_index_cert_error_check, check);
 +        }
 +#if 1 // USE_SSL_CERT_VALIDATOR
      }
 +#endif
  
      // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
      X509 *peeked_cert;
diff --cc src/forward.h
index b0bae5e3dad60835b2698754334435aa3d1397c2,0a754c6ee9b720b8750944aebc17a0e56b6771d8..2c7ce764bae78cd2f20b826011c243581d290bc5
@@@ -2,14 -2,13 +2,17 @@@
  #define SQUID_FORWARD_H
  
  #include "Array.h"
+ #include "base/RefCount.h"
  #include "comm.h"
  #include "comm/Connection.h"
+ #include "err_type.h"
  #include "fde.h"
++#include "HelperReply.h"
+ #include "HttpStatusCode.h"
  #include "ip/Address.h"
- #include "RefCount.h"
 +#if USE_SSL
 +#include "ssl/support.h"
 +#endif
  
  /* forward decls */
  
@@@ -80,14 -71,6 +83,14 @@@ public
      /** return a ConnectionPointer to the current server connection (may or may not be open) */
      Comm::ConnectionPointer const & serverConnection() const { return serverConn; };
  
-     static void sslCrtvdHandleReplyWrapper(void *data, char *reply);
 +#if USE_SSL //&& USE_SSL_CERT_VALIDATOR
 +    /// Callback function called when squid receive message from cert validator helper
-     void sslCrtvdHandleReply(const char *reply);
++    static void sslCrtvdHandleReplyWrapper(void *data, const HelperReply &reply);
 +    /// Process response from cert validator helper
++    void sslCrtvdHandleReply(const HelperReply &reply);
 +    /// Check SSL errors returned from cert validator against sslproxy_cert_error access list
 +    Ssl::Errors *sslCrtvdCheckForErrors(Ssl::CertValidationResponse &, Ssl::ErrorDetail *&);
 +#endif
  private:
      // hidden for safer management of self; use static fwdStart
      FwdState(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp);
diff --cc src/main.cc
Simple merge
Simple merge
Simple merge
index 3d22aa64a917cba6af96a867b76fe1d5ad473722,0000000000000000000000000000000000000000..b2479bcaebf0fe53573ba842a442e5a979259d75
mode 100644,000000..100644
--- /dev/null
@@@ -1,116 -1,0 +1,116 @@@
-     CertValidationMsg(): CrtdMessage() {}
 +/*
 + * $Id$
 + */
 +
 +#ifndef SQUID_SSL_CERT_VALIDATE_MESSAGE_H
 +#define SQUID_SSL_CERT_VALIDATE_MESSAGE_H
 +
 +#include "ssl/support.h"
 +#include "ssl/crtd_message.h"
 +#include <vector>
 +
 +namespace Ssl
 +{
 +
 +/**
 + * This class is used to hold the required informations to build
 + * a request message for the certificate validator helper
 + */
 +class CertValidationRequest
 +{
 +public:
 +    STACK_OF(X509) *peerCerts; ///< The list of sent by SSL server
 +    Errors *errors; ///< The list of errors detected
 +    std::string domainName; ///< The server name
 +    CertValidationRequest() : peerCerts(NULL), errors(NULL) {}
 +};
 +
 +/**
 + * This class is used to store informations found in certificate validation
 + * response messages read from certificate validator helper
 + */
 +class CertValidationResponse
 +{
 +public:
 +    /**
 +     * This class used to hold error informations returned from
 +     * cert validator helper.
 +     */
 +    class  RecvdError
 +    {
 +    public:
 +        RecvdError(): id(0), error_no(SSL_ERROR_NONE), cert(NULL) {}
 +        RecvdError(const RecvdError &);
 +        ~RecvdError();
 +        RecvdError & operator = (const RecvdError &);
 +        void setCert(X509 *);  ///< Sets cert to the given certificate
 +        int id; ///<  The id of the error
 +        ssl_error_t error_no; ///< The OpenSSL error code
 +        std::string error_reason; ///< A string describing the error
 +        X509 *cert; ///< The broken certificate
 +    };
 +
 +    typedef std::vector<RecvdError> RecvdErrors;
 +
 +    /// Search in errors list for the error item with id=errorId.
 +    /// If none found a new RecvdError item added with the given id;
 +    RecvdError &getError(int errorId);
 +    RecvdErrors errors; ///< The list of parsed errors
 +};
 +
 +/**
 + * This class is responsible for composing or parsing messages destined to
 + * or comming from a cert validator helper.
 + * The messages format is:
 + *   <response/request code> <whitespace> <body length> <whitespace> <key=value> ...\1
 + */
 +class CertValidationMsg: public CrtdMessage
 +{
 +private:
 +    /**
 +     * This class used to hold the certId/cert pairs found
 +     * in cert validation messages.
 +     */
 +    class CertItem
 +    {
 +    public:
 +        std::string name; ///< The certificate Id to use
 +        X509 *cert;       ///< A pointer to certificate
 +        CertItem(): cert(NULL) {}
 +        CertItem(const CertItem &);
 +        CertItem & operator = (const CertItem &);
 +        ~CertItem();
 +        void setCert(X509 *); ///< Sets cert to the given certificate
 +    };
 +
 +public:
++    CertValidationMsg(MessageKind kind): CrtdMessage(kind) {}
 +
 +    /// Build a request message for the cert validation helper
 +    /// using informations provided by vcert object
 +    void composeRequest(CertValidationRequest const &vcert);
 +
 +    /// Parse a response message and fill the resp object with parsed informations
 +    bool parseResponse(CertValidationResponse &resp, STACK_OF(X509) *peerCerts, std::string &error);
 +
 +    /// Search a CertItems list for the certificate with ID "name"
 +    X509 *getCertByName(std::vector<CertItem> const &, std::string const & name);
 +
 +    /// String code for "cert_validate" messages
 +    static const std::string code_cert_validate;
 +    /// Parameter name for passing intended domain name
 +    static const std::string param_domain;
 +    /// Parameter name for passing SSL errors
 +    static const std::string param_error;
 +    /// Parameter name for passing SSL certificates
 +    static const std::string param_cert;
 +    /// Parameter name for passing the major SSL error
 +    static const std::string param_error_name;
 +    /// Parameter name for passing the error reason
 +    static const std::string param_error_reason;
 +    /// Parameter name for passing the error cert ID
 +    static const std::string param_error_cert;
 +};
 +
 +}//namespace Ssl
 +#endif // SQUID_SSL_CERT_VALIDATE_MESSAGE_H
Simple merge
index d42db1c7304a68ae49376f72383233fb9f8cdc84,dd6b00b90f1bcb04d6f6d58b0fcdfc36cd1ad513..1dbff287d02a75cf39019b6a0b6579f50f144cb9
@@@ -106,85 -104,3 +104,87 @@@ void Ssl::Helper::sslSubmit(CrtdMessag
      msg += '\n';
      helperSubmit(ssl_crtd, msg.c_str(), callback, data);
  }
-         callback(data, (char *)"error 45 Temporary network problem, please retry later");
 +
 +/*ssl_crtd_validator*/
 +
 +Ssl::CertValidationHelper * Ssl::CertValidationHelper::GetInstance()
 +{
 +    static Ssl::CertValidationHelper sslHelper;
 +    if (!Ssl::TheConfig.ssl_crt_validator)
 +        return NULL;
 +    return &sslHelper;
 +}
 +
 +Ssl::CertValidationHelper::CertValidationHelper() : ssl_crt_validator(NULL)
 +{
 +}
 +
 +Ssl::CertValidationHelper::~CertValidationHelper()
 +{
 +    Shutdown();
 +}
 +
 +void Ssl::CertValidationHelper::Init()
 +{
 +    assert(ssl_crt_validator == NULL);
 +
 +    // we need to start ssl_crtd only if some port(s) need to bump SSL
 +    bool found = false;
 +    for (AnyP::PortCfg *s = ::Config.Sockaddr.http; !found && s; s = s->next)
 +        found = s->sslBump;
 +    for (AnyP::PortCfg *s = ::Config.Sockaddr.https; !found && s; s = s->next)
 +        found = s->sslBump;
 +    if (!found)
 +        return;
 +
 +    ssl_crt_validator = new helper("ssl_crt_validator");
 +    ssl_crt_validator->childs.updateLimits(Ssl::TheConfig.ssl_crt_validator_Children);
 +    ssl_crt_validator->ipc_type = IPC_STREAM;
 +    // The crtd messages may contain the eol ('\n') character. We are
 +    // going to use the '\1' char as the end-of-message mark.
 +    ssl_crt_validator->eom = '\1';
 +    assert(ssl_crt_validator->cmdline == NULL);
 +    {
 +        char *tmp = xstrdup(Ssl::TheConfig.ssl_crt_validator);
 +        char *tmp_begin = tmp;
 +        char * token = NULL;
 +        while ((token = strwordtok(NULL, &tmp))) {
 +            wordlistAdd(&ssl_crt_validator->cmdline, token);
 +        }
 +        safe_free(tmp_begin);
 +    }
 +    helperOpenServers(ssl_crt_validator);
 +}
 +
 +void Ssl::CertValidationHelper::Shutdown()
 +{
 +    if (!ssl_crt_validator)
 +        return;
 +    helperShutdown(ssl_crt_validator);
 +    wordlistDestroy(&ssl_crt_validator->cmdline);
 +    delete ssl_crt_validator;
 +    ssl_crt_validator = NULL;
 +}
 +
 +void Ssl::CertValidationHelper::sslSubmit(CrtdMessage const & message, HLPCB * callback, void * data)
 +{
 +    static time_t first_warn = 0;
 +    assert(ssl_crt_validator);
 +
 +    if (ssl_crt_validator->stats.queue_size >= (int)(ssl_crt_validator->childs.n_running * 2)) {
 +        if (first_warn == 0)
 +            first_warn = squid_curtime;
 +        if (squid_curtime - first_warn > 3 * 60)
 +            fatal("SSL servers not responding for 3 minutes");
 +        debugs(83, 1, HERE << "Queue overload, rejecting");
++        const char *errMsg = "BH error 45 Temporary network problem, please retry later";
++        HelperReply failReply(errMsg,strlen(errMsg));
++        callback(data, failReply);
 +        return;
 +    }
 +
 +    first_warn = 0;
 +    std::string msg = message.compose();
 +    msg += '\n';
 +    helperSubmit(ssl_crt_validator, msg.c_str(), callback, data);
 +}
Simple merge
index d17ca751d36d118370863f8b399c22ce5296a0c4,8cc8b634750f9bb42f4b872b789259b7e02e5eb8..4b42d0278a23c99398170634669535e3daf9818d
@@@ -44,8 -42,7 +42,9 @@@
  #include "anyp/PortCfg.h"
  #include "fde.h"
  #include "globals.h"
 +#include "protos.h"
+ #include "SquidConfig.h"
 +#include "ssl/Config.h"
  #include "ssl/ErrorDetail.h"
  #include "ssl/support.h"
  #include "ssl/gadgets.h"