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);
+static void parse_sslproxy_ssl_bump(acl_access **ssl_bump);
+static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump);
+static void free_sslproxy_ssl_bump(acl_access **ssl_bump);
#endif /* USE_SSL */
static void parse_b_size_t(size_t * var);
}
}
+static void parse_sslproxy_ssl_bump(acl_access **ssl_bump)
+{
+ char *bm;
+ if ((bm = strtok(NULL, w_space)) == NULL) {
+ self_destruct();
+ return;
+ }
+
+ acl_access *A = new acl_access;
+ A->allow = allow_t(ACCESS_ALLOWED);
+
+ if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpClientFirst]) == 0)
+ A->allow.kind = Ssl::bumpClientFirst;
+ else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpServerFirst]) == 0)
+ A->allow.kind = Ssl::bumpServerFirst;
+ else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpNone]) == 0)
+ A->allow.kind = Ssl::bumpNone;
+ else if (strcmp(bm, "allow") == 0 || strcmp(bm, "deny") == 0) {
+ // allow/deny rule sets may rely on an implicit "negate the last one"
+ // rule which we cannot support due to multuple "allow" keywords
+ debugs(3, DBG_CRITICAL, "FATAL: ssl_bump allow/deny rule(s) " <<
+ "must be CAREFULLY converted to specify bump mode(s).");
+ self_destruct();
+ return;
+ } else {
+ debugs(3, DBG_CRITICAL, "FATAL: unknown ssl_bump mode: " << bm);
+ self_destruct();
+ return;
+ }
+
+ aclParseAclList(LegacyParser, &A->aclList);
+
+ acl_access *B, **T;
+ for (B = *ssl_bump, T = ssl_bump; B; T = &B->next, B = B->next);
+ *T = A;
+}
+
+static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump)
+{
+ acl_access *sb;
+ for (sb = ssl_bump; sb != NULL; sb = sb->next) {
+ storeAppendPrintf(entry, "%s ", name);
+ storeAppendPrintf(entry, "%s ", Ssl::bumpMode(sb->allow.kind));
+ if (sb->aclList)
+ dump_acl_list(entry, sb->aclList);
+ storeAppendPrintf(entry, "\n");
+ }
+}
+
+static void free_sslproxy_ssl_bump(acl_access **ssl_bump)
+{
+ free_acl_access(ssl_bump);
+}
+
#endif
wccp2_service
wccp2_service_info
wordlist
+sslproxy_ssl_bump acl
sslproxy_cert_sign acl
sslproxy_cert_adapt acl
accel Accelerator / reverse proxy mode
- ssl-bump Intercept each CONNECT request matching ssl_bump ACL,
+ ssl-bump For each CONNECT request allowed by ssl_bump ACLs,
establish secure connection with the client and with
- the server, decrypt HTTP messages as they pass through
+ the server, decrypt HTTPS messages as they pass through
Squid, and treat them as unencrypted HTTP messages,
becoming the man-in-the-middle.
- The ssl_bump option is required to fully enable
- the SslBump feature.
+ The "ssl_bump" option is required to fully enable
+ bumping of CONNECT requests.
Omitting the mode flag causes default forward proxy mode to be used.
connections using the client IP address.
NP: disables authentication and maybe IPv6 on the port.
- ssl-bump Intercept each SSL request matching ssl_bump ACL,
- establish secure connection with the client and with
- the server, decrypt HTTP messages as they pass through
+ ssl-bump For each intercepted connection allowed by ssl_bump
+ ACLs, establish a secure connection with the client and with
+ the server, decrypt HTTPS messages as they pass through
Squid, and treat them as unencrypted HTTP messages,
becoming the man-in-the-middle.
- The ssl_bump option is required to fully enable
- the SslBump feature.
+ An "ssl_bump server-first" match is required to
+ fully enable bumping of intercepted SSL connections.
Requires tproxy.
NAME: ssl_bump
IFDEF: USE_SSL
-TYPE: acl_access
+TYPE: sslproxy_ssl_bump
LOC: Config.accessList.ssl_bump
DEFAULT: none
DOC_START
- This ACL controls which CONNECT requests to an http_port
- marked with an sslBump flag are actually "bumped". Please
- see the sslBump flag of an http_port option for more details
- about decoding proxied SSL connections.
+ This option is consulted when a CONNECT request is received on
+ an http_port (or a new connection is intercepted at an
+ https_port), provided that port was configured with an ssl-bump
+ flag. The subsequent data on the connection is either treated as
+ HTTPS and decrypted OR tunneled at TCP level without decryption,
+ depending on the first bumping "mode" which ACLs match.
+
+ ssl_bump <mode> [!]acl ...
+
+ The following bumping modes are supported:
+
+ client-first
+ Allow bumping of the connection. Establish a secure connection
+ with the client first, then connect to the server. This old mode
+ does not allow Squid to mimic server SSL certificate and does
+ not work with intercepted SSL connections.
- By default, no requests are bumped.
+ server-first
+ Allow bumping of the connection. Establish a secure connection
+ with the server first, then establish a secure connection with
+ the client, using a mimicked server certificate. Works with both
+ CONNECT requests and intercepted SSL connections.
+
+ none
+ Become a TCP tunnel without decoding the connection.
+ Works with both CONNECT requests and intercepted SSL
+ connections. This is the default behavior when no
+ ssl_bump option is given or no ssl_bump ACLs match.
+
+ By default, no connections are bumped.
+
+ The first matching ssl_bump option wins. If no ACLs match, the
+ connection is not bumped. Unlike most allow/deny ACL lists, ssl_bump
+ does not have an implicit "negate the last given option" rule. You
+ must make that rule explicit if you convert old ssl_bump allow/deny
+ rules that rely on such an implicit rule.
- See also: http_port ssl-bump
-
This clause supports both fast and slow acl types.
See http://wiki.squid-cache.org/SquidFaq/SquidAcl for details.
+ See also: http_port ssl-bump, https_port ssl-bump
+
- # Example: Bump all requests except those originating from localhost and
- # those going to webax.com or example.com sites.
+ # Example: Bump all requests except those originating from
+ # localhost and those going to example.com.
- acl localhost src 127.0.0.1/32
- acl broken_sites dstdomain .webax.com
acl broken_sites dstdomain .example.com
- ssl_bump deny localhost
- ssl_bump deny broken_sites
- ssl_bump allow all
+ ssl_bump none localhost
+ ssl_bump none broken_sites
+ ssl_bump server-first all
DOC_END
NAME: sslproxy_flags
* Otherwise, calls switchToHttps to generate a dynamic SSL_CTX.
*/
static void
-httpsEstablish(ConnStateData *connState, SSL_CTX *sslContext)
+httpsEstablish(ConnStateData *connState, SSL_CTX *sslContext, Ssl::BumpMode bumpMode)
{
SSL *ssl = NULL;
assert(connState);
Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
else {
char buf[MAX_IPSTRLEN];
+ assert(bumpMode != Ssl::bumpNone && bumpMode != Ssl::bumpEnd);
HttpRequest *fakeRequest = new HttpRequest;
fakeRequest->SetHost(details->local.NtoA(buf, sizeof(buf)));
fakeRequest->port = details->local.GetPort();
fakeRequest->my_addr = connState->clientConnection->local;
debugs(33, 4, HERE << details << " try to generate a Dynamic SSL CTX");
- connState->switchToHttps(fakeRequest);
+ connState->switchToHttps(fakeRequest, bumpMode);
}
}
if (!connState->isOpen())
return;
- if (answer == ACCESS_ALLOWED) {
+ // Require both a match and a positive mode to work around exceptional
+ // cases where ACL code may return ACCESS_ALLOWED with zero answer.kind.
+ if (answer == ACCESS_ALLOWED && answer.kind != Ssl::bumpNone) {
debugs(33, 2, HERE << " sslBump done data: " << connState->clientConnection);
- httpsEstablish(connState, NULL);
+ httpsEstablish(connState, NULL, (Ssl::BumpMode)answer.kind);
} else {
// fake a CONNECT request to force connState to tunnel
return;
} else {
SSL_CTX *sslContext = s->staticSslContext.get();
- httpsEstablish(connState, sslContext);
+ httpsEstablish(connState, sslContext, Ssl::bumpNone);
}
}
certProperties.commonName = sslCommonName.defined() ? sslCommonName.termedBuf() : sslConnectHostOrIp.termedBuf();
// fake certificate adaptation requires bump-server-first mode
- if (!sslServerBump)
+ if (!sslServerBump) {
+ assert(port->signingCert.get());
+ certProperties.signWithX509.resetAndLock(port->signingCert.get());
+ if (port->signPkey.get())
+ certProperties.signWithPkey.resetAndLock(port->signPkey.get());
+ certProperties.signAlgorithm = Ssl::algSignTrusted;
return;
+ }
// In the case of error while connecting to secure server, use a fake trusted certificate,
// with no mimicked fields and no adaptation algorithms
}
void
-ConnStateData::switchToHttps(HttpRequest *request)
+ConnStateData::switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode)
{
assert(!switchedToHttps_);
flags.readMore = true;
debugs(33, 5, HERE << "converting " << clientConnection << " to SSL");
- const bool alwaysBumpServerFirst = true;
// If sslServerBump is set, then we have decided to deny CONNECT
// and now want to switch to SSL to send the error to the client
// without even peeking at the origin server certificate.
- if (alwaysBumpServerFirst && !sslServerBump) {
+ if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
request->flags.sslPeek = 1;
sslServerBump = new Ssl::ServerBump(request);
/// Proccess response from ssl_crtd.
void sslCrtdHandleReply(const char * reply);
- void switchToHttps(HttpRequest *request);
+ void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
bool switchedToHttps() const { return switchedToHttps_; }
Ssl::ServerBump *serverBump() {return sslServerBump;}
void setServerBump(Ssl::ServerBump *srvBump) {if (!sslServerBump) sslServerBump = srvBump;}
request_satisfaction_mode = false;
#endif
#if USE_SSL
- sslBumpNeed = needUnknown;
+ sslBumpNeed = Ssl::bumpEnd;
#endif
}
acl_checklist->nonBlockingCheck(sslBumpAccessCheckDoneWrapper, this);
return true;
} else {
- http->sslBumpNeeded(false);
+ http->sslBumpNeeded(Ssl::bumpNone);
return false;
}
}
if (!httpStateIsValid())
return;
- http->sslBumpNeeded(answer == ACCESS_ALLOWED);
+ if (answer == ACCESS_ALLOWED)
+ http->sslBumpNeeded(static_cast<Ssl::BumpMode>(answer.kind));
+ else
+ http->sslBumpNeeded(Ssl::bumpNone);
+
http->doCallouts();
}
#endif
#if USE_SSL
-bool
+Ssl::BumpMode
ClientHttpRequest::sslBumpNeeded() const
{
- assert(sslBumpNeed != needUnknown);
- return (sslBumpNeed == needConfirmed);
+ assert(sslBumpNeed != Ssl::bumpEnd);
+ return sslBumpNeed;
}
void
-ClientHttpRequest::sslBumpNeeded(bool isNeeded)
+ClientHttpRequest::sslBumpNeeded(Ssl::BumpMode mode)
{
- debugs(83, 3, HERE << "sslBump required: "<< (isNeeded ? "Yes" : "No"));
- sslBumpNeed = (isNeeded ? needConfirmed : needNot);
+ debugs(83, 3, HERE << "sslBump required: "<< Ssl::bumpMode(mode));
+ sslBumpNeed = mode;
}
// called when comm_write has completed
getConn()->auth_user_request = request->auth_user_request;
#endif
- getConn()->switchToHttps(request);
+ getConn()->switchToHttps(request, sslBumpNeeded());
}
void
ConnStateData * conn_;
#if USE_SSL
- /// whether the request needs to be bumped
- enum { needUnknown, needConfirmed, needNot } sslBumpNeed;
+ /// whether (and how) the request needs to be bumped
+ Ssl::BumpMode sslBumpNeed;
public:
/// return true if the request needs to be bumped
- bool sslBumpNeeded() const;
+ Ssl::BumpMode sslBumpNeeded() const;
/// set the sslBumpNeeded state
- void sslBumpNeeded(bool isNeeded);
+ void sslBumpNeeded(Ssl::BumpMode mode);
void sslBumpStart();
void sslBumpEstablish(comm_err_t errflag);
#endif
#include "ssl/support.h"
#include "ssl/gadgets.h"
+const char *Ssl::BumpModeStr[] = {
+ "none",
+ "client-first",
+ "server-first",
+ NULL
+};
+
/**
\defgroup ServerProtocolSSLInternal Server-Side SSL Internals
\ingroup ServerProtocolSSLAPI
namespace Ssl
{
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Supported ssl-bump modes
+ */
+enum BumpMode {bumpNone = 0, bumpClientFirst, bumpServerFirst, bumpEnd};
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Short names for ssl-bump modes
+ */
+extern const char *BumpModeStr[];
+
+/**
+ \ingroup ServerProtocolSSLAPI
+ * Return the short name of the ssl-bump mode "bm"
+ */
+inline const char *bumpMode(int bm)
+{
+ return (0 <= bm && bm < Ssl::bumpEnd) ? Ssl::BumpModeStr[bm] : NULL;
+}
+
/**
\ingroup ServerProtocolSSLAPI
* Generate a certificate to be used as untrusted signing certificate, based on a trusted CA