Squid Proxy with SSL Bump

The squid proxy is an amazingly powerful web proxy that can be used from anything to captive portals, redirection, user authentification, 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.2 versions allow a little bit more control, but be aware this method still invalidates the SSL chain of trust.

Squid’s new method involves creating a local certificate authority and generating chained certificates on the fly. If that sounds confusing keep reading, I promise the how-to will make more sense than that last sentence.

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 and configuring clients to use the web proxy (I prefer auto-discovery) Be aware that you can not use this method with squid in transparent mode yet. Clients will need to be configured to use squid as a true proxy. See the edit note at the end about transparent SSL Bump interception.

The first thing we need to do is make sure that the version of squid you are using is greater than 3.3. While 3.2 is capable of this method, the SSL Bump directive has changed as of version 3.3. Also squid needs to be built with the ‘enable-ssl’ and ‘enable-ssl-crtd’ flags. These flags are not enabled by default, so if you want to take advantage of this feature you will probably need to re-compile.

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. 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.

As squid generates certificates it stores a copy of each in a cache directory so that it only has to do it once every so often. So we need to set up it’s certificate cache. We will be using the ssl_crtd command created when squid was compiled, I don’t know where it is normally installed but mine was installed in to the location in ‘/usr/lib64/squid/’. I will be storing my certificate cache in ‘/var/lib/ssl_db’ so adjust the command as necessary.

# Generate certificate cache
/usr/lib64/squid/ssl_crtd -c -s /var/lib/ssl_db
# Change ownership of the certificate cache
chown squid: /var/lib/ssl_db

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.

# Squid listen Port
ssl-bump generate-host-certificates=on dynamic_cert_mem_cache_size=4MB key=/etc/squid/example.com.private cert=/etc/squid/example.com.cert
# SSL Bump Config
always_direct allow all
ssl_bump server-first all
sslproxy_cert_error deny all
sslproxy_flags DONT_VERIFY_PEER
sslcrtd_program /usr/lib64/squid/ssl_crtd -s /var/lib/ssl_db -M 4MB sslcrtd_children 8 startup=1 idle=1

Now lets delve into some of this:
Line #2 http_port: This tells squid to listen on port 3128 in ssl_bump mode, you can, of course, change the IP & port. Telling it to generate host certificates dynamically, where the certificate cache is, and the location of the certificate and the private key.

Line #5 always_direct: This tells squid to communicate with the remote server.

Line #6 ssl_bump: This tells squid to run ssl_bump in ‘server-first’ mode. This mode establishes a SSL connection between the squid proxy and the remote site, say Google for example, first. Then generates a certificate, or pulls one from its cache, and establishes a connection between proxy server and user.

Line #7 sslproxy_cert_error: This is important. When squid is configured in this manner it takes the ability for the user to accept/deny invalid or questionable certificates. This directive tells the server how to handle these circumstances. I have mine configured to reject communication with suspect certificates.

Line #8 sslproxy_flags: I’ll be honest, I have no idea, let me know in the comments if you know exactly what this does. I do know that it won’t work with out it. A friendly e-mail from Geoffrey McRae notes that “DONT_VERIFY_PEER [tells] squid to not verify the self signed certificate [we generated above]. This would not be recommended in a corporate office environment as you would want to have a proper CA set-up that the proxy can verify the certificate chain against.” Thank you for the explanation!

Line #9 sslcrtd_program: This tells squid where the program is that actually does the certificate auto-generation.

Line #10 sslcrtd_children: This tells squid how many total number of the certificate generator program can run at the same time to serve requests. I have it set to 1 – 8, with 1 needed at start up. Squid will manage rest.

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.

EDIT: Added explanation for DONT_VERIFY_PEER from Geoffrey McRae. He also notes that you can do SSL Bump along with a transparent configuration:

https_port XXXX intercept ssl-bump generate-host-certificates=on dynamic_cert_mem_cache_size=4MB key=/etc/squid/example.com.private cert=/etc/squid/example.com.cert