strongSwan IKEv2 VPN
02 January 2017I 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 getcaCert.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 VPS 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, changingeth0
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:
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.
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 toipsec 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