]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
sslproxy_cert_adapt squid.conf option
authorChristos Tsantilas <chtsanti@users.sourceforge.net>
Sat, 21 Jan 2012 10:11:43 +0000 (12:11 +0200)
committerChristos Tsantilas <chtsanti@users.sourceforge.net>
Sat, 21 Jan 2012 10:11:43 +0000 (12:11 +0200)
This patch add the sslproxy_cert_adapt option to squid.conf which gives to
squid administrators the required functionality to "fix" a known broken
certificate using acls.
Currently only the "Not After", "Not Before" and "Common Name" fields of a
certificate can be modified/fixed.

The sslproxy_cert_adapt option has the form:
   sslproxy_cert_adapt <adaptation algorithm> acl ...
where <adaptation algorithm> is one of the setValidAfter, setValidBefore and
setCommonName.

    setValidAfter: sets the "Not After" property to the signing cert's
                   "Not After" property.
    setValidBefore: sets the "Not Before" property to the signing cert's
                   "Not After" property.
    setCommonName: sets certificate Subject.CN property to the host name
                   from specified as a CN parameter (setCommonName{CN}) or,
                   if no explicit CN parameter was specified, extracted from
                   the CONNECT request

When the acl(s) match, the corresponding adaptation algorithm is applied to
the fake/generated certificate. Otherwise, the default mimicking action takes
place.

25 files changed:
src/AclRegs.cc
src/acl/FilledChecklist.cc
src/acl/FilledChecklist.h
src/acl/SslError.cc
src/acl/SslError.h
src/acl/SslErrorData.cc
src/acl/SslErrorData.h
src/cache_cf.cc
src/cf.data.depend
src/cf.data.pre
src/client_side.cc
src/client_side.h
src/forward.cc
src/globals.h
src/ssl/certificate_db.cc
src/ssl/certificate_db.h
src/ssl/crtd_message.cc
src/ssl/crtd_message.h
src/ssl/gadgets.cc
src/ssl/gadgets.h
src/ssl/ssl_crtd.cc
src/ssl/support.cc
src/ssl/support.h
src/structs.h
src/typedefs.h

index ae4faabb4a74d5143d3819980306483b395a392e..6a03e6baaa59836854ffd2db80992440ddbdbd6e 100644 (file)
@@ -137,7 +137,7 @@ ACLStrategised<int> ACLUrlPort::RegistryEntry_(new ACLIntRange, ACLUrlPortStrate
 
 #if USE_SSL
 ACL::Prototype ACLSslError::RegistryProtoype(&ACLSslError::RegistryEntry_, "ssl_error");
-ACLStrategised<int> ACLSslError::RegistryEntry_(new ACLSslErrorData, ACLSslErrorStrategy::Instance(), "ssl_error");
+ACLStrategised<Ssl::Errors const &> ACLSslError::RegistryEntry_(new ACLSslErrorData, ACLSslErrorStrategy::Instance(), "ssl_error");
 ACL::Prototype ACLCertificate::UserRegistryProtoype(&ACLCertificate::UserRegistryEntry_, "user_cert");
 ACLStrategised<SSL *> ACLCertificate::UserRegistryEntry_(new ACLCertificateData (sslGetUserAttribute), ACLCertificateStrategy::Instance(), "user_cert");
 ACL::Prototype ACLCertificate::CARegistryProtoype(&ACLCertificate::CARegistryEntry_, "ca_cert");
index e061e8c638cd6a159875590bd38b3e506f3203f2..084bcf749b8cd317758e6d83868295613cea6536 100644 (file)
@@ -62,9 +62,6 @@ ACLFilledChecklist::ACLFilledChecklist() :
 #endif
 #if SQUID_SNMP
         snmp_community(NULL),
-#endif
-#if USE_SSL
-        ssl_error(0),
 #endif
         extacl_entry (NULL),
         conn_(NULL),
@@ -174,9 +171,6 @@ ACLFilledChecklist::ACLFilledChecklist(const acl_access *A, HttpRequest *http_re
 #endif
 #if SQUID_SNMP
         snmp_community(NULL),
-#endif
-#if USE_SSL
-        ssl_error(0),
 #endif
         extacl_entry (NULL),
         conn_(NULL),
index 9ffccbcb61e98637b758a45603220e6c8ea057a9..3ec833128b3ec5d6bf52882d5f7f3eaca8941e3d 100644 (file)
@@ -5,6 +5,9 @@
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
+#if USE_SSL
+#include "ssl/support.h"
+#endif
 
 class ExternalACLEntry;
 class ConnStateData;
@@ -63,7 +66,7 @@ public:
 #endif
 
 #if USE_SSL
-    int ssl_error;
+    Ssl::Errors sslErrorList;
 #endif
 
     ExternalACLEntry *extacl_entry;
index 33041e6d1767b7ff7b036b8bab030811a891f8e6..b50ed75e64bfc15095caa07d18d248f016797ed8 100644 (file)
@@ -11,7 +11,7 @@
 int
 ACLSslErrorStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
-    return data->match (checklist->ssl_error);
+    return data->match (checklist->sslErrorList);
 }
 
 ACLSslErrorStrategy *
index e18cf1c7bcaf84dc85d1789fec581f69531de223..0fff38076bcfaf9384e3303dd9f0e948ebe897ae 100644 (file)
@@ -7,8 +7,9 @@
 #define SQUID_ACLSSL_ERROR_H
 #include "acl/Strategy.h"
 #include "acl/Strategised.h"
+#include "ssl/support.h"
 
-class ACLSslErrorStrategy : public ACLStrategy<int>
+class ACLSslErrorStrategy : public ACLStrategy<Ssl::Errors const&>
 {
 
 public:
@@ -31,7 +32,7 @@ class ACLSslError
 
 private:
     static ACL::Prototype RegistryProtoype;
-    static ACLStrategised<int> RegistryEntry_;
+    static ACLStrategised<Ssl::Errors const&> RegistryEntry_;
 };
 
 #endif /* SQUID_ACLSSL_ERROR_H */
index 820ed646afdc4545c064ed6b437f5aafcf34ced9..ad2a0043f7d56b8e4126eadb98cc00cad088975c 100644 (file)
@@ -22,9 +22,14 @@ ACLSslErrorData::~ACLSslErrorData()
 }
 
 bool
-ACLSslErrorData::match(Ssl::ssl_error_t toFind)
+ACLSslErrorData::match(Ssl::Errors const &toFind)
 {
-    return values->findAndTune (toFind);
+    typedef std::vector<Ssl::ssl_error_t>::const_iterator SEsI;
+    for (SEsI it = toFind.begin() ; it != toFind.end(); it++ ) {
+        if (values->findAndTune (*it))
+            return true;
+    }
+    return false;
 }
 
 /* explicit instantiation required for some systems */
@@ -67,7 +72,7 @@ ACLSslErrorData::empty() const
     return values == NULL;
 }
 
-ACLData<Ssl::ssl_error_t> *
+ACLSslErrorData *
 ACLSslErrorData::clone() const
 {
     /* Splay trees don't clone yet. */
index 1f21a7ceae0fe94b48d1f94b0ff162ecf45b72d1..0673049d3a8fe646450f637da81d60e25e9bc1b0 100644 (file)
@@ -10,8 +10,9 @@
 #include "CbDataList.h"
 #include "ssl/support.h"
 #include "ssl/ErrorDetail.h"
+#include <vector>
 
-class ACLSslErrorData : public ACLData<Ssl::ssl_error_t>
+class ACLSslErrorData : public ACLData<Ssl::Errors const&>
 {
 
 public:
@@ -21,11 +22,11 @@ public:
     ACLSslErrorData(ACLSslErrorData const &);
     ACLSslErrorData &operator= (ACLSslErrorData const &);
     virtual ~ACLSslErrorData();
-    bool match(Ssl::ssl_error_t);
+    bool match(Ssl::Errors const &);
     wordlist *dump();
     void parse();
     bool empty() const;
-    virtual ACLData<Ssl::ssl_error_t> *clone() const;
+    virtual  ACLSslErrorData *clone() const;
 
     CbDataList<Ssl::ssl_error_t> *values;
 };
index add7c03dd2f54d21c905d56548649c93806fadba..189aa0ffe40d152f0a7e0f2de2a4a7c68b8f08e5 100644 (file)
@@ -197,6 +197,9 @@ static void free_http_port_list(http_port_list **);
 static void parse_https_port_list(https_port_list **);
 static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
 static void free_https_port_list(https_port_list **);
+static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
+static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt);
+static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
 #if 0
 static int check_null_https_port_list(const https_port_list *);
 #endif
@@ -4521,4 +4524,82 @@ static void free_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
     cfg->service_failure_limit = 0;
 }
 
+#if USE_SSL
+static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
+{
+    char *al;
+    sslproxy_cert_adapt *ca = (sslproxy_cert_adapt *) xcalloc(1, sizeof(sslproxy_cert_adapt));
+    if ((al = strtok(NULL, w_space)) == NULL) {
+        self_destruct();
+        return;
+    }
+    
+    const char *param;
+    if ( char *s = strchr(al, '{')) {
+        *s = '\0'; // terminate the al string
+        s++;
+        param = s;
+        s = strchr(s, '}');
+        if (!s) {
+            self_destruct();
+            return;
+        }
+        *s = '\0';
+    }
+    else
+        param = NULL;
+
+    if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidAfter]) == 0) {
+        ca->alg = Ssl::algSetValidAfter;
+        ca->param = strdup("on");
+    }
+    else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidBefore]) == 0) {
+        ca->alg = Ssl::algSetValidBefore;
+        ca->param = strdup("on");
+    }
+    else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetCommonName]) == 0) {
+        ca->alg = Ssl::algSetCommonName;
+        if (param) {
+            ca->param = strdup(param);
+        }
+    } else {
+        debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: unknown cert adaptation algorithm: " << al);
+        self_destruct();
+        return;
+    }
+
+    aclParseAclList(LegacyParser, &ca->aclList);
+
+    while(*cert_adapt)
+        cert_adapt = &(*cert_adapt)->next;
+
+    *cert_adapt = ca;
+}
+
+static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt)
+{
+    for (sslproxy_cert_adapt *ca = cert_adapt; ca != NULL; ca = ca->next) {
+        storeAppendPrintf(entry, "%s ", name);
+        storeAppendPrintf(entry, "%s{%s} ", Ssl::sslCertAdaptAlgoritm(ca->alg), ca->param);
+        if (ca->aclList)
+            dump_acl_list(entry, ca->aclList);
+        storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
+{
+    while(*cert_adapt) {
+        sslproxy_cert_adapt *ca = *cert_adapt;
+        *cert_adapt = ca->next;
+        safe_free(ca->param);
+
+        if (ca->aclList)
+            aclDestroyAclList(&ca->aclList);
+
+        safe_free(ca);
+    }
+}
+#endif
+
 #endif
index 9409d54712ffc8cb9f775bbdcae9b4cf8962eca2..478390aef9f88d6d46ce747c621e71082fa11191 100644 (file)
@@ -69,3 +69,4 @@ wccp2_amethod
 wccp2_service
 wccp2_service_info
 wordlist
+sslproxy_cert_adapt    acl
index e400801cec64d70d91bd0eb4e668fed1a2e871aa..0b45881252f8d2c57a2ddabc3e00b60cbfd7c616 100644 (file)
@@ -2052,6 +2052,35 @@ DOC_START
        Default setting:  sslproxy_cert_error deny all
 DOC_END
 
+NAME: sslproxy_cert_adapt 
+IFDEF: USE_SSL
+DEFAULT: none
+TYPE: sslproxy_cert_adapt
+LOC: Config.ssl_client.cert_adapt
+DOC_START
+       
+       sslproxy_cert_adapt <adaptation algorithm> acl ...
+
+       The following certificate adaptation algorithms supported:
+          setValidAfter
+               sets the "Not After" property to the "Not After" propery of
+               the ca certificate used to sign generated certificates
+          setValidBefore
+               sets the "Not Before" property to the "Not Before" property of
+               the ca certificate used to sign generated certificates
+          setCommonName
+               sets certificate Subject.CN property to the
+               host name  from specified as a CN parameter (setCommonName{CN})
+               or, if no explicit CN parameter was specified, extracted from
+               the CONNECT request. It is a misconfiguration to use setName
+               without an explicit parameter for intercepted or tproxied SSL
+               transactions. 
+               
+       When the acl(s) match, the corresponding adaptation algorithm is
+       applied to the fake/generated certificate. Otherwise, the
+       default mimicking action takes place.
+DOC_END
+
 NAME: sslpassword_program
 IFDEF: USE_SSL
 DEFAULT: none
index 7eb28aceda43249e908a39a40dac85278568f7fa..35f33e3bfc4a069c619e0439b61260f3e0aa4ff1 100644 (file)
@@ -3615,12 +3615,12 @@ ConnStateData::sslCrtdHandleReply(const char * reply)
     } else {
         Ssl::CrtdMessage reply_message;
         if (reply_message.parse(reply, strlen(reply)) != Ssl::CrtdMessage::OK) {
-            debugs(33, 5, HERE << "Reply from ssl_crtd for " << sslHostName << " is incorrect");
+            debugs(33, 5, HERE << "Reply from ssl_crtd for " << sslConnectHostOrIp << " is incorrect");
         } else {
             if (reply_message.getCode() != "OK") {
-                debugs(33, 5, HERE << "Certificate for " << sslHostName << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
+                debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
             } else {
-                debugs(33, 5, HERE << "Certificate for " << sslHostName << " was successfully recieved from ssl_crtd");
+                debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " was successfully recieved from ssl_crtd");
                 SSL_CTX *ctx = Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str());
                 getSslContextDone(ctx, true);
                 return;
@@ -3630,34 +3630,91 @@ ConnStateData::sslCrtdHandleReply(const char * reply)
     getSslContextDone(NULL);
 }
 
+void ConnStateData::buildSslCertAdaptParams(Ssl::CrtdMessage::BodyParams &certAdaptParams)
+{
+    // Build a key to use for storing/retrieving certificates to cache
+    sslBumpCertKey = sslCommonName.defined() ? sslCommonName : sslConnectHostOrIp;
+
+    // fake certificate adaptation requires bump-server-first mode
+    if (!bumpServerFirstErrorEntry())
+        return;
+
+    HttpRequest *fakeRequest =  new HttpRequest();
+    fakeRequest->SetHost(sslConnectHostOrIp.termedBuf());
+    fakeRequest->port = clientConnection->local.GetPort();
+    fakeRequest->protocol = AnyP::PROTO_HTTPS;
+    ACLFilledChecklist checklist(NULL, fakeRequest, 
+                                 clientConnection != NULL ? clientConnection->rfc931 : dash_str);
+    checklist.conn(this);
+    checklist.src_addr = clientConnection->remote;
+    checklist.my_addr = clientConnection->local;
+    checklist.sslErrorList = bumpSslErrorNoList;
+
+    for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
+        if (ca->aclList && checklist.fastCheck(ca->aclList) == ACCESS_ALLOWED) {
+            const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
+            const char *param = ca->param;
+  
+            // if already set ignore
+            if (certAdaptParams.find(alg) != certAdaptParams.end())
+                continue;
+
+            // if not param defined for Common Name adaptation use hostname from 
+            // the CONNECT request
+            if (!param && ca->alg == Ssl::algSetCommonName)
+                param = sslConnectHostOrIp.termedBuf();
+
+            assert(alg && param);
+            debugs(33, 5, HERE << "Matches certificate adaptation aglorithm: " << 
+                   alg << " param: " << param);
+
+            // append to the certificate adaptation parameters
+            certAdaptParams.insert( std::make_pair(alg, param));
+
+            // And also build the key used to store certificate to cache.
+            sslBumpCertKey.append("+");
+            sslBumpCertKey.append(alg);
+            sslBumpCertKey.append("=");
+            sslBumpCertKey.append(param);
+        }
+    }    
+}
+
 void
 ConnStateData::getSslContextStart()
 {
-    char const * host = sslHostName.termedBuf();
-    if (port->generateHostCertificates && host && strcmp(host, "") != 0) {
-        debugs(33, 5, HERE << "Finding SSL certificate for " << host << " in cache");
+    if (port->generateHostCertificates) {
+        Ssl::CrtdMessage::BodyParams certAdaptParams;
+        buildSslCertAdaptParams(certAdaptParams);
+        assert(sslBumpCertKey.defined() && sslBumpCertKey[0] != '\0');
+
+            debugs(33, 5, HERE << "Finding SSL certificate for " << sslBumpCertKey << " in cache");
         Ssl::LocalContextStorage & ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
-        SSL_CTX * dynCtx = ssl_ctx_cache.find(host);
+        SSL_CTX * dynCtx = ssl_ctx_cache.find(sslBumpCertKey.termedBuf());
         if (dynCtx) {
-            debugs(33, 5, HERE << "SSL certificate for " << host << " have found in cache");
+            debugs(33, 5, HERE << "SSL certificate for " << sslBumpCertKey << " have found in cache");
             if (Ssl::verifySslCertificate(dynCtx, bumpServerCert.get())) {
-                debugs(33, 5, HERE << "Cached SSL certificate for " << host << " is valid");
+                debugs(33, 5, HERE << "Cached SSL certificate for " << sslBumpCertKey << " is valid");
                 getSslContextDone(dynCtx);
                 return;
             } else {
-                debugs(33, 5, HERE << "Cached SSL certificate for " << host << " is out of date. Delete this certificate from cache");
-                ssl_ctx_cache.remove(host);
+                debugs(33, 5, HERE << "Cached SSL certificate for " << sslBumpCertKey << " is out of date. Delete this certificate from cache");
+                ssl_ctx_cache.remove(sslBumpCertKey.termedBuf());
             }
         } else {
-            debugs(33, 5, HERE << "SSL certificate for " << host << " haven't found in cache");
+            debugs(33, 5, HERE << "SSL certificate for " << sslBumpCertKey << " haven't found in cache");
         }
 
+        char const * host = sslCommonName.defined() ? sslCommonName.termedBuf() : sslConnectHostOrIp.termedBuf();
 #if USE_SSL_CRTD
         debugs(33, 5, HERE << "Generating SSL certificate for " << host << " using ssl_crtd.");
         Ssl::CrtdMessage request_message;
         request_message.setCode(Ssl::CrtdMessage::code_new_certificate);
         Ssl::CrtdMessage::BodyParams map;
         map.insert(std::make_pair(Ssl::CrtdMessage::param_host, host));
+        /*Append parameters for cert adaptation*/
+        map.insert(certAdaptParams.begin(), certAdaptParams.end());
         std::string bufferToWrite;
         Ssl::writeCertAndPrivateKeyToMemory(port->signingCert, port->signPkey, bufferToWrite);
         if (bumpServerCert.get()) {
@@ -3665,11 +3722,12 @@ ConnStateData::getSslContextStart()
             debugs(33, 5, HERE << "Append Mimic Certificate to body request: " << bufferToWrite);
         }
         request_message.composeBody(map, bufferToWrite);
+        debugs(33, 5, HERE << "SSL crtd request: " << request_message.compose().c_str());
         Ssl::Helper::GetInstance()->sslSubmit(request_message, sslCrtdHandleReplyWrapper, this);
         return;
 #else
         debugs(33, 5, HERE << "Generating SSL certificate for " << host);
-        dynCtx = Ssl::generateSslContext(host, bumpServerCert, port->signingCert, port->signPkey);
+        dynCtx = Ssl::generateSslContext(host, bumpServerCert, port->signingCert, port->signPkey, certAdaptParams);
         getSslContextDone(dynCtx, true);
         return;
 #endif //USE_SSL_CRTD
@@ -3686,13 +3744,14 @@ ConnStateData::getSslContextDone(SSL_CTX * sslContext, bool isNew)
         Ssl::addChainToSslContext(sslContext, port->certsToChain.get());
 
         Ssl::LocalContextStorage & ssl_ctx_cache(Ssl::TheGlobalContextStorage.getLocalStorage(port->s));
-        if (sslContext && sslHostName != "") {
-            if (!ssl_ctx_cache.add(sslHostName.termedBuf(), sslContext)) {
+        assert(sslBumpCertKey.defined() && sslBumpCertKey[0] != '\0');
+        if (sslContext) {
+            if (!ssl_ctx_cache.add(sslBumpCertKey.termedBuf(), sslContext)) {
                 // If it is not in storage delete after using. Else storage deleted it.
                 fd_table[clientConnection->fd].dynamicSslContext = sslContext;
             }
         } else {
-            debugs(33, 2, HERE << "Failed to generate SSL cert for " << sslHostName);
+            debugs(33, 2, HERE << "Failed to generate SSL cert for " << sslConnectHostOrIp);
         }
     }
 
@@ -3725,7 +3784,8 @@ ConnStateData::switchToHttps(const char *host, const int port)
 {
     assert(!switchedToHttps_);
 
-    sslHostName = host;
+    sslConnectHostOrIp = host;
+    sslCommonName = host;
 
     //HTTPMSGLOCK(currentobject->http->request);
     assert(areAllContextsForThisConnection());
@@ -3741,7 +3801,7 @@ ConnStateData::switchToHttps(const char *host, const int port)
     const bool alwaysBumpServerFirst = true;
     if (alwaysBumpServerFirst) {
         Must(!httpsPeeker.set());
-        httpsPeeker = new Ssl::ServerPeeker(this, sslHostName.termedBuf(), port);
+        httpsPeeker = new Ssl::ServerPeeker(this, sslConnectHostOrIp.termedBuf(), port);
         bumpErrorEntry = httpsPeeker->storeEntry();
         Must(bumpErrorEntry);
         bumpErrorEntry->lock();
@@ -3750,7 +3810,7 @@ ConnStateData::switchToHttps(const char *host, const int port)
         return;
     }
 
-    // otherwise, use sslHostName
+    // otherwise, use sslConnectHostOrIp
     getSslContextStart();
 }
 
@@ -3764,16 +3824,16 @@ ConnStateData::httpsPeeked(Comm::ConnectionPointer serverConnection)
         assert(ssl);
         Ssl::X509_Pointer serverCert(SSL_get_peer_certificate(ssl));
         assert(serverCert.get() != NULL);
-        sslHostName = Ssl::CommonHostName(serverCert.get());
-        assert(sslHostName.defined());
-        debugs(33, 5, HERE << "found HTTPS server " << sslHostName << " at bumped " <<
+        sslCommonName = Ssl::CommonHostName(serverCert.get());
+        assert(sslCommonName.defined());
+        debugs(33, 5, HERE << "found HTTPS server CN " << sslCommonName << " at bumped " <<
                *serverConnection);
 
         pinConnection(serverConnection, NULL, NULL, false);
 
-        debugs(33, 5, HERE << "bumped HTTPS server: " << sslHostName);
+        debugs(33, 5, HERE << "bumped HTTPS server: " << sslConnectHostOrIp);
     } else
-        debugs(33, 5, HERE << "Error while bumped HTTPS server: " << sslHostName);
+        debugs(33, 5, HERE << "Error while bumped HTTPS server: " << sslConnectHostOrIp);
 
     if (httpsPeeker.valid())
         httpsPeeker->noteHttpsPeeked(serverConnection);
index 8df9c59de7a9679e4253c795d829df058aa2c222..b0d4591dadb36aefb849c892dfd59e0463796941 100644 (file)
@@ -335,6 +335,10 @@ public:
     StoreEntry *bumpServerFirstErrorEntry() const {return bumpErrorEntry;}
     void setBumpServerCert(X509 *serverCert) {bumpServerCert.reset(serverCert);}
     X509 *getBumpServerCert() {return bumpServerCert.get();}
+    void setBumpSslErrorList(Ssl::Errors &errNoList) {bumpSslErrorNoList = errNoList;}
+    /// Fill the certAdaptParams with the required data for certificate adaptation
+    /// and create the key for storing/retrieve the certificate to/from the cache
+    void buildSslCertAdaptParams(Ssl::CrtdMessage::BodyParams &certAdaptParams);
     bool serveDelayedError(ClientSocketContext *context);
 #else
     bool switchedToHttps() const { return false; }
@@ -360,12 +364,16 @@ private:
 
 #if USE_SSL
     bool switchedToHttps_;
-    String sslHostName; ///< Host name for SSL certificate generation
+    /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
+    String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
+    String sslCommonName; ///< CN name for SSL certificate generation
+    String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
 
     /// a job that connects to the HTTPS server to get its SSL certificate
     CbcPointer<Ssl::ServerPeeker> httpsPeeker;
     StoreEntry *bumpErrorEntry;
     Ssl::X509_Pointer bumpServerCert;
+    Ssl::Errors bumpSslErrorNoList; ///< The list of SSL certificate errors which ignored
 #endif
 
     AsyncCall::Pointer reader; ///< set when we are reading
index 5f940df8a0bc8a23b08a9aac6236a22f48dcc2be..d372803a038529ae3dcd2fabb09b1dc8e0a28cbf 100644 (file)
@@ -668,6 +668,10 @@ FwdState::negotiateSSL(int fd)
                 // Get the server certificate from ErrorDetail object and store it 
                 // to connection manager
                 request->clientConnectionManager->setBumpServerCert(X509_dup(srvX509));
+
+                // if there is a list of ssl errors, pass it to connection manager
+                if (Ssl::Errors *errNoList = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno)))
+                    request->clientConnectionManager->setBumpSslErrorList(*errNoList);
             }
 
             HttpRequest *fakeRequest = NULL;
@@ -697,8 +701,11 @@ FwdState::negotiateSSL(int fd)
         }
     }
     
-    if (request->clientConnectionManager.valid())
+    if (request->clientConnectionManager.valid()) {
         request->clientConnectionManager->setBumpServerCert(SSL_get_peer_certificate(ssl));
+        if (Ssl::Errors *errNoList = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno)))
+            request->clientConnectionManager->setBumpSslErrorList(*errNoList);
+    }
 
     if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
         if (serverConnection()->getPeer()->sslSession)
index 048be61382d7b8e00bc1e8a56025b9fa33f9e142..c590922e91c21e075cb27bd56b2363dd221c793e 100644 (file)
@@ -156,6 +156,7 @@ extern "C" {
     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_error_sslerrno;   /* -1 */
 
     extern const char *external_acl_message;      /* NULL */
     extern int opt_send_signal;        /* -1 */
index c2237f1874abbb560a57abf855ce39edb271a8f9..d7f2955c03afc0be8ef2f2fab2f8fb7363a76a9e 100644 (file)
@@ -203,7 +203,7 @@ bool Ssl::CertificateDb::find(std::string const & host_name, Ssl::X509_Pointer &
     return pure_find(host_name, cert, pkey);
 }
 
-bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey)
+bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, std::string const & useName)
 {
     const Locker locker(dbLock, Here);
     load();
@@ -224,7 +224,7 @@ bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP
 
     {
         TidyPointer<char, tidyFree> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), NULL, 0));
-        if (pure_find(subject.get(), cert, pkey))
+        if (pure_find(useName.empty() ? subject.get() : useName, cert, pkey))
             return true;
     }
     // check db size.
@@ -241,7 +241,9 @@ bool Ssl::CertificateDb::addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP
     ASN1_UTCTIME * tm = X509_get_notAfter(cert.get());
     row.setValue(cnlExp_date, std::string(reinterpret_cast<char *>(tm->data), tm->length).c_str());
     row.setValue(cnlFile, "unknown");
-    {
+    if (!useName.empty())
+        row.setValue(cnlName, useName.c_str());
+    else {
         TidyPointer<char, tidyFree> subject(X509_NAME_oneline(X509_get_subject_name(cert.get()), NULL, 0));
         row.setValue(cnlName, subject.get());
     }
index 30352514313104e440999a20a7cf2ea1699e3582..1d247c9cc9f00f5a89688356ac23052eda028b5a 100644 (file)
@@ -96,7 +96,7 @@ public:
     /// Find certificate and private key for host name
     bool find(std::string const & host_name, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
     /// Save certificate to disk.
-    bool addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey);
+    bool addCertAndPrivateKey(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, std::string const & useName);
     /// Get a serial number to use for generating a new certificate.
     BIGNUM * getCurrentSerialNumber();
     /// Create and initialize a database  under the  db_path
index 1ade0a7ceafa96d6bef3cf1410cb14ffc50a55f5..f23c1aa2bb24b28689a5baec3d4ac563bb2d813f 100644 (file)
@@ -3,6 +3,7 @@
  */
 
 #include "config.h"
+#include "ssl/gadgets.h"
 #include "ssl/crtd_message.h"
 #if HAVE_CSTDLIB
 #include <cstdlib>
@@ -175,3 +176,6 @@ void Ssl::CrtdMessage::composeBody(CrtdMessage::BodyParams const & map, std::str
 
 const std::string Ssl::CrtdMessage::code_new_certificate("new_certificate");
 const std::string Ssl::CrtdMessage::param_host("host");
+const std::string Ssl::CrtdMessage::param_SetValidAfter(Ssl::CertAdaptAlgorithmStr[algSetValidAfter]);
+const std::string Ssl::CrtdMessage::param_SetValidBefore(Ssl::CertAdaptAlgorithmStr[algSetValidBefore]);
+const std::string Ssl::CrtdMessage::param_SetCommonName(Ssl::CertAdaptAlgorithmStr[algSetCommonName]);
index 6fade2a26ce9f99cf1dd0494a5c3c2f748e1c818..5891c3f207c829d481bee07541e120e6d6b5babd 100644 (file)
@@ -65,6 +65,12 @@ public:
     static const std::string code_new_certificate;
     /// Parameter name for passing hostname
     static const std::string param_host;
+    /// Parameter name for passing SetValidAfter cert adaptation variable
+    static const std::string param_SetValidAfter;
+    /// Parameter name for passing SetValidBefore cert adaptation variable
+    static const std::string param_SetValidBefore;
+    /// Parameter name for passing SetCommonName cert adaptation variable
+    static const std::string param_SetCommonName;
 private:
     enum ParseState {
         BEFORE_CODE,
index 4c08d1ce2831a38339bd77e8c9b6954d91f6349e..bed17c327be09ddc6114b2e169bbfb0a53c16b8f 100644 (file)
@@ -256,7 +256,31 @@ bool Ssl::generateSslCertificateAndPrivateKey(char const *host, Ssl::X509_Pointe
     return true;
 }
 
-static bool mimicCertificate(Ssl::X509_Pointer & cert, Ssl::X509_Pointer const & caCert, Ssl::X509_Pointer const &certToMimic)
+// Replace certs common name with the given
+static bool replaceCommonName(Ssl::X509_Pointer & cert, const char *cn)
+{
+    X509_NAME *name = X509_get_subject_name(cert.get());
+    if (!name)
+        return false;
+    // Remove the CN part:
+    int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
+    X509_NAME_ENTRY *tmp = X509_NAME_get_entry(name, loc);
+    X509_NAME_delete_entry(name, loc);
+    X509_NAME_ENTRY_free(tmp);
+
+    // Add a new CN
+    return X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
+                                      (unsigned char *)cn, -1, -1, 0);
+}
+
+const char *Ssl::CertAdaptAlgorithmStr[] = {
+    "setValidAfter",
+    "setValidBefore",
+    "setCommonName",
+    NULL
+};
+
+static bool mimicCertificate(Ssl::X509_Pointer & cert, Ssl::X509_Pointer const & caCert, Ssl::X509_Pointer const &certToMimic,  Ssl::CrtdMessage::BodyParams const &exceptions)
 { 
     // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
     // returns a pointer to the existing subject name. Nothing to clean here.
@@ -266,27 +290,46 @@ static bool mimicCertificate(Ssl::X509_Pointer & cert, Ssl::X509_Pointer const &
     // X509_set_subject_name will call X509_dup for name 
     X509_set_subject_name(cert.get(), name);
 
+    Ssl::CrtdMessage::BodyParams::const_iterator it;
+    it = exceptions.find(sslCertAdaptAlgoritm(Ssl::algSetCommonName));
+    if (it != exceptions.end()) {
+        // In this case the CN of the certificate given by the exceptions 
+        // and should be replaced
+        const char *cn = it->second.c_str();
+        if (cn && !replaceCommonName(cert, cn))
+            return false;
+    }
 
     // We should get caCert notBefore and notAfter fields and do not allow 
     // notBefore/notAfter values from certToMimic before/after notBefore/notAfter
     // fields from caCert.
     // Currently there is not any way in openssl tollkit to compare two ASN1_TIME 
     // objects.
-    ASN1_TIME *aTime;
-    if ((aTime = X509_get_notBefore(certToMimic.get())) || (aTime = X509_get_notBefore(caCert.get())) ) {
+    ASN1_TIME *aTime = NULL;
+    it = exceptions.find(sslCertAdaptAlgoritm(Ssl::algSetValidBefore));
+    if (it == exceptions.end() || strcasecmp(it->second.c_str(), "on") != 0)
+        aTime = X509_get_notBefore(certToMimic.get());
+    if (!aTime)
+        aTime = X509_get_notBefore(caCert.get());
+
+    if (aTime) {
         if (!X509_set_notBefore(cert.get(), aTime))
             return false;
     }
     else if (!X509_gmtime_adj(X509_get_notBefore(cert.get()), (-2)*24*60*60))
         return false;
 
-    if ((aTime = X509_get_notAfter(certToMimic.get())) || (aTime = X509_get_notAfter(caCert.get())) ) {
+    aTime = NULL;
+     it = exceptions.find(sslCertAdaptAlgoritm(Ssl::algSetValidAfter));
+    if (it == exceptions.end() || strcasecmp(it->second.c_str(), "on") != 0)
+        aTime = X509_get_notAfter(certToMimic.get());
+    if (!aTime)
+        aTime = X509_get_notAfter(caCert.get());
+    if (aTime) {
         if (!X509_set_notAfter(cert.get(), aTime))
             return NULL;
     } else if (!X509_gmtime_adj(X509_get_notAfter(cert.get()), 60*60*24*356*3))
         return NULL;
-
-    
     unsigned char *alStr;
     int alLen;
     alStr = X509_alias_get0(certToMimic.get(), &alLen);
@@ -303,7 +346,7 @@ static bool mimicCertificate(Ssl::X509_Pointer & cert, Ssl::X509_Pointer const &
     return true;
 }
 
-bool Ssl::generateSslCertificate(Ssl::X509_Pointer const &certToMimic, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey, Ssl::X509_Pointer & certToStore, Ssl::EVP_PKEY_Pointer & pkey, BIGNUM const * serial)
+bool Ssl::generateSslCertificate(Ssl::X509_Pointer const &certToMimic, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey, Ssl::X509_Pointer & certToStore, Ssl::EVP_PKEY_Pointer & pkey, BIGNUM const * serial, Ssl::CrtdMessage::BodyParams const &mimicExceptions)
 {
     if (!certToMimic.get())
         return false;
@@ -323,7 +366,7 @@ bool Ssl::generateSslCertificate(Ssl::X509_Pointer const &certToMimic, Ssl::X509
         return false;
 
     // inherit properties from certToMimic
-    if (!mimicCertificate(cert, signedX509, certToMimic))
+    if (!mimicCertificate(cert, signedX509, certToMimic, mimicExceptions))
         return false;
 
     // Set issuer name, from CA or our subject name for self signed cert
index 97f60a129ac4cac8ff663f5876fef064a6128d7b..e8cf163fe7353e72a8babd59c65bd55251bab928 100644 (file)
@@ -6,6 +6,7 @@
 #define SQUID_SSL_GADGETS_H
 
 #include "base/TidyPointer.h"
+#include "ssl/crtd_message.h"
 
 #if HAVE_OPENSSL_SSL_H
 #include <openssl/ssl.h>
@@ -131,6 +132,30 @@ X509 * signRequest(X509_REQ_Pointer const & request, X509_Pointer const & x509,
  */
 bool generateSslCertificateAndPrivateKey(char const *host, X509_Pointer const & signedX509, EVP_PKEY_Pointer const & signedPkey, X509_Pointer & cert, EVP_PKEY_Pointer & pkey, BIGNUM const* serial);
 
+/**
+ \ingroup SslCrtdSslAPI
+ * Supported certificate adaptation algorithms
+ */
+enum CertAdaptAlgorithm {algSetValidAfter = 0, algSetValidBefore, algSetCommonName, algEnd};
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Short names for certificate adaptation algorithms
+ */
+extern const char *CertAdaptAlgorithmStr[];
+
+/**
+ \ingroup SslCrtdSslAPI
+ * Return the short name of the adaptation algorithm "alg"
+ */
+inline const char *sslCertAdaptAlgoritm(int alg)
+{
+    if (alg >=0 && alg < Ssl::algEnd)
+        return Ssl::CertAdaptAlgorithmStr[alg];
+
+    return NULL;
+}
+
 /**
  \ingroup SslCrtdSslAPI
  * Decide on the kind of certificate and generate a CA- or self-signed one.
@@ -138,7 +163,7 @@ bool generateSslCertificateAndPrivateKey(char const *host, X509_Pointer const &
  * Return generated certificate and private key in resultX509 and resultPkey
  * variables.
  */
-bool generateSslCertificate(X509_Pointer const &certToMimic, X509_Pointer const & signedX509, EVP_PKEY_Pointer const & signedPkey, X509_Pointer & cert, EVP_PKEY_Pointer & pkey, BIGNUM const * serial);
+bool generateSslCertificate(X509_Pointer const &certToMimic, X509_Pointer const & signedX509, EVP_PKEY_Pointer const & signedPkey, X509_Pointer & cert, EVP_PKEY_Pointer & pkey, BIGNUM const * serial, CrtdMessage::BodyParams const & mimicExceptions);
 
 /**
  \ingroup SslCrtdSslAPI
index 105728440447c5a8262be54039a201ac054288b9..6ba0194448c9cfd335daac8fadf57e78cfe64884 100644 (file)
@@ -243,6 +243,20 @@ static bool proccessNewRequest(Ssl::CrtdMessage const & request_message, std::st
     if (cert_subject.empty())
         cert_subject = "/CN=" + host;
 
+    i = map.find(Ssl::CrtdMessage::param_SetValidAfter);
+    if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
+        cert_subject.append("+SetValidAfter=on");
+    
+    i = map.find(Ssl::CrtdMessage::param_SetValidBefore);
+    if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
+        cert_subject.append("+SetValidBefore=on");
+
+    i = map.find(Ssl::CrtdMessage::param_SetCommonName);
+    if (i != map.end()) {
+        cert_subject.append("+SetCommonName=");
+        cert_subject.append(i->second);
+    }
+
     db.find(cert_subject, cert, pkey);
 
     if (cert.get() && certToMimic.get()) {
@@ -262,13 +276,13 @@ static bool proccessNewRequest(Ssl::CrtdMessage const & request_message, std::st
         Ssl::BIGNUM_Pointer serial(db.getCurrentSerialNumber());
 
         if (certToMimic.get()) {
-            Ssl::generateSslCertificate(certToMimic, certToSign, pkeyToSign, cert, pkey, serial.get());
+            Ssl::generateSslCertificate(certToMimic, certToSign, pkeyToSign, cert, pkey, serial.get(), map);
         }
         else 
             if (!Ssl::generateSslCertificateAndPrivateKey(host.c_str(), certToSign, pkeyToSign, cert, pkey, serial.get()))
                 throw std::runtime_error("Cannot create ssl certificate or private key.");
 
-        if (!db.addCertAndPrivateKey(cert, pkey) && db.IsEnabledDiskStore())
+        if (!db.addCertAndPrivateKey(cert, pkey, cert_subject) && db.IsEnabledDiskStore())
             throw std::runtime_error("Cannot add certificate to db.");
     }
 
index 8cb0d5e5bd60b54e4533a9b9864d64dca81020f0..f50b9fb0bda47d1ac832c6b50dd1f08eb42e09f5 100644 (file)
@@ -246,13 +246,28 @@ ssl_verify_cb(int ok, X509_STORE_CTX * ctx)
     }
 
     if (!ok) {
+        Ssl::Errors *errNoList = static_cast<Ssl::Errors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno));
+        if (!errNoList) {
+            errNoList = new Ssl::Errors;
+            if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_error_sslerrno,  (void *)errNoList)) {
+                debugs(83, 2, "Failed to set ssl error_no in ssl_verify_cb: Certificate " << buffer);
+                delete errNoList;
+                errNoList = NULL;
+            }
+        }
+
+        if (errNoList) // Append the err no to the SSL errors lists.
+            errNoList->push_back(error_no);
+
         if (const char *err_descr = Ssl::GetErrorDescr(error_no))
             debugs(83, 5, err_descr << ": " << buffer);
         else
             debugs(83, DBG_IMPORTANT, "SSL unknown certificate error " << error_no << " in " << buffer);
 
         if (check) {
-            Filled(check)->ssl_error = error_no;
+            ACLFilledChecklist *filledCheck = Filled(check);
+            filledCheck->sslErrorList.clear();
+            filledCheck->sslErrorList.push_back(error_no);
             if (check->fastCheck() == ACCESS_ALLOWED) {
                 debugs(83, 3, "bypassing SSL error " << error_no << " in " << buffer);
                 ok = 1;
@@ -580,6 +595,14 @@ ssl_free_ErrorDetail(void *, void *ptr, CRYPTO_EX_DATA *,
     delete errDetail;
 }
 
+static void
+ssl_free_SslErrNoList(void *, void *ptr, CRYPTO_EX_DATA *,
+                     int, long, void *)
+{
+    Ssl::Errors *errNo = static_cast <Ssl::Errors *>(ptr);
+    delete errNo;
+}
+
 // "free" function for X509 certificates
 static void
 ssl_free_X509(void *, void *ptr, CRYPTO_EX_DATA *,
@@ -629,6 +652,7 @@ ssl_initialize(void)
     ssl_ex_index_cert_error_check = SSL_get_ex_new_index(0, (void *) "cert_error_check", NULL, &ssl_dupAclChecklist, &ssl_freeAclChecklist);
     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_error_sslerrno =  SSL_get_ex_new_index(0, (void *) "ssl_error_sslerrno", NULL, NULL, &ssl_free_SslErrNoList);
 }
 
 /// \ingroup ServerProtocolSSLInternal
@@ -1234,12 +1258,12 @@ SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data)
     return createSSLContext(cert, pkey);
 }
 
-SSL_CTX * Ssl::generateSslContext(char const *host, Ssl::X509_Pointer const & mimicCert, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey)
+SSL_CTX * Ssl::generateSslContext(char const *host, Ssl::X509_Pointer const & mimicCert, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey, Ssl::CrtdMessage::BodyParams const &mimicExceptions)
 {
     Ssl::X509_Pointer cert;
     Ssl::EVP_PKEY_Pointer pkey;
     if (mimicCert .get()) {
-        if (!generateSslCertificate(mimicCert, signedX509, signedPkey, cert, pkey, NULL))
+        if (!generateSslCertificate(mimicCert, signedX509, signedPkey, cert, pkey, NULL, mimicExceptions))
             return NULL;
     }
     else if (!generateSslCertificateAndPrivateKey(host, signedX509, signedPkey, cert, pkey, NULL)) {
index e2b25b15edac80cbe68f4ea34ff4c74a8d3faa7f..4e368485481786bdd0f6f1dbc663ee805d30b664 100644 (file)
@@ -67,6 +67,10 @@ namespace Ssl
 {
 /// Squid defined error code (<0),  an error code returned by SSL X509 api, or SSL_ERROR_NONE
 typedef int ssl_error_t;
+
+/// \ingroup ServerProtocolSSLAPI
+/// SSL error codes in the order they were encountered
+typedef std::vector<ssl_error_t> Errors;
 } //namespace Ssl
 
 /// \ingroup ServerProtocolSSLAPI
@@ -109,7 +113,7 @@ namespace Ssl
   \ingroup ServerProtocolSSLAPI
   * Decide on the kind of certificate and generate a CA- or self-signed one
 */
-SSL_CTX *generateSslContext(char const *host, Ssl::X509_Pointer const & mimicCert, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey);
+    SSL_CTX *generateSslContext(char const *host, Ssl::X509_Pointer const & mimicCert, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey, CrtdMessage::BodyParams const & mimicExceptions);
 
 /**
   \ingroup ServerProtocolSSLAPI
index 84952a2ebcad7f9902d405a0852c961d29e14318..5e7525fc28f116c5433be4f67feb39769f6d96d3 100644 (file)
@@ -629,6 +629,7 @@ struct SquidConfig {
         char *flags;
         acl_access *cert_error;
         SSL_CTX *sslContext;
+        sslproxy_cert_adapt *cert_adapt;
     } ssl_client;
 #endif
 
@@ -1301,6 +1302,15 @@ struct _store_rebuild_data {
     int zero_object_sz;
 };
 
+#if USE_SSL
+struct _sslproxy_cert_adapt {
+    int alg;
+    char *param;
+    ACLList *aclList;
+    sslproxy_cert_adapt *next;
+};
+#endif
+
 class Logfile;
 
 #include "format/Format.h"
index 1acfdb664fa7bf7c5d82ecad5b53de0e7601cb94..ac61115715137a1fa604a010e61efaee99a1b9d6 100644 (file)
@@ -114,6 +114,10 @@ typedef struct _link_list link_list;
 
 typedef struct _customlog customlog;
 
+#if USE_SSL
+typedef struct _sslproxy_cert_adapt sslproxy_cert_adapt;
+#endif
+
 #if SQUID_SNMP
 typedef variable_list *(oid_ParseFn) (variable_list *, snint *);