Squid (v3.5+) proxy with SSL Bump

The squid proxy is an amazingly powerful web proxy that can be used from anything to captive portals, redirection, user authentication, logging, and so on; but Squid has always had a limitation where SSL was concerned. Prior to version 3.2, Squid’s method of handling SSL was to simply pass through SSL encrypted traffic as it was un-able to do anything with it with out invalidating the SSL chain of trust, alerting the user for every SSL connection. However post 3.5 versions allow a lot more control, but be aware this method still invalidates the SSL chain of trust.

This how-to will not focus on too much other than the requirements for getting squid running with SSL Bump. You will need to read the documentation regarding compiling and configuring the squid proxy. It is far easier to advertise the proxy via auto-discovery and have the browser connect directly to the proxy server, but some users may try to circumvent this and attempt a direct connection. In this case we will need to force these users to use the proxy by intercepting traffic.

The premise of SSL Bumping is a man-in-the-middle attack of sorts, but because this is being done in an environment where your users are aware that all their traffic is subject to inspection, this is not really an attack as much as it is policy.

There are a few new methods squid uses to perform SSL Bumping, but I will sum the most invasive method up like this: Squid receives a https request and then goes about establishing a secure connection for the user. Once the remote connection is established, squid re-encrypts all the traffic; but with a local private key and creates a certificate on the fly using a trusted local certificate authority you have installed on each user machine.

So, on to the task at hand: The first thing we need to do is make sure that the version of squid you are using is greater than 3.5. While 3.2, 3.3, and 3.4 versions are capable of this method, the SSL Bump directive has changed a significantly as of version 3.5. Also squid needs to be built with the ‘--with-openssl’ flag.

I use the following line to configure squid for CentOS:

./configure \
        --prefix=/usr \
        --exec-prefix=/usr \
        --includedir=/usr/include \
        --datadir=/usr/share \
        --libdir=/usr/lib64 \
        --libexecdir=/usr/lib64/squid \
        --localstatedir=/var \
        --sysconfdir=/etc/squid \
        --sharedstatedir=/var/lib \
        --with-logdir=/var/log/squid \
        --with-pidfile=/var/run/squid.pid \
        --with-default-user=squid \
        --enable-silent-rules \
        --enable-dependency-tracking \
        --with-openssl \
        --enable-icmp \
        --enable-delay-pools \
        --enable-useragent-log \
        --enable-esi \
        --enable-follow-x-forwarded-for \
        --enable-ipf-transparent \
        --enable-auth

The next thing we need to do is generate a local ssl certificate. I’m going to be going with some very basic commands here and not worrying about encrypting our keys, with that said lets generate our private key.

# Generate Private Key
openssl genrsa -out example.com.private 2048

Now we have to create a Certificate Signing Request.

# Create Certificate Signing Request
openssl req -new -key example.com.private -out example.com.csr
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:Illinois
Locality Name (eg, city) [Default City]:Chicago
Organization Name (eg, company) [Default Company Ltd]:Example Company LTD.
Organizational Unit Name (eg, section) []:Information Technology
Common Name (eg, your name or your server's hostname) []:Example Company LTD.
Email Address []: 
Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: 
An optional company name []:Example Company LTD.

Notice that I did not use a domain for the ‘Common Name’ attribute. This is because squid will be using this certificate to dynamically create a chained certificate with the domain of the proxy user’s request. Now we need to sign our Certificate Signing Request.

# Sign Certificate
openssl x509 -req -days 3652 -in example.com.csr -signkey example.com.private -out example.com.cert

Once that is finished copy the private key and the certificate to some location where squid can access it, make sure to keep your private key some place secure. The certificate will need to be accessible to the squid proxy user, and installed as a Trusted Root Certificate Authority on each users machine. This is the real reason I did not use * or a domain as the Common Name, because it would be labeled as such when loaded as a certificate authority.

That should take care of most of the external squid stuff, lets move into the squid configuration. This is not a complete squid.conf file, only lines directly related to the task at hand. The configuration below is in a particular order though.

# Proxy Aware (non-intercepted traffic)
http_port 192.168.0.1:3128 ssl-bump cert=/etc/squid/example.com.cert key=/etc/squid/example.com.private generate-host-certificates=on version=1 options=NO_SSLv2,NO_SSLv3,SINGLE_DH_USE
# Intercepted Traffic
https_port 192.168.0.1:3130 cert=/etc/squid/example.com.cert key=/etc/squid/example.com.private ssl-bump intercept generate-host-certificates=on version=1 options=NO_SSLv2,NO_SSLv3,SINGLE_DH_USE

# SSL Bump Config
ssl_bump stare all
ssl_bump bump all

Now lets delve into some of this:
http_port: This tells squid to listen on 192.168.0.1 port 3128 in ssl_bump mode. I refuse SSLv2 & SSLv3 connections and disable multiple DH here as well. Refer to the linked documentation for further explanation. Use http_port when the browser knows it is talking to a proxy.

https_port: This tells squid to listen on 192.168.0.1 port 3130 in ssl_bump intercept mode. Again I refuse SSLv2 & SSLv3 connections and disable multiple DH. Use https_port when the browser does NOT know it is talking to a proxy (i.e. Transparent/Interception).

ssl_bump stare: This is required first for proper certificate generation. More on this below.

ssl_bump bump: Perform the actual bump method.

Ok, stare vs. bump: As of squid version 3.5 there are MULTIPLE bump methods and multiple bump phases:
'splice' is the old pass-through method, no certificate mangling.
'bump' automatically generates certificates and re-encrypts the traffic. Which is what we want to do.
'peek' allows for some understanding of the connection but also allow us to splice (pass-through) traffic with out messing with it afterward.
'stare' allows for some understanding of the connection but also allows us to bump it later.

In order to successfully intercept the traffic and generate the certificate we have to know the domain we want to generate the certificate for. Easily done if the browser knows it's using a proxy. But if we simply bump the traffic with out getting this information the certificate will be generated using the IP address of the remote server and that won't work. So we have to 'stare' at the connection first. That allows us to get the domain and generate a proper certificate. This, by the way, is the only documentation I found on the issue..

With that finished you should be ready to go. Please be aware this is essentially breaking the SSL trust mechanism. You are taking control of the decision making process away from the end user (which may be a good thing for some people) and trusting the proxy server implicitly. The power of this configuration allows you to now take full advantage of squids powerful functions, like content filtering, against SSL protected sites.

Notes:
I encountered a compile issue on CentOS. This was resolved by modifying the definition for USE_SOLARIS_IPFILTER__MINOR_T_HACK around line 38725:

#define USE_SOLARIS_IPFILTER_MINOR_T_HACK 0