Subject: relayd SSL interception From: Reyk Floeter Date: 2013-01-29 Tags: blog OpenBSD relayd I recently sent an email to OpenBSD's misc@ list where I explained some details of the experimental support for SSL Interception ("SSL-MITM") in relayd, my versatile networking and load balancing software for OpenBSD. The content of the email is quite interesting, so I modified it a bit to post it as an article. As you probably know, relayd already supports running as a transparent non-caching HTTP proxy that can be used for URL filtering and policy enforcements. It also supports running as an SSL server and can be used to terminate SSL connections and to forward them as plain TCP. The marketing term for this is "SSL acceleration" and is typically used to provide HTTPS on the load balancer for HTTP-only webservers in the pool. Some time ago, I also added support for running relayd as an SSL client to terminate plain TCP connections and transparently tunnel them through SSL. I don't know if there is an actual marketing term for it, but let's call it some kind of SSL VPN ... whatever SSL VPN means. ---- When combining both modes, SSL server and client, you end up with a man-in-the-middle that can filter between two SSL connections. This is actually already possible with the current version of relayd. However, for an effective SSL-MITM, or "SSL Interception", you need to do some trickery with the certificates. An SSL client, especially web browsers for HTTPS, should verify the certificate and check if it is a) valid, b) signed by a trusted Certificate Authority and c) it is matching some additional security policies, most importantly having a matching domain name in the certificate. Some existing solutions and firewall vendors support SSL interception (e.g. for URL filtering on secured connections) by generating client certificates on-the-fly with a local CA that is accepted by the clients. This way, secured HTTPS connections from web browsers behind a corporate gateway can be URL-filtered and "intercepted". The remaining problem is that the web browsers normally don't recognize the local CA, but having a corporate infrastructure allows you to deploy the custom CA certificate on your internal clients. Another solution is to obtain an official CA with private key or to get an intermediate CA - a local CA signed by an official CA. Getting an an official CA or intermediate CA for SSL Interception is normally only possible for governmental authorities (e.g. TURKTRUST in Turkey), or people who have access to a possibly compromised CA (e.g. DigiNotar in the Netherlands). Regarding the large number of official CAs that are accepted by modern browsers, I suppose that this is already a fairly common practice that keeps on questioning the CA model itself. Inspired by this situation, I implemented SSL Interception in relayd. You can find the related patch attached to the original mail of this post or in my experimental [relayd repository on GitHub](https://github.com/reyk/relayd/tree/sslmitm "relayd repository on GitHub"). When relayd is configured for SSL Interception, it will listen for incoming connections that have been diverted to the local socket by PF. Before accepting and negotiating the incoming SSL connection as a server, it will look up the the original destination address on the diverted socket, and pre-connect to the target server as an SSL client to obtain the remote SSL certificate. It will update or "patch" the obtained SSL certificate by replacing the included public key with its local server key because it doesn't have the private key of the remote server certificate. It also updates the X.509 issuer name to the local CA subject name and signs the certificate with its local CA key. This way it keeps all the other X.509 attributes that are already present in the server certificate, including the "green bar" extended validation attributes. Now it finally accepts the SSL connection from the diverted client using the updated certificate and continues to handle the connection and to connect to the remote server. You just need to generate a CA and configure relayd and PF to run it. Please also make sure that you apply it to the very latest code from -current to include a fix for Chunked Transfer Encoding that unbreaks Chrome. I also warn you that you should make sure that you legally created or obtained the CA certificate and that your privacy policy actually allows to intercept encrypted HTTPS/SSL connections. There are some known limitations: Safari on OSX uses the system key chain that does not seem to allow importing custom CA Root certificates and keeps on warning about the intercepted SSL connections. Additionally, Google is able to monitor the certificates when accessing its servers with Chrome allowing them to detect interception attempts. This shouldn't be a problem if you're intercepting users behind a corporate gateway with a local CA - but it allowed Google to detect the misused CA certificate that was issued by TURKTRUST to a related governmental authority in Turkey. There is probably a way to bypass the restriction on OSX and my upcoming filter rewrite might allow to selectively disable SSL interception for selected domains; you can already filter Chrome or well-known Google-related domains. **Configuration Example:** 1. Your CA key and certificate: # openssl req -x509 -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/ca.key -out /etc/ssl/ca.crt 2. You will also need an SSL server key and cert for 127.0.0.1, see "listen on" in the RELAYS section of relayd.conf(5) and ssl(8) for more details). 3. /etc/pf.conf: # Divert incoming HTTPS traffic to relayd pass in on vlan1 inet proto tcp to port 443 divert-to localhost port 8443 4. /etc/relayd.conf: http protocol httpfilter { return error label "Get back to work!" request url filter "facebook.com/" # New configuration directives for SSL Interception ssl ca key "/etc/ssl/private/ca.key" password "humppa" ssl ca cert "/etc/ssl/ca.crt" } relay sslmitm { listen on 127.0.0.1 port 8443 ssl protocol httpfilter forward with ssl to destination }