strongSwan IKEv2 VPN

02 January 2017
I had a look at the strongSwan Android VPN app, and one nice feature is that it allows certificates (but not user keys) to be imported directly, bypassing some of Android's irritations such as credential store security requirements. This was enough motivation to try out IKEv2 EAP (username/password) as an alternative to L2TP/IPSec with strongSwan.

Certificate setup

The certificate setup is same as with certificate-based L2TP/IPSec, but since Windows7 has somewhat pickey certificate requirements, extra parameters are needed when generating the VPN server's certificate. For simplicity, the expanded commandline for this stage is given below with the extra parameters highlighted:

ipsec pki --issue --cacert caCert --cakey caKey \ --dn "C=UK, OU=VPN, O=MyNET, CN=VPN" \ --san "vpn.example.com" \ --flag serverAuth --flag ikeIntermediate --in serverKey.pub > serverCert

Android client setup

If you want to avoid using Android's credentials store because of its assocated irritations, you only need to get caCert.pem (the CA certificate in X509 PEM format, see previous guide) onto your phone and import it directly into the strongSwan app. Annoyingly the only way to easily import the certificate was via Google Drive, as the strongSwan app doesn't seem to be able to load from arbitary SD card locations. Pity really as loading it via adb push using the Android SDK is for me much more convenient, but it does mean that the app needs no special permissions to install.

Windows client setup

Although I didn't test it, Windows7 supports this setup out-of-the-box, although one gotcha is that Windows is particularly pickey about what certificates for IKEv2 connections contain, which is taken care of with the above.

Linux client setup

This is covered below.

strongSwan EAP “Hybrid Mode” setup

This is almost a direct copying of strongSwan's EAP for multiple Windows7 clients guide, and this will provide something much like IPSec Hybrid mode: Server authenticates with a certificate, a secure connection is established, and finally the client authenticates with userid/password exchange. This avoids the need for installing a user key on the client.

/etc/ipsec.conf

config setup plutostart=no conn certvpn keyexchange=ikev2 ike=aes256-sha1-modp1024! esp=aes256-sha1! dpdaction=clear dpddelay=300s rekey=no left=%any leftsubnet=0.0.0.0/0 leftauth=pubkey leftcert=server.crt leftid=@vpn.example.com right=%any rightsourceip=192.168.128.128/23 rightdns=8.8.8.8 rightauth=eap-mschapv2 eap_identity=%any auto=add

Change vpn.example.com to whatever you gave the --san parameter above, which can be a resolved IP address in dotted format if you don't have a DNS FQDN. In this setup I use 192.168.128.128/23 (i.e. 192.168.128.128 to 192.168.128.254) as the pool for client IP addresses.

/etc/ipsec.secrets

: RSA server.key mobile : EAP "sekret" laptop : EAP "magick"

/etc/strongswan.conf

charon { dns1 = 8.8.8.8 dns2 = 8.8.4.4 load_modular = yes plugins { include strongswan.d/charon/*.conf } } include strongswan.d/*.conf

Only change from default here is adding Google's DNS server, as using these avoids any problems that might arise from using your VPN provider's DNS servers.

Firewall setup

You'll need to enable IP Forwarding. Otherwise this basic iptables setup should be fine for NAT'ing all client traffic, changing eth0 if appropriate:

iptables -P FORWARD ACCEPT iptables -t nat -A POSTROUTING -s 192.168.128.0/24 -o eth0 -j MASQUERADE

If you are not happy using a default iptables FORWARD rule of ACCEPT then strongSwan does have the capability to add connection-specific forwarding rules via the use of leftfirewall=yes. These rules are very specific to the connection, but annoyingly are placed at the top of the FORWARD table by the stock firewall script. My personal preference is a ruleset which boils down to the following:

iptables -P FORWARD DENY iptables -A FORWARD -p tcp --dport 25 ! -d smtp.example.com -j REJECT iptables -A FORWARD -p tcp --dport 194 -j REJECT iptables -A FORWARD -p tcp --dport 465 -j REJECT iptables -A FORWARD -i eth0 -s 192.168.128.0/24 -m policy --dir in --pol ipsec --proto esp -j ACCEPT iptables -A FORWARD -o eth0 -d 192.168.128.0/24 -m policy --dir out --pol ipsec --proto esp -j ACCEPT iptables -t nat -A POSTROUTING -s 192.168.128.0/24 -o eth0 -j MASQUERADE

This is a slightly tighter version of the rules in the OpenWrt wiki but not quite as tight as that leftfirewall=yes results in. SMTP, SMTP/TLS, and IRC are specifically blocked as a damage-limitation measure because in my experience these are the ports that attract by far the most trouble when machines on the internet are compromised.

Linux client setup

With strongSwan setting up a Linux client is basically flipping around the left/right entries in ipsec.conf and setting the client-side to use a specific identity. To my knowledge it is possible to setup ipsec.conf in such a way that allows it to be identical on both the server and client, but that is not something a investigated to any real depth.

/etc/ipsec.conf

config setup plutostart=no conn certvpn keyexchange=ikev2 #ike=aes256-sha1-modp1024! #esp=aes256-sha1! dpdaction=restart dpddelay=120s left=%any leftauth=eap leftid=laptop leftfirewall=yes right=vpn.example.com rightid=@vpn.example.com rightsubnet=0.0.0.0/0 rightauth=pubkey #eap_identity=%any auto=add leftsourceip=%config

Main thing to have is rightsubnet=0.0.0.0/0 and leftfirewall=yes which together will cause strongSwan to route all traffic over the VPN to the VPS gateway. My choice of dpddelay and dpdaction cause the connection to ping every 2 minutes, and to restart it if the remote end seems to be dead.

/etc/ipsec.secrets

laptop : EAP "magick"

Certificates and keys

In this setup only the CA certificate from the previous guide needs to be copied:

cp caCert /etc/ipsec.d/cacerts/

Client startup

/usr/sbin/ipsec start /usr/sbin/ipsec up certvpn

Client shutdown

/usr/sbin/ipsec down certvpn /usr/sbin/ipsec stop

Gotchas

Unable to authenticate

If there are errors on the server related to MSCHAPv2, such as below, it is due to the required authentication plugin not being available:

charon: 06[IKE] EAP-Identity request configured, but not supported charon: 06[IKE] loading EAP_MSCHAPV2 method failed

On Ubuntu, the EAP-MSCHAPv2 plugin is in a seperate package from strongSwan:

apt-get install strongswan-plugin-eap-mschapv2

Once installed, strongSwan with automatically detect it during startup, so no configuration changes will be required.

Slackware client con't connect

Errors such as these will appear on the console in response to ipsec up certvpn:

authentication of 'vps.example.com' with RSA_EMSA_PKCS1_SHA256 successful server requested EAP_IDENTITY (id 0x00), sending 'laptop' EAP_IDENTITY not supported, sending EAP_NAK generating IKE_AUTH request 2 [ EAP/RES/NAK ]

Much the same as above, the mschap-v2 module is missing. This can be checked using ipsec statusall | grep mschap. I had to hack the strongSwan SlackBuild script to add the following:

--enable-eap-aka --enable-eap-mschapv2 --enable-eap-identity --enable-openssl

Connection authenticates then disconnects

Authentication is successful, but then the connection drops with errors like the ones below.

charon: 12[KNL] received netlink error: Protocol not supported (93) charon: 12[KNL] unable to add SAD entry with SPI c23eab9a charon: 12[KNL] received netlink error: Protocol not supported (93) charon: 12[KNL] unable to add SAD entry with SPI b889db8f charon: 12[IKE] unable to install inbound and outbound IPsec SA (SAD) in kernel charon: 12[IKE] failed to establish CHILD_SA, keeping IKE_SA

This to my knowledge is caused by the kernel not having all the required options, and in the cases when you simply cannot change the kernel, the workaround is to use strongSwan entirely in userspace. You need to install the kernel-libipsec module, which on Ubuntu is in the strongswan-plugin-kernel-libipsec package, and then in /etc/strongswan.d/charon/kernel-libipsec.conf change load = no to load = yes. You will need to use the following firewall rules:

iptables -A FORWARD -i ipsec+ -o venet0 -j ACCEPT iptables -A FORWARD -i venet0 -o ipsec+ -j ACCEPT iptables -t nat -A POSTROUTING -s 192.168.128.0/24 -o venet0 -j MASQUERADE