Shortly after I purchased my HTC Incredible late last year to replace my iPhone 3GS, I began to think about how I could take advantage of the more open nature of the Android OS. Recently, I decided to ditch the standard Android 2.2 system and upgrade to Gingerbread a la CyanogenMod 7 (CM7).
One of the first things I noticed after the move to CM7 was that a new option appeared in the VPN settings for OpenVPN. That piqued my interest as I already knew that I had a system ready to act as an OpenVPN server (my Vyatta 6 firewall).
After reading about Google’s latest Android security problems with devices connected over unsecured WiFi networks, I decided to take a little bit of time to figure out how to better secure my wireless handset data connection. Here are the steps necessary to configure the Vyatta system to act as an OpenVPN server suitable for serving Android clients:
- Using SSH, log in to the Vyatta system as root and move in to the /usr/share/doc/openvpn/examples/easy-rsa/2.0 directory.
- Modify the “vars” file with the correct certificate details (in my file, this is the very last section). You can also change the KEY_DIR variable if you want to create your keys somewhere other than the keys subdirectory in the current directory.
- Read in the variables:
source ./vars
- Create two files in the keys directory:
touch $KEY_DIR/index.txt echo 01 > $KEY_DIR/serial
- Create the Certificate Authority certificate:
./build-ca
- Create a key for your OpenVPN server and build the Diffie-Hellman exchange file (replace “vyatta” with the name of your firewall; mine is predictably called, “vyatta”):
./build-key-server vyatta ./build-dh
- Create a key for your specific Android phone (I just called my key “android”):
./build-key android
With the keys generated, you now need to configure the Vyatta firewall to enable the OpenVPN functionality. For this example below, my DNS server is at 192.168.1.10 and I want the Android phone to be able to access that and other servers on the 192.168.1.0/24 subnet. I’ve also chosen 172.16.1.0/24 as my VPN client subnet. Change the “openvpn-option” and “subnet” strings to whatever you need for your environment. I also assume that the keys were built in the default, /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/ directory; change that configuration option to match your previous decisions. The names “vyatta.crt” and “vyatta.key” will need to match whatever you chose for your firewall name above.
configure set interfaces openvpn vtun0 encryption aes256 set interfaces openvpn vtun0 mode server set interfaces openvpn vtun0 openvpn-option "--push dhcp-option DNS 192.168.1.10 --push route 192.168.1.0 255.255.255.0" set interfaces openvpn vtun0 server subnet 172.16.1.0/24 set interfaces openvpn vtun0 server topology subnet set interfaces openvpn vtun0 tls ca-cert-file /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/ca.crt set interfaces openvpn vtun0 tls cert-file /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/vyatta.crt set interfaces openvpn vtun0 tls dh-file /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/dh1024.pem set interfaces openvpn vtun0 tls key-file /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys/vyatta.key commit save
At this point, the Vyatta firewall is prepped and ready to accept connections from your Android device. The last steps necessary are to transfer the certificate over to your phone and configure CM7 to connect to your server. Before you transfer the certificate, you’ll need to merge the files into a format that can be consumed by CM7. While still logged in to the firewall, issue the following commands:
openssl pkcs12 -export -in $KEY_DIR/android.crt -inkey $KEY_DIR/android.key -certfile $KEY_DIR/ca.crt -name CM7 -out ./certs.p12
Move that certs.p12 file over to the /sdcard/ directory on your Android phone (that location is important for some, bizarre reason – the only option available in CM7 is to install the certificate “from SD card”). I use QuickSSH to launch an SSH server on the Android phone and push the file over to the proper location.
With that file in place, navigate to the main settings on the Android phone and select “Location & security.” From there, select “Install from SD card” to load up your OpenVPN certs. Follow the prompts and create a credential storage password as requested; don’t forget that password as you’ll need it every time you start the VPN after booting the phone.
From the main settings menu, select “Wireless & network settings” and “VPN settings.” Instruct the phone to “Add VPN” and specify that you want to “Add OpenVPN VPN.” Give your VPN any name you want and set the VPN server to your external Vyatta interface. Set the CA certificate to the cert you previously installed from the SD card and the user certificate to the same. Set the DNS search domain to include your internal domain if you are so inclined.
Select “Menu” and “Advanced.” Ensure that your settings are as follows:
Server port: 1194 Protocol to use: udp Redirect gateway: Enabled Remote Sets Addresses: Enabled Cipher algorithm: AES-256-CBC Size of cipher key: 256
With that, select Back, Menu, and Save.
At this point, you should be able to select your VPN and it should connect right up. Using a terminal application on your phone (or an SSH server), you can verify that your traffic is encrypted. This is what mine looks like while I’m browsing the web on my phone (I’m connected via SSH and using ‘tcpdump “not port 22″‘ to view the traffic; port 22 traffic is excluded because I’m connected to the internal VPN client address (172.16.1.2) and as such that traffic is visible):
19:45:48.642230 IP 10.239.31.236.37332 > 24.X.X.X.openvpn: UDP, length 101 19:45:48.655078 IP 24.X.X.X.openvpn > 10.239.31.236.37332: UDP, length 213 19:45:48.678271 IP 10.239.31.236.37332 > 24.X.X.X.openvpn: UDP, length 101 19:45:48.693347 IP 24.X.X.X.openvpn > 10.239.31.236.37332: UDP, length 101 19:45:48.693927 IP 10.239.31.236.37332 > 24.X.X.X.openvpn: UDP, length 1141 19:45:48.699847 IP 10.239.31.236.37332 > 24.X.X.X.openvpn: UDP, length 309 19:45:48.713336 IP 24.X.X.X.openvpn > 10.239.31.236.37332: UDP, length 101 . . .
To my delight, I’ve found that the VPN functionality of CM7 is quite stable. I’ve configured my internal network to resolve my external VPN DNS name to the internal interface of the firewall. What this means is that when my phone is in range of my WiFi, the WiFi connects and the VPN renegotiates with the internal address – silently. When I leave the house, the VPN automatically reconnects to the external address; from the CM7 VPN perspective, it’s the same DNS name (a dyndns.org URL), but the underlying address changes based on whether the phone is connected locally or remotely. The upshot is that my VPN is always connected; I don’t really have to worry about it at all. It works surprisingly well. One caveat: you won’t be able to connect to addresses on the same client subnet when connected via WiFi after the VPN is established. For me, that meant that my DNS server was inaccessible – I addressed that problem by creating a destination NAT on the Vyatta to redirect port 53/udp on the firewall’s vtun0 interface to port 53/udp on my DNS server. I then pushed the firewall vtun0 interface IP as the DNS server to the connected VPN clients. Problem solved (although it would be smarter of me to move my server on to a different subnet than my clients, but that’s a task for another day).
The only unsolvable challenge (thus far) I’ve run into is with using the Portable Hotspot functionality of CM7 – something with the routing is messed up (even though it looks fine using ‘ip route’ on the phone) and will not work properly when the VPN is enabled. I never see the packets move over to the phone’s tun0 interface, so the packets are definitely getting hung up in the phone. That’s not a deal breaker for me, though.
Thanks to Kamil Figiela and DestinyBlog for some of the details related to OpenVPN certificate configuration and certificate bundling for CM7.
