IPsec between strongswan and my android phone (IKEv2 EAP-TLS)

So and here we go again. Another article about ipsec using strongswan.

I’d like my mobile phone (google pixel 2) to access my own servers and services through an ipsec tunnel. For that I’am going to create an ECDSA key and a certificate.

Keys and certificate

ECDSA private key

jean@christine ~ $ mkdir ipsec
jean@christine ~ $ cd ipsec
jean@christine ~/ipsec $ ls
jean@christine ~/ipsec $ openssl ecparam -out christine.priv.pem -name secp384r1 -genkey -noout

Pretty simple. Bear in mind that only the following curves will work for IKEv2:

  • prime256v1
  • secp384r1
  • secp521r1

Certificate

Add the following to a file called openssl.cnf:

[v3_req]
subjectKeyIdentifier = hash
basicConstraints     = critical,CA:false
subjectAltName       = @alt_names
keyUsage             = critical,digitalSignature,keyEncipherment
extendedKeyUsage     = serverAuth, 1.3.6.1.5.5.8.2.2
 
[alt_names]
DNS.1                = ipsec.jeanbruenn.info
IP.1                 = 185.37.145.136

Replace 185.37.145.136 with your IPSec servers IP. In case you’re wondering why this might be necessary, let me quote the documentation:

Important: The hostname/IP of the VPN server, as configured in the VPN profile, has to be contained as subjectAltName extension in the VPN server’s certificate. Since 1.6.0 the server identity may also be configured explicitly. StrongSwan Wiki: AndroidVPNClient

Also bear in mind that

If you intend to use IP addresses instead of host names with Windows clients, add them in a subjectAltName of type dNSName (i.e. DNS:x.x.x.x) and not one of type iPAddress (i.e. IP:x.x.x.x). The client will throw a 13801 error if this is not met. The same applies to some versions of Apple’s iOS/Mac OS X when using EAP-TLS, which will fail with error 1001 -9807. StrongSwan Wiki: Win7CertReq

Now you may create the certificate like this

jean@christine ~/ipsec $ openssl req -new -x509 -key christine.priv.pem -out christine.pem -days 7300 \
                         -config <(cat /etc/ssl/openssl.cnf openssl.cnf) -extensions v3_req
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Somewhere in space
Locality Name (eg, city) []:Earth
Organization Name (eg, company) [Internet Widgits Pty Ltd]:.
Organizational Unit Name (eg, section) []:.
Common Name (e.g. server FQDN or YOUR name) []:ipsec.jeanbruenn.info
Email Address []:himself@jeanbruenn.info

Verify that everything is fine (shortened a bit for readability)

jean@christine ~/ipsec $ openssl x509 -in christine.pem -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 9465773191777157955 (0x835d2e90ec4b0343)
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: C=DE, ST=Somewhere in space, L=Earth, CN=ipsec.jeanbruenn.info/emailAddress=himself@jeanbruenn.info
        Validity
            Not Before: Feb  5 21:04:54 2018 GMT
            Not After : Jan 31 21:04:54 2038 GMT
        Subject: C=DE, ST=Somewhere in space, L=Earth, CN=ipsec.jeanbruenn.info/emailAddress=himself@jeanbruenn.info
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (384 bit)
                pub: 
                    xx
                ASN1 OID: secp384r1
                NIST CURVE: P-384
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                xx
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Alternative Name: 
                DNS:ipsec.jeanbruenn.info, IP Address:185.37.145.136
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, 1.3.6.1.5.5.8.2.2
    Signature Algorithm: ecdsa-with-SHA256
         xx

ecdsa-with-sha256, pretty cool isn’t it?

bundling it into a PKCS#12 file

Lastly, we need to package it so that we can import it on the phone’s app.

jean@christine ~/ipsec $ openssl pkcs12 -in christine.pem -inkey christine.priv.pem -export -out christine.p12
Enter Export Password:
Verifying - Enter Export Password:
jean@christine ~/ipsec $ ls
christine.p12  christine.pem  christine.priv.pem  openssl.cnf

Server configuration

Install strongswan

apt-get install strongswan libcharon-extra-plugins

Certificates

Move both christine.pem to your /etc/ipsec.d/certs folder and christine.priv.pem to /etc/ipsec.d/private. You should use some secure way to transfer the files e.g.

jean@christine:~/ipsec$ scp christine.pem root@ipsec.jeanbruenn.info:/etc/ipsec.d/certs/
christine.pem                                 100% 1017    91.1KB/s   00:00

/etc/ipsec.conf

conn android
    compress=yes
    dpdaction=hold
    dpddelay=60s
    fragmentation=yes
    forceencaps=yes
    leftcert=christine.pem
    leftauth=pubkey
    leftsubnet=some-net
    right=%any
    rightauth=eap-tls
    rightsendcert=never
    rightsourceip=some-ip
    keyexchange=ikev2
    auto=add

Replace some-ip with an IP or cidr – your client will get that IP (or one of the network you’ve added here). Replace some-net with the network which should be accessible through the tunnel by your client.

/etc/ipsec.secrets

%any : ECDSA christine.priv.pem

iptables

Replace x.x.x.x with the IP your client gets assigned (see rightsourceip in ipsec.conf)

iptables -t nat -A POSTROUTING -s x.x.x.x/32 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT
iptables -t nat -A POSTROUTING -s x.x.x.x/32 -o eth0 -j MASQUERADE

Client configuration

  • Server: ipsec.jeanbruenn.info
  • Typ: IKEv2 EAP-TLS (Certificate)
  • User Certificate: (the .p12 file)
  • User Identity: 185.37.145.136
  • CA: auto

Took me a while to get this working. Be sure that user identity, the IP in the certificate, ecetera matches.

Testing

I’ve just installed an nginx with php-fpm and displayed $_SERVER[‚REMOTE_ADDR‘] to verify that if I do use my mobile phone accessing it will show the IP I’ve got from the tunnel instead of my real IP. There might be more simple checks, though.

No Comments

Post a Comment