How to Build Secure VPN Between iOS and OS X with OpenVPN
There is currently no secure VPN option between iOS and OS X, which is a significant problem if you must access your box remotely or need a trusted connection on an untrusted network.
This post explains how to build an OpenVPN secure VPN server on OS X and connect to it from an iOS device. As far as I know, this is the only way to get a secure VPN link between your iPhone or iPad and your Mac. Until Apple replaces its VPN on OS X Server with a secure option, I intend this to replace my OS X Server VPN.
OS X Server VPN is insecure as it only uses the insecure and broken <http://arstechnica.com/security/2012/07/broken-microsoft-sheme-exposes-traffic/> PPTP and L2TP protocols with MS-CHAPv2 ("PPTP traffic should be considered unencrypted") or pre-shared keys (PSKs, "IPSEC-PSK is arguably worse than PPTP ever was for a dictionary-based attack vector") <https://www.cloudcracker.com/blog/2012/07/29/cracking-ms-chap-v2/>. The only secure options are certificate-based L2TP/IPSec or SSL-based OpenVPN. Unfortunately, there simply are no Kerberos-based certificate VPN clients for iOS, but fortunately, an excellent OpenVPN option exists on iOS. The only trick is to stand up an OpenVPN server on iOS. Running your own OpenVPN server is free, and the client app will set you back about seven dollars.
This information is scattered across the web, so I'll integrate into one place here explicitly for an OS X/iOS solution.
Step 1. Get OpenVPN on OSX and configure it.
1A. I like Macports, so assuming that you've downloaded and installed Xcode from the App Store, installed Macports, run:
sudo port selfupdate
sudo port install openvpn
2A. Create your own SSL/TLS certificates with OpenSSL (automatically installed as a OpenVPN dependent by Macports). Remember, every OpenSSL file name .key is secret and must be protected on both your OS X box and transmitted securely to iOS (as below) using either ssh or the method described at the GuizmoVPN website. You must also use a strong, secure pass phrase to protect the certificate authority you will create in this step. The integrity of your VPN relies on performing this step properly and then properly protecting your secret keys. For any security issues, such as with a lost or stolen iPhone, you must discard the compromised certificate and repeat these steps.
su root
cd /opt/local/share/doc/openvpn2/easy-rsa/2.0
# edit script defaults like KEY_CN == Common Name
vi ./vars
mkdir ./keys
touch ./keys/index.txt
echo 1 > ./keys/serial
. ./vars
./clean-all
./build-ca --pass
./build-key-server server-domainname
# choose a unique Common Name (CN) for each client
./build-key client-domainname
./build-dh
openvpn2 --genkey --secret ./keys/ta.key
# Notes:
# Use the domain name "domainname.com" for the common name
# Contact email "admin@domainname.com" must match name in CA;
# otherwise, there will be some X509 error.
# For the server-domainname cert, use the default common name
# "server-domainname".This must also match the client configuration
# setting:
# tls-remote domainname.com
# Unnecessary if you already signed with ./build-key[-server]
# ./sign-req server-domainname
# ./sign-req client-domainname
cd keys
openssl verify -CAfile ca.crt ca.crt
openssl verify -CAfile ca.crt server-domainname.crt
openssl verify -CAfile ca.crt client-domainname.crt
1C. Configure OS X to route your VPN packets correctly. See <https://forums.openvpn.net/topic11401.html>.
su
mkdir /Library/Application\ Support/vpn
vi /Library/Application\ Support/vpn/enable-vpn-forward-nat.sh
#!/bin/bash
#
# Sleep is necessary cause network has to be up at the time of following commands
# Otherwise the network will not work at all
#
sleep 15
#
sysctl -w net.inet.ip.fw.enable=1
sysctl -w net.inet.ip.forwarding=1
natd -interface en0
ipfw add divert natd ip from any to any via en0
chmod 755 /Library/Application\ Support/vpn/enable-vpn-forward-nat.sh
On OS X Server, make sure that ipfw is running and, if blocked, that the firewall allows UDP port 443. On OS X client, I believe that the App firewall will take care of all this automatically.
sudo ipfw enable firewall
sudo ipfw add allow udp from any to any 443
Make these changes permanent on boot:
su
vi /Library/LaunchDaemons/net.openvpn.enable-vpn-forward-nat.plist
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >
<plist version="1.0">
<dict>
<key>Label</key>
<string>net.openvpn.enable-vpn-forward-nat</string>
<key>ProgramArguments</key>
<array>
<string>/Library/Application Support/vpn/enable-vpn-forward-nat.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
sudo launchctl load -w
/Library/LaunchDaemons/net.openvpn.enable-vpn-forward-nat.plist
Step 2. Get Tunnelblick on OS X and configure it.
2A. <http://code.google.com/p/tunnelblick/>
2B. Create a .tblk directory for your VPN server with all the necessary files. I'll demo a tun setup. The LAN here looks like a router on 10.0.1.1 and a OS X Server on 10.0.1.3.
mkdir ~/Desktop/Domainname_tun.tblk
cd /opt/local/share/doc/openvpn2/easy-rsa/2.0/keys
sudo cp -p ca.crt dh2048.pem server-domainname.crt server-domainname.key ta.key ~/Desktop/Domainname_tun.tblk
sudo chown -R username ~/Desktop/Domainname_tun.tblk
cd ~/Desktop/Domainname_tun.tblk
vi config.ovpn
local 10.0.1.3
port 443
proto udp
dev tun
;dev tap
ca ca.crt
cert server-domainname.crt
key server-domainname.key
tls-auth ta.key 0
dh dh2048.pem
server 10.8.0.0 255.255.255.0
;server-bridge 10.0.1.98 255.255.255.0 10.0.1.50
10.0.1.90
push "redirect-gateway def1"
push "dhcp-option DNS 8.8.8.8"
;push "dhcp-option DNS 10.0.1.3"
;push "dhcp-option DOMAIN domainname.com."
client-to-client
keepalive 10 120
;cipher BF-CBC
comp-lzo
max-clients 10
user nobody
group nobody
persist-key
persist-tun
ifconfig-pool-persist ipp.txt
verb 3
2C. Forward UDP port 443 from your router to you server at 10.0.1.3. (You may also wish to forward the default OpenVPN port 1194 as well to test other configurations.)
2D. Doubleclick on ~/Desktop/Domainname_tun.tblk within Finder, which should start Tunnelblick and import your configuration. Then,
Tunnelblick>VPN Details ... >Configuration>Settings>Set Nameserver (3.1)
You may also wish to launch this service at boot.
Hit connect and Tunnelblick should launch your OpenVPN server on UDP port 443.
Step 3. Get GuizmoVPN on iOS and configure it.
3A. <http://www.guizmovpn.com/>
3B. Create a configuration .zip file for the GuizmoVPN OpenVPN client:
mkdir ~/Desktop/tun_client-domainname
cd /opt/local/share/doc/openvpn2/easy-rsa/2.0/keys
sudo cp -p ca.crt client-domainname.crt client-domainname.key ta.key ~/Desktop/tun_client-domainname
sudo chown -R username ~/Desktop/tun_client-domainname
cd ~/Desktop/tun_client-domainname
vi tun_client-domainname.conf
####
## Domainname Mac UDP client configuration version 2.0
####
client
dev tun
proto udp
remote server.domainname.com 443
redirect-gateway def1
resolv-retry infinite
nobind
;user nobody
;group nobody
persist-key
persist-tun
ca ca.crt
cert client-domainname.crt
key client-domainname.key
ns-cert-type server
tls-auth ta.key 1
;auth-user-pass
tls-remote server-domainname
tls-cipher DHE-RSA-AES256-SHA
;cipher BF-CBC
comp-lzo
verb 3
# shaper 50000
cd ~/Desktop
zip -r tun_client-domainname.zip tun_client-domainname
3C. Securely copy the file tun_client-domainname.zip to your iOS device by either:
(1) GuizmoVPN's web server: <http://www.guizmovpn.com/index.php?option=com_content&view=article&id=3&Itemid=3>
(2) SMIME encrypted email to yourself, click on the .zip file, Open In ... GuizmoVPN.
(3) A combination of ssh and iFile's web server (password enabled, running on your LAN).
3D. GuizmoVPN>Settings>DNS Configuration>DNS Push ON
3E. GuizmoVPN>General>Connect ON
Watch your log file to see the authentication, push options, and routing work. This will give you an IP of, e.g., 10.8.0.6 on your LAN, secured with TLS.
Finally, if anyone knows how to configure these additional items, please post: use of my own DNS server, and bridged connections.
(A) My LAN's DNS server is at 10.0.1.3 (same as the OpenVPN server), which serves up LAN addresses for my server and local clients. I'd like to use this DNS server as my OpenVPN client's DNS server rather than 8.8.8.8. Problem is, DNS is fail when I specify
push "dhcp-option DNS 10.0.1.3"
in the server config above. Why?! Could the client be trying to hit 10.0.1.3 on the internet, rather than my LAN? That's the only thing I can think of, but that doesn't make sense to me either because I can OpenVPN into VNC via 10.0.1.3:5900 just fine, as well http on 10.0.1.3:80 and all other services. Why would LAN DNS fail?
(B) I'd like to use bridging mode with the "dev tap" server+client settings:
dev tap
server-bridge 10.0.1.3 255.255.255.0 10.0.1.50 10.0.1.90
But that fails -- the client connects with assigned IP 10.0.1.50, but its packets don't appear to go anywhere. Pings fail in both directions, web at 10.0.1.3:80 fails, and of course DNS fails. Not sure if this is a tap issue on OS X, a Tunnelblick issue, or an ipfw issue. Any suggestions to troubleshoot or magic ipfw incantations would be greatly appreciated.
Mac mini Server (Mid 2010), Mac OS X (10.7.4), Lion Server, EyeTV HD, Turbo.264 HD