Configuring strongSwan on Debian, RHEL and Fedora with the Android client

In my earlier blog post about VPNs, I looked at a range of VPN options.

The strongSwan wiki documentation is generally quite good but it doesn't describe the exact procedure for an Android user anywhere. This blog aims to fill that gap.

Here I am sharing some working examples of how to configure and use RSA certificate authentication between a Linux box and an Android phone using strongSwan. There are several commands to execute for each step, but they can be easily scripted.

Here are the versions in play:

Certificate creation: private certificate authority "example.org CA root"

For production, I would highly recommend creating your own root CA on a smart card and managing it from a clean machine without any network connection.

To start quickly for testing, just create a CA using the steps from the strongSwan wiki, in particular:

umask 0177
ipsec pki --gen > caKey.der
ipsec pki --self --in caKey.der \
   --dn "C=CH, O=Acme Ltd, CN=example.org CA root" \
   --ca > caCert.der

Certificate creation: VPN gateway machine vpn.example.org

Now you need to create a key for the server. The key thing to observe here is the use of the "--san" argument: the Android client expects a subjectAltName in the certificate from the server. The VPN gateway has the hostname vpn.example.org:

ipsec pki --gen > vpnKey.der
ipsec pki --pub --in vpnKey.der | \
   ipsec pki --issue --cacert caCert.der --cakey caKey.der \
  --dn 'CN=vpn.example.org' \
  --san vpn.example.org > vpnCert.der 
cp vpnKey.der /etc/ipsec.d/private/
cp vpnCert.der /etc/ipsec.d/certs/

Certificate creation: mobile user

For the Android client, it is necessary to create a private key and certificate and then embed them together with a copy of the root certificate in a PKCS#12 file. We will need OpenSSL or GnuTLS for some of these steps. The pkcs12 command will prompt for a password: make up a long, obscure password, you will only use it once when importing the certificate into the phone. Here is a script you can use for each client certificate you want to create:

#!/bin/bash -e

umask 0177
TARGET_HOST=$1
DOMAIN=example.org

IPSEC=/usr/sbin/ipsec

KEY_FILE="${TARGET_HOST}Key.der"
CRT_FILE="${TARGET_HOST}Cert.der"

if [ -f ${KEY_FILE} ];
then

  echo "$KEY_FILE exists"
  exit 1

fi

${IPSEC} pki --gen > ${KEY_FILE} 

${IPSEC} pki --pub --in  ${KEY_FILE} | \
  ${IPSEC} pki --issue \
  --cacert caCert.der --cakey caKey.der \
  --dn "CN=${TARGET_HOST}.${DOMAIN}" > ${CRT_FILE}

[ -f caCert.pem ] || \
   openssl x509 -in caCert.der -inform der -out caCert.pem -outform pem

openssl rsa \
   -in ${KEY_FILE} -out ${TARGET_HOST}Key.pem -inform der

openssl x509 \
   -in ${CRT_FILE} -inform der \
   -out ${TARGET_HOST}Cert.pem -outform pem

openssl pkcs12 \
   -export \
   -in ${TARGET_HOST}Cert.pem \
   -inkey ${TARGET_HOST}Key.pem \
   -certfile caCert.pem \
   -out ${TARGET_HOST}.p12

# delete the key files, leaving only the key in the p12 file:
rm ${KEY_FILE} ${TARGET_HOST}Key.pem

Assuming you call that script make-client-creds, you would run it once for each Android device:

$ ./make-client-creds phone1
$ ./make-client-creds phone2
...

Loading the PKCS#12 file into the phone

Copy the cert bundle (the p12 file only) to the SD card in the phone. You can mount the phone over USB or using ADB, e.g.

$ adb push phone1.p12 /sdcard/

Now go to the Android settings, select Security and Install from SD card. Follow the prompts.

Setting up the VPN gateway

Add the following line to /etc/ipsec.secrets

: RSA vpnKey.der

and add a stanza like the following to /etc/ipsec.conf

conn private-droid
	left=vpn.example.org
	leftsubnet=insert gateway IP here/32
	leftcert=vpnCert.der
	leftid=@vpn.example.org
	leftfirewall=no
	lefthostaccess=no
	right=%any
	rightsourceip=192.168.10.0/24
	auto=add

Finally, restart ipsec and you should be ready.

# service ipsec restart

Install the app on the phone

Finally, install the app on the phone. This bit should be quite easy. Once installed, press the option ADD VPN, put in the DNS name of the VPN gateway (must match the name in the certificate, e.g. vpn.example.org from the example above) and tell it to use IKEv2 Certificate as the authentication type. Press to select a certificate and highlight the certificate that you installed earlier.

Checking for problems

You should see a message on the phone telling you it is connected to the VPN.

If it fails, it will let you see the log messages. If you see the error Constraint check failed it often means that the subjectAltName was not included in the VPN gateway's certificate (see the steps above) or the DNS name doesn't match the name in the certificate.

On the server side, this command shows who is connected:

# ipsec status

Making it secure with iptables

Once the packets are decrypted by strongSwan on the VPN gateway, the kernel will route them appropriately just like any other packet. Use standard Linux netfilter/iptables rules to ensure that routing is restricted appropriately so that the clients can access the services they need and nothing else.

Support and discussion

Please feel free to post comments below or discuss on the strongSwan Users mailing list

Comments

Hi,

Can you please advice - which is better way to configure and use (if possible) 1 generated CA cert to sign all other servers certs, so user should have only this one (CA cert) intalled on his Android phone to use all servers?