I have been doing some work with VPNs lately, having set up a PPTP(Point to Point Tunneling Protocol) VPN for some Android network analysis that I have been doing lately. It is easy to set up on a server and a mobile device, but PPTP generally isn’t secure unless you are using (P)EAP. I wanted to try out something that overlaps with something that I’m pretty knowledgeable about, TLS/SSL, with something I have never had to actually set up, an SSL VPN. Most people who use a VPN to connect into work use an SSL VPN. Probably either from someone like Cisco or Juniper. They are pretty easy to set up on the router side of things, and relatively easy for client device to get set up. Other advantages are that they can be run over port 443, so they won’t be blocked by most firewalls, and that they use the verification properties inherent to TLS/SSL rather than some sort of challenge-response handshake. Using TLS/SSL allows them to also be flexible about key sizes and cipher suites used and upgrade them as the future requires.
I went with OpenVPN for setting up an SSL VPN because it is free, and I could install it on hardware I have. I started with a plain Ubuntu 14.10 server box. First we need to install a few prerequisites.
$sudo apt-get install bridge-utils openvpn libssl-dev openssl
OpenVPN makes use of a bridge adapter(br0) that sits between the internal clients, once connected, and the external interface(eth0). We need to modify our network config to add this bridge adapter in.
$sudo nano /etc/network/interfaces
This file should look something like the below file, substituting out the IP information for your machine. I just moved the info that was in eth0 to br0.
# This file describes the network interfaces available on your # system and how to activate them. For more information, see # interfaces(5). # The loopback network interface auto lo iface lo inet loopback auto br0 iface br0 inet static address 22.214.171.124 netmask 255.255.192.0 gateway 126.96.36.199 network 188.8.131.52 broadcast 184.108.40.206 dns-nameservers 220.127.116.11 18.104.22.168 bridge_ports eth0 bridge_fd 9 bridge_hello 2 bridge_maxage 12 bridge_stp off # The primary network interface auto eth0 #iface eth0 inet static # address 22.214.171.124 # netmask 255.255.192.0 # gateway 126.96.36.199 # dns-nameservers 188.8.131.52 184.108.40.206 iface eth0 inet manual up ip link set $IFACE up promisc on down ip link set $IFACE down promisc off
Next we need to turn on IP forwarding. We do this in sysctl to make sure that the setting survives a reboot.
$sudo nano /etc/sysctl.conf
Uncomment this line
Reboot the server.
$sudo shutdown -r 0
At this point you may want to do some pinging and whatnot to make sure your networking situation is still intact.
OpenVPN uses a tool called “Easy RSA”. Basically this functions as a very barebones PKI(Public Key Infrastructure) that helps you issue certificates for your server and clients. The reason that OpenVPN needs a PKI is to issue the server certificate and if using client certs, to issue those as well. One of the things that surprised me about OpenVPN is that the certificates are self-signed. I looked into whether or not you can use third-party signed certs for the server side of OpenVPN to make client configuration easier. Because of the way OpenVPN works on the client, you have to at least install a config, and in our case client certificates as well so installing a the public key of the server on the client isn’t really extra work. Anyway, back to it, we install Easy RSA.
apt-get install easy-rsa
We tell it where the CA is going to be located.
We need to set up some options for our self-signed certificated
sudo nano /etc/openvpn/easy-rsa/vars
Modify these to suit your situation.
export KEY_COUNTRY="CA" export KEY_PROVINCE="SK" export KEY_CITY="Some Town" export KEY_ORG="JimCo" export KEY_EMAIL="email@example.com"
Now we are going to set up our CA.
Load the options into environmental variables
Make sure we are starting from a clean slate
We generate a Diffie-Hellman parameter for the server end of things so that Perfect Forward Secrecy can be maintained.
This generates the server private key and csr(ca.key and ca.csr).
This creates the self-signed certificate(ca.crt).
./pkitool --server server
At first I thought this step was generating a static key to do something that I had read about but never seen implemented, TLS-PSK, but the fact that we generated a Diffie Hellman perameter a few steps ago made me skeptical of that. But according to the OpenVPN documentation the tls-auth directive, requires you to authenticate with a static key before you even attempt any computationally expensive public key encryption.
cd keys openvpn --genkey --secret ta.key
Now we copy out server’s certificate, and private key, our Diffie Hellman parameter and static key to the OpenVPN configuration directory, /etc/openvpn. I believe this is where our config file looks for them.
sudo cp server.crt server.key ca.crt dh2048.pem ta.key ../../
Next we create a startup script for OpenVPN.
nano /etc/openvpn/up.sh #!/bin/sh BR=$1 DEV=$2 MTU=$3 /sbin/ifconfig $DEV mtu $MTU promisc up /sbin/brctl addif $BR $DEV
And a shutdown script as well.
#!/bin/sh BR=$1 DEV=$2 /sbin/brctl delif $BR $DEV /sbin/ifconfig $DEV down
Make them executable.
sudo chmod +x /etc/openvpn/up.sh /etc/openvpn/down.sh
We need to write our server config. Make sure you set any options, like port or IP/hostname. You may want to run over 443 to avoid firewalls. You also set the network information for clients that are connecting within this file.
sudo nano /etc/openvpn/server.conf
mode server tls-server local 220.127.116.11 ## ip/hostname of server port 1194 ## default openvpn port proto udp #bridging directive dev tap0 ## If you need multiple tap devices, add them here up "/etc/openvpn/up.sh br0 tap0 1500" down "/etc/openvpn/down.sh br0 tap0" persist-key persist-tun #certificates and encryption ca ca.crt cert server.crt key server.key # This file should be kept secret dh dh2048.pem tls-auth ta.key 0 # This file is secret cipher BF-CBC # Blowfish (default) comp-lzo #DHCP Information ifconfig-pool-persist ipp.txt server-bridge 192.168.1.10 255.255.255.0 192.168.1.100 192.168.1.110 push "dhcp-option DNS 18.104.22.168" push "dhcp-option DOMAIN secstuff.org" max-clients 10 ## set this to the max number of clients that should be connected at a time #log and security user nobody group nogroup keepalive 10 120 status openvpn-status.log verb 3
A guide I read recommended creating this file, but may not be necessary.
Restart the OpenVPN service.
sudo /etc/init.d/openvpn restart
Now we need to generate a certificate and key that we will copy down to the client. Feel free to use the actual name of your client instead of client-cert. It is recommended that you create a unique client certificate for each client connecting in.
cd /etc/openvpn/easy-rsa/ source vars ./pkitool client-cert
You will need to copy these files down to the client. The signing certificate, so that the client trusts your VPN, the client certificate and private key so that the VPN can trust your client, and the static key for pre-authentication.
/etc/openvpn/easy-rsa/keys/ca.crt /etc/openvpn/easy-rsa/keys/client-cert.key /etc/openvpn/easy-rsa/keys/ta.key /etc/openvpn/easy-rsa/keys/client-cert.crt
Put those files in the configuration folder on the client. For example on Windows it is “C:\Program Files\OpenVPN\Config\”. Next create a config file with the following contents in the same folder. On Windows name it “client.ovpn”, and on other platforms call it “client.conf”
### Client configuration file for OpenVPN # Specify that this is a client client # Bridge device setting dev tap # Host name and port for the server (default port is 1194) # note: replace with the correct values your server set up remote secstuff.org 1194 # Client does not need to bind to a specific local port nobind # Keep trying to resolve the host name of OpenVPN server. ## The windows GUI seems to dislike the following rule. ##You may need to comment it out. resolv-retry infinite # Preserve state across restarts persist-key persist-tun # SSL/TLS parameters - files created previously ca ca.crt cert client-cert.crt key client-cert.key # Since we specified the tls-auth for server, we need it for the client # note: 0 = server, 1 = client tls-auth ta.key 1 # Specify same cipher as server cipher BF-CBC # Use compression comp-lzo # Log verbosity (to help if there are problems) verb 3
And you should be done! OpenVPN requires a bit more hands-on than other VPNs for client setup, but hey it is free. I also took a look at OpenVPN Access Server which gives you a very similar experience to Juniper or Cisco SSL VPNS, but near as I can tell it is a commercial offering that requires a license for more than 2 concurrent connections. Looks promising though.