Setting up OpenVPN with Android and Tomato

Introduction

I recently updated my router’s firmware to Advanced Tomato, which is just a modern HTML5 reskin of Tomato by Shibby, which is an update of the original Tomato for the famous WRT54GL. Tomato is a router firmware that supports a wide variety of improved functions, including QoS, realtime bandwidth monitoring and logging, easy LAN DHCP management, etc. – including an OpenVPN server and client, as well as a few other VPN solutions. Tomato supports a number of routers, including my ASUS RT-N16.

I thought I’d try to combine Tomato’s OpenVPN server with OpenVPN for Android, allowing my Galaxy Note II1 to have a fixed endpoint regardless of data connection method (WiFi, 3G, 4G LTE) and increased privacy when connected to public WiFi.

Setup

Tomato

Before starting, I recommend backing up the current configuration settings in Tomato’s Administration > Configuration section, as this procedure can use a significant amount of NVRAM. If a problem occurs, it can be fixed by restoring the saved configuration file.

To start, customize the settings in Tomato’s VPN > OpenVPN Server section to your preferences:

Tomato VPN
Tomato VPN settings page

Key Generation

Unfortunately, OpenVPN for Android doesn’t seem to play well with ‘static’ key authentication (a single identical private key on both machines), so we’ll have to set up TLS. That requires implementing a custom public key infrastructure (‘PKI’: CA certificate, server key and certificate, and client keys and certificates). While I’m not directly following the Debian instructions for OpenVPN setup, I’ll be using their easy-rsa package of scripts to generate and manage the required certificates on one of my Debian 8 virtual machines.

After installing easy-rsa, make a copy for this particular usage and open the vars file:


cp -R /usr/share/easy-rsa ~/tomatoVPN
cd tomatoVPN && pico vars

Customize the definitions at the bottom of the vars file, then continue to generate the certificates:


source ./vars
./clean-all
./pkitool --initca
./pkitool --server tomato
./build-dh
./pkitool <clientname>

With output:


source ./vars
NOTE: If you run ./clean-all, I will be doing a rm -rf on /home/<you>/tomatoVPN/keys
./clean-all
./pkitool --initca
Using CA Common Name: <your CN> CA
Generating a 2048 bit RSA private key
................................+++
............................................+++
writing new private key to 'ca.key'
-----

./pkitool --server tomato
Generating a 2048 bit RSA private key
.........................+++
.......................................................................+++
writing new private key to 'tomato.key'
-----
Using configuration from /home/nickersonm/tomatoVPN/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'<your info>'
stateOrProvinceName   :PRINTABLE:'<your info>'
localityName          :PRINTABLE:'<your info>'
organizationName      :PRINTABLE:'<your info>'
organizationalUnitName:PRINTABLE:'<your info>'
commonName            :PRINTABLE:'tomato'
name                  :PRINTABLE:'<your info>'
emailAddress          :IA5STRING:'<your info>'
Certificate is to be certified until Jul 21 00:21:18 2027 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated

./build-dh
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
...............................................................................
<many more lines>
......................................................+....................++*++*

./pkitool <clientname>
Generating a 2048 bit RSA private key
....+++
............+++
writing new private key to '<clientname>.key'
-----
Using configuration from /home/nickersonm/tomatoVPN/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'<your info>'
stateOrProvinceName   :PRINTABLE:'<your info>'
localityName          :PRINTABLE:'<your info>'
organizationName      :PRINTABLE:'<your info>'
organizationalUnitName:PRINTABLE:'<your info>'
commonName            :PRINTABLE:'<clientname>'
name                  :PRINTABLE:'<your info>'
emailAddress          :IA5STRING:'<your info>'
Certificate is to be certified until Jul 21 00:28:57 2027 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated

Several of these will need to be transferred to the Android device eventually:


mkdir keys/<clientname>
cp keys/ca.crt keys/<clientname>.key keys/<clientname>.crt keys/<clientname>

And the rest are needed for the Tomato interface:


mkdir keys/tomato
cp keys/ca.crt keys/tomato.key keys/tomato.crt keys/dh2048.pem keys/tomato

Back to Tomato

In the Tomato VPN configuration screen’s ‘Keys’ tab, paste the contents of the appropriate files into the fields in order:

  • keys/tomato/ca.crt into ‘Certificate Authority’
  • keys/tomato/tomato.crt into ‘Server Certificate’
  • keys/tomato/tomato.key into ‘Server Key’
  • keys/tomato/dh2048.pem into ‘Diffie Hellman parameters’

And then save the Tomato settings and verify that the router has nonzero free NVRAM – if the certificates used up all available NVRAM, you will have to free up space or may be unable to utilize this feature.

To investigate NVRAM usage, you can use the Administration > Debugging > Download NVRAM Dump option. This will show where NVRAM is being used – I had to delete the unused Advanced Settings > Adblock lists, default Administration > Scripts comments, and unused QoS rules. Alternatively, it’s possible to use local files for the certificates and load them with the VPN > OpenVPN Server > Advanced > Custom Configuration. As I could not free sufficient NVRAM, I decided to place the certificates on my router’s filesystem. SSH can be configured in Administration > Admin Access – after doing so, I ended up using pscp2 to transfer the certificates to the home directory of root:
pscp -scp -r -load local-tomato openvpn-keys/ 192.168.1.1:/tmp/home/root from my machine, and
chmod -R 0600 /tmp/home/root/openvpn-keys/ on the router3. They can then be loaded in OpenVPN with this custom configuration:


ca /tmp/home/root/openvpn-keys/ca.crt
cert /tmp/home/root/openvpn-keys/tomato.crt
key /tmp/home/root/openvpn-keys/tomato.key
dh /tmp/home/root/openvpn-keys/dh2048.pem
Load keys from the filesystem instead of NVRAM

Tomato’s OpenVPN server can now be started with the ‘play’ button in the upper-right of the page.

Android Device

Transfer the three files noted earlier — ca.crt, <clientname>.key, and <clientname>.crt — to your Android device. I use Syncthing and its Android app to keep selected folders synchronized between my desktop4, Note II, and other devices – I utilized this to transfer the keys.

Select these files in the first tab of a new connection in the OpenVPN Android app. Also make sure to change the Authentication > Remote certificate subject to tomato (set during key generation via ./pkitool --server tomato). If your phone is ever on the same LAN as your router, you also want to enable Advanced > Allow floating server so that the LAN IP address of your router will be accepted by the OpenVPN client in addition to the WAN address.

Set the remote certificate subject to ‘tomato’
Allow floating server if on same LAN

OpenVPN on Android should now be able to connect to the Tomato OpenVPN server!

It’s possible to hide the OpenVPN persistent notification, but unfortunately Android versions before 5.0 will have a system notification about the VPN connection that is impossible to hide. 5.0 and later should allow it to be customized or hidden.

Footnotes

  1. Yes, quite old – I haven’t found an acceptable replacement yet; perhaps the ASUS Zenfone AR or the Galaxy Note 8, assuming it’s rootable
  2. Windows’ version of scp from the PuTTY suite
  3. Probably unnecessary if your router is only accessible locally
  4. SyncTrayzor is a good Windows GUI for it

Leave a Reply

Your email address will not be published. Required fields are marked *