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:
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, 18.104.22.168.22.214.171.124.2 [alt_names] DNS.1 = ipsec.jeanbruenn.info IP.1 = 126.96.36.199
Replace 188.8.131.52 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 :firstname.lastname@example.org
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/emailAddressemail@example.com 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/emailAddressfirstname.lastname@example.org 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:184.108.40.206 X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication, 220.127.116.11.18.104.22.168.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
apt-get install strongswan libcharon-extra-plugins
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 email@example.com:/etc/ipsec.d/certs/ christine.pem 100% 1017 91.1KB/s 00:00
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.
%any : ECDSA christine.priv.pem
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
- Server: ipsec.jeanbruenn.info
- Typ: IKEv2 EAP-TLS (Certificate)
- User Certificate: (the .p12 file)
- User Identity: 22.214.171.124
- CA: auto
Took me a while to get this working. Be sure that user identity, the IP in the certificate, ecetera matches.
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.