HTTPS tunnels

HTTPS tunnels

cryptostorm now has a feature that allows you to make your VPN traffic look like HTTPS traffic. This is mainly to help people who are behind restrictive firewalls that only allow HTTPS traffic, but it can also be useful against certain correlation attacks.

Normally, if a network administrator wanted to block everything but HTTPS, they would simply block everything but TCP port 443 (HTTPS). If you're behind a firewall that's only doing that, you can just tell the VPN to connect to TCP port 443 to get past it. But because DPI-capable firewalls are getting cheaper, you might be behind a firewall that's doing packet inspection to see if that traffic on port 443 is really HTTPS. If that's the case, then this new feature will allow you to bypass that firewall.

Thanks to our port striping feature, this new HTTPS feature can also be used on any port from 1-29999 (excluding 5061 and 5062). So if the network you're on is doing DPI to detect HTTPS, but it's only allowing HTTPS on port 4443, you can still use this to bypass that firewall. Also, this feature uses the same hosts/IPs as the VPN, so those of you doing your own custom IP-based kill switch won't have to change anything.

(yes, the above was copied from the SSH tunneling article, but it also applies to this HTTPS tunneling)

Another feature included in this HTTPS tunneling setup is that you can specify any SNI host/domain.
That might help bypass certain DPI rules. For example, if the firewall allows HTTPS, but only to baidu.com, you might be able to bypass that by setting your SNI host to baidu.com, even though you're actually connecting to our HTTPS server (and tunneling your OpenVPN traffic through that HTTPS tunnel, where you can now access any domain without any restrictions).

Also, the TLS certificates used for this HTTPS tunnel have a CA and server certificate whose CN (Common Name) is a single period. Even though that's obviously not a valid domain, we thought it might be a good idea to use it anyway because DPI implementations that don't get fooled by SNI will be able to see the server's CN during this HTTPS tunnel's TLS handshake, and there's a possibility that a single period might bypass that DPI.

Windows instructions

Widget users

As of v3.46, our widget has built-in SSH and HTTPS tunneling support. Click the "Options" button then the "Advanced" tab, it's at the bottom.

OpenVPN GUI users

First off, download the win64 stunnel installer from https://www.stunnel.org/downloads.html
Install it, and during the installation when a black DOS window pops up asking you for the country code etc. just keep pressing enter until that goes away. That's generating a TLS certificate, but since we're not going to be using a client-side certificate the defaults are fine.

Next, start stunnel as Administrator, then double click on it's icon in the system tray to bring up the main stunnel window:

Click the "Configuration" menu and go to "Edit Configuration". In your text editor, you'll see a bunch of lines that are included in the default stunnel config. Delete all of them and replace them with:

[openvpn]
client = yes
accept = 127.0.0.1:31337
connect = paris.cstorm.is:443
sni = .

If you'd like to change the SNI as mentioned in the 4th paragraph of this page, change the "sni = ." part to 
"sni = whateverdomain.com"

To connect to something besides our Paris node, change the "paris.cstorm.is" to any of the nodes listed here.

When you're done with that, reload the config by going to "Configuration" again then "Reload Configuration".

Next step is to grab one of our OpenVPN ECC or RSA TCP configs from here.
(The Ed25519 and Ed448 configs won't work with this HTTPS tunneling)

Edit that OpenVPN config, removing all the lines that begin with "remote", and replacing them with this line:

remote 127.0.0.1 31337 tcp

If you changed the port in the above stunnel config to something other 31337, make the same change here.

And finally, connect with OpenVPN GUI using the config you just edited. If you don't know how to do that, read the instructions at https://cryptostorm.is/windows#ovpngui

Once you're connected, all of your traffic will now appear to be regular HTTPS to anyone listening in.

Linux instructions

This HTTPS tunnel uses stunnel, so download and install that if you don't already have it.
For those of you on Debian-based distros, you can do that with the command:
sudo apt-get install stunnel4
For those of you on Redhat-based distros, you can do that with the command:
sudo yum install stunnel

Once you have stunnel installed, create the file /etc/stunnel.conf with the contents:

[openvpn]
client = yes
accept = 127.0.0.1:31337
connect = paris.cstorm.is:443
sni = .

The /etc/ directory is owned by root, so you'll need to be root in order to create the file in that location.

If you'd like to change the SNI as mentioned in the 4th paragraph of this page, change the "sni = ." part to
"sni = whateverdomain.com"

To connect to something besides our Paris node, change the "paris.cstorm.is" to any of the nodes listed here.

Next step is to grab one of our OpenVPN ECC or RSA TCP configs from here.
(The Ed25519 and Ed448 configs won't work with this HTTPS tunneling)

Edit that OpenVPN config, removing all the lines that begin with "remote", and replacing them with these two lines:

remote 127.0.0.1 31337 tcp
route paris.cstorm.is 255.255.255.255 net_gateway

In this example, I'll save that to /etc/openvpn/ssl.conf

If you changed the node in the above stunnel.conf to something other than "paris.cstorm.is", then make the same change to this OpenVPN config. Same goes for the 31337 port.

As with our SSH tunneling setup, for reasons we're not quite sure of, that route line is only needed on Linux.
In Windows it appears to work fine without it.

Anyways, start up stunnel with the command:
stunnel /etc/stunnel.conf

You shouldn't need to use sudo since stunnel doesn't need to run as root, unless you changed the above 31337 port to something < 1024, because you need root privileges to listen on any port below 1024.

With stunnel now running in the background, start OpenVPN with the command:
sudo openvpn /etc/openvpn/ssl.conf

Once that's connected, you're all done. All of your traffic will now appear to be HTTPS traffic.

Technical details

Those of you experienced with stunnel will probably notice that we're not doing anything to verify the server's TLS certificate, or the CA certificate. The reason for that is because leaving it out makes the client-side stunnel config smaller and the whole process a little easier, and it's not actually needed since OpenVPN does verify the remote TLS certificates. If someone were to MiTM the HTTPS tunnel, they wouldn't be able to do the same thing to the VPN tunnel, so no harm done.

As with SSH tunneling, the initial connection is actually made to haproxy, which acts as a frontend balancer for this whole thing (and it's also used to balance our TCP OpenVPN instances). haproxy detects whether the session is RSA OpenVPN, ECC OpenVPN, or SSH, or HTTPS, and forwards it to it's respective backend. For HTTPS, haproxy sends the session to the server-side stunnel, which then forwards it back to haproxy (minus the HTTPS). Doing it that way allows clients to use either the ECC or RSA OpenVPN configs with this.

As with all of our other services, the server-side stunnel isn't logging anything, and is running under a restricted account. Here's our server-side stunnel.conf:

setgid = stunnel
setuid = stunnel
cert = /etc/stunnel/chain.crt
key = /etc/stunnel/server.key
pid = /var/run/stunnel/stunnel.pid
output = /dev/null
syslog = no

[openvpn]
failover=rr
accept=127.0.0.1:44344 connect=27.255.77.57:443 connect=27.255.77.58:443

That's for the South Korea node. All the other nodes have the same config, except that the connect= lines include each VPN IP for that node. The failover=rr part implements stunnel's round-robin algorithm so that whenever you connect to this HTTPS tunnel, you're given a different exit IP each time.

What's next?

We're still testing out other protocols, but unfortunately most obfuscation/tunneling software for other protocols is "Proof of Concept" code only, which usually means insecure/unstable. Once we're done testing and adding other protocols, we'll add obfs4 support to all the servers, which should help those out behind the GFW.

Our widget now includes built-in SSH and HTTPS tunneling support, so changing the above widget instructions to reflect that.

Posted on