This post does NOT provide full tutorial of setting-up IKEv2 VPN. Please refer to Vultr’s Guide for step-by-step tutorial.
Pure certificate authentication means certificates are used for both server & client authentication. No PSK (pre-shared key) is involved.
Pros: safer than weak password; can’t be easily shared by verbal; no need to share the server PSK; difficult to spoof the server.
Cons: more complicated to configure.
Most configuration tutorials generally use server PSK + client PSK (usually IKEv1) or server cert + client PSK (usually IKEv2). This is enough for own use or sharing with a few friends. However, for sharing with many people or within an organization, cert auth will be more convenient. Based on general settings, the following paragraphs elaborates how to setup cert auth and tips.
Strongswan configuration
Sample ipsec.conf
:
config setup
uniqueids = never
#Default profile
conn %default
dpdaction=clear
dpddelay=3600s
dpdtimeout=300s
fragmentation=yes
rekey=no
ike=aes256gcm16-aes256gcm12-aes128gcm16-aes128gcm12-aesxcbc-sha256-sha1-modp4096-modp2048-modp1024,aes256-aes128-sha256-sha1-modp4096-modp2048-modp1024,3des-sha1-modp1024!
esp=aes128gcm12-aes128gcm16-aes256gcm12-aes256gcm16-modp4096-modp2048-modp1024,aes128-aes256-sha1-sha256-modp4096-modp2048-modp1024,aes128-sha1-modp4096,aes128-sha1-modp1024,aes128-sha1,3des-sha1!
left=%defaultroute
leftauth=pubkey
leftcert=vpnHostCert.pem
leftsendcert=always
leftsubnet=0.0.0.0/0
right=%any
rightauth=pubkey
rightsourceip=192.168.11.0/24
rightdns=8.8.8.8, 8.8.4.4
#IKEv1. Note this is pure PSK conf as an alternative only
conn ikev1-psk-xauth
keyexchange=ikev1
leftauth=psk
leftsendcert=never
rightauth=psk
rightauth2=xauth
auto=add
#IKEv2 basic conf. Write your own server fqdn
conn ikev2-pubkey
keyexchange=ikev2
leftid=YOUR.VPN.SERVER.FQDN
rightid=%any
auto=add
#IKEv2 + EAP-TLS
conn ikev2-eap-tls
also="ikev2-pubkey"
rightauth=eap-tls
eap_identity=%identity
Notes:
fragmentation
means breaking down large chump of data to smaller blocks, which is quite important for cert auth, especially with some wicked ISP. However, some clients may have compatibility issue. For example, Windows 7 may or may not have trouble connecting. Please test on your own.ike
andesp
stipulates encryption algorithms. The algorithms here is enough for popular clients.- Each
conn
paragraph is a configuration. You can choose any name you like (except %default).also
can expand based on previous conf. - Essentially
left
refers to the server andright
refers to the client. leftid
andrightid
are required by a few clients like iOS.- We configured an IKEv1 here, because there is no native IKEv2 support on Android. To avoid chicken or the egg problem and due to heavy block against PPTP, we put an IKEv1 here. Note that you have to write relevant PSK in ipsec.secrets.
Generate mobileconfig file for iOS
Below is the shell script for automatically generating mobileconfig file. You can save it as mobiconf.sh
.
#!/bin/sh
if [ $1 ]; then
localid="$1@SOME.DOMAIN"
else
echo "Error: missing parameter"
echo "Usage: mobiconf.sh <username> [passphrase]"
exit 1
fi
passphrase=$2
remoteid=${3:-'YOUR.VPN.SERVER.FQDN'}
remoteid_r=$(echo $remoteid | awk 'BEGIN{FS=".";OFS=".";ORS=""}{for (i=NF;i>0;i--) printf("%s%s",$i,(i>1?OFS:ORS))}')
ca_name=${4:-'MY CA COMMON NAME'}
conf_name=${5:-'MY CONF'}
vpn_name=${6:-'MY VPN'}
uuid_conf=$(uuidgen)
uuid_vpn=$(uuidgen)
uuid_p12cert=$(uuidgen)
uuid_cacert=$(uuidgen)
p12cert_file=$1.p12
cacert_file="cacerts/strongswanCert.pem"
output_file=$1.mobileconfig
cat >${output_file} <<EOF
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Set the name to whatever you like, it is used in the profile list on the device -->
<key>PayloadDisplayName</key>
<string>${conf_name}</string>
<!-- This is a reverse-DNS style unique identifier used to detect duplicate profiles -->
<key>PayloadIdentifier</key>
<string>${remoteid_r}</string>
<!-- A globally unique identifier, use uuidgen on Linux/Mac OS X to generate it -->
<key>PayloadUUID</key>
<string>${uuid_conf}</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadContent</key>
<array>
<!-- It is possible to add multiple VPN payloads with different identifiers/UUIDs and names -->
<dict>
<!-- This is an extension of the identifier given above -->
<key>PayloadIdentifier</key>
<string>${remoteid_r}.instance</string>
<!-- A globally unique identifier for this payload -->
<key>PayloadUUID</key>
<string>${uuid_vpn}</string>
<key>PayloadType</key>
<string>com.apple.vpn.managed</string>
<key>PayloadVersion</key>
<integer>1</integer>
<!-- This is the name of the VPN connection as seen in the VPN application later -->
<key>UserDefinedName</key>
<string>${vpn_name}</string>
<key>VPNType</key>
<string>IKEv2</string>
<key>IKEv2</key>
<dict>
<!-- Hostname or IP address of the VPN server -->
<key>RemoteAddress</key>
<string>${remoteid}</string>
<!-- Remote identity, can be a FQDN, a userFQDN, an IP or (theoretically) a certificate's subject DN. Can't be empty.
IMPORTANT: DNs are currently not handled correctly, they are always sent as identities of type FQDN -->
<key>RemoteIdentifier</key>
<string>${remoteid}</string>
<!-- Local IKE identity, same restrictions as above. If it is empty the client's IP address will be used -->
<key>LocalIdentifier</key>
<string>${localid}</string>
<!-- Optional, if it matches the CN of the root CA certificate (not the full subject DN) a certificate request will be sent
NOTE: If this is not configured make sure to configure leftsendcert=always on the server, otherwise it won't send its certificate -->
<key>ServerCertificateIssuerCommonName</key>
<string>${ca_name}</string>
<!-- Optional, the CN or one of the subjectAltNames of the server certificate to verify it, if not set RemoteIdentifier will be used -->
<key>ServerCertificateCommonName</key>
<string>${remoteid}</string>
<!-- The server is authenticated using a certificate -->
<key>AuthenticationMethod</key>
<string>Certificate</string>
<!-- The client uses EAP to authenticate -->
<key>ExtendedAuthEnabled</key>
<integer>1</integer>
<key>PayloadCertificateUUID</key>
<string>${uuid_p12cert}</string>
<!-- The next two dictionaries are optional (as are the keys in them), but it is recommended to specify them as the default is to use 3DES.
IMPORTANT: Because only one proposal is sent (even if nothing is configured here) it must match the server configuration -->
<key>IKESecurityAssociationParameters</key>
<dict>
<key>EncryptionAlgorithm</key>
<string>AES-128</string>
<key>IntegrityAlgorithm</key>
<string>SHA1-96</string>
<key>DiffieHellmanGroup</key>
<integer>14</integer>
</dict>
<key>ChildSecurityAssociationParameters</key>
<dict>
<key>EncryptionAlgorithm</key>
<string>AES-128</string>
<key>IntegrityAlgorithm</key>
<string>SHA1-96</string>
<key>DiffieHellmanGroup</key>
<integer>14</integer>
</dict>
</dict>
</dict>
<dict>
<key>PayloadIdentifier</key>
<string>${remoteid_r}.cert.client</string>
<key>PayloadUUID</key>
<string>${uuid_p12cert}</string>
<key>PayloadType</key>
<string>com.apple.security.pkcs12</string>
<key>PayloadVersion</key>
<integer>1</integer>
<!-- Optional password to decrypt the PKCS#12 container, if not set the user is prompted when installing the profile -->
<key>Password</key>
<string>${passphrase}</string>
<!-- This is the Base64 encoded PKCS#12 container with the certificate and private key for the client.
IMPORTANT: The CA certificate will not be extracted from the container, so either install it separately or include it as payload (as seen above) -->
<key>PayloadContent</key>
<data>
$(cat ${p12cert_file}|base64)
</data>
</dict>
<!-- This payload is optional but it provides an easy way to install the CA certificate together with the configuration -->
<dict>
<key>PayloadIdentifier</key>
<string>${remoteid_r}.cert.ca</string>
<key>PayloadUUID</key>
<string>${uuid_cacert}</string>
<key>PayloadType</key>
<string>com.apple.security.root</string>
<key>PayloadVersion</key>
<integer>1</integer>
<!-- This is the Base64 (PEM) encoded CA certificate -->
<key>PayloadContent</key>
<data>
$(grep -v '^-.*-$' ${cacert_file})
</data>
</dict>
</array>
</dict>
</plist>
EOF
Notes:
- Configuration for cert auth via GUI seems broken on iOS 9.3.2, so we have to use mobileconfig file to install.
- User p12 & CA files are prerequisites for using this script. You should tailor the parameters & path to your VPN settings.
- The generated mobileconfig file has integrated user p12 file (base64-encoded) and CA cert (base64-encoded). Therefore only mobileconfig is needed and no additional certs are needed.
- Pay special attention that this file can only be installed through iOS native Mail app or Safari. You cannot install it via other mail apps.
Compatibility of clients & ISP (China Mainland)
After many tests, OS supporting of IKEv2 is listed below:
- Windows 7: Maybe yes, maybe no (sometimes fails when fragmentation is enabled), depending on individual client OS.
- Windows 10: Yes, but requires manual configuration of gateway & metrics (either via control panel or PowerShell).
- Windows 10 mobile:Almost no, due to no way to configure gateway & metrics, unless deploying with MDM which is used by large corporations.
- Android 6.0: No native support, but Strongswan client is available on Google Play.
- iOS 9.3.2: Yes, but have to configure via mobileconfig file.
- Shanghai Telecom normal broadband: Windows sometimes fails (>60% probability), but the connection won’t drop once connected. Usually no problem for other OS.
- Shanghai Unicom 4G LTE: Usually can connect.
- Shanghai Mobile 4G LTE: Almost not connectable. Seems non-DNS UDP packets are dropped.
Tips for installation method
Android
No native support for IKEv2. Please install Strongswan app.
There are two methods to import certificates. First, importing cert in Strongswan (i.e. for Strongswan only). Second, importing in Settings -> Security -> Credential Storage -> Import from Internal Storage or SD card (i.e. for System, but may display security warning).
Windows 7
In short: Install CA cert on Local Computer and install User cert on Current User. As for the other certs imported along with .p12 file, you may delete them.
Steps (both are required):
- Step One: search mmc.exe in Start Menu and run as administrator. Click File -> Add/Remove Snap-in… -> Certificates -> Add -> Computer account -> OK. Click Trusted Root Certification Authorities in the left panel. Click Action -> All Tasks -> Import. Import the p12 file into Local Computer.
- Step Two: Double click the p12 file and install it to Current User.
Windows 10
Steps (both are required):
- Step One: Double click p12 file and install it to Local Computer.
- Step Two: Double click p12 file and install it to Current User.
After configuring VPN, you may find that network is still directly connected. This is because Win10 by default doesn’t add default gateway and enables Split Tunneling. To make it global, you have to manually configure via control panel or PowerShell.
Click the network icon in System Tray -> Network & Internet Settings -> Change adapter options. Right-clck the VPN connection -> Property -> Networking -> Internet Protocol Version 4 (TCP/IPv4) -> Property -> Advanced. Check “Use default gateway on remote network”. Uncheck Automatic metric and set 15 or smaller in the textbox below.
(Microsoft: This is NOT a BUG! It’s a FEATURE! We’ll never fix it!)
Windows 10 mobile
Not possible unless deploying with MDM tools for large corporations.
Update: Actually there is workaround…
(Microsoft: Our OS is designed for large corporations. No support for small companies or individuals!)
iOS 9.3.2
Seems not possible via Settings GUI and user has to install through mobileconfig file.
(Apple: Our products are fool-proof! Our bugs? Let developers struggle against those.)
Other tips
For OpenVZ, you have to install libipsec, otherwise the below error will prompt:
charon: 12[IKE] unable to install inbound and outbound IPsec SA (SAD) in kernel
If you installed Strongswan from epel repo, simply run yum install strongswan-libipsec
and it will work.