reykfloeter – blog

relayd SSL interception

Posted by
Reyk Floeter

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. 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, 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 ""
        # 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 port 8443 ssl
        protocol httpfilter
        forward with ssl to destination
Permalink, Source, Tags: blogOpenBSDrelayd