OpenIKED based IPsec VPN tunnel on FreeBSD
This post will show how to set up an IPsec based VPN tunnel using OpenIKED. Road warrior clients will be placed within their own subnet of 10.0.5.0/24. Authentication between road warriors and the VPN server will be based on certificates. A word of advice for those attempting this journey; IPsec based VPNs with certificate based authentication is a messy endeavour. The first messy part is the Internet Key Exchange (IKE), both client and server have their own set of supported algorithms. During key negotiation a common ground needs to be found between client and server regarding cipher suites. Second messy part are the certificates, as a random guy on the internet, has so nicely phrased: public key infrastructure (PKI) and X.509 certificates are a wild, wild, west.
Config
The configuration file for the IPsec tunnel is very simple. For a full set of options see iked.conf(5).
# /usr/local/etc/iked.conf
ikev2 "bram" esp \
from any to 10.0.5.0/24 \
local vpn.cbbg.nl peer any \
srcid vpn.cbbg.nl \
config address 10.0.5.0/24 \
config name-server 192.168.0.1
I suspect the srcid
is used to find the matching server certificate.
packet filter (PF) config
Below is an excerpt from my pf config file with the relevant pieces related to creating an IPsec VPN tunnel.
# /etc/pf.conf
udp_services = "{isakmp, ipsec-nat-t}"
nat on $ext_if from 10.0.5.0/24 to any -> ($ext_if)
pass in proto udp to any port $udp_services
IPsec requires port 500 (isakmp) and if one of the devices is behind a NAT, port 4500 (ipsec-nat-t) is required as well. Service names and the related ports are specified in /etc/services
. After making changed to the configuration file, make sure to reload it again using pfctl -f /etc/pf.conf
.
Certificates
For authentication purposes, at least three certificates are required. These are:
- Root certificate (Certificate Authority)
- Server certificate to authenticate the server
- Client certificate(s) to authenticate client(s)
This section will describe how these certificates are generated using the openssl command. Note that these certificates can also be generated by using the ikectl(8) command, but for educational purposes it is fun to do manually.
Root certificate
This is the mother of all certificates, and is most commonly referred to as the Certificate Authority (CA). This certificate is used for signing the other certificates, thereby creating a chain of trust. The commands to create the CA certificate are listed below.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out ca.pem
openssl req -x509 -days 1001 -key ca.pem -sha1 -addext basicConstraints=CA:TRUE -subj "/C=NL/O=Jabberwocky/CN=Jabberwocky Root CA" -out ca.crt
First the private and public key pair is generated and stored in ca.pem
. After this the root certificate is generated.
Server certificate
This certificate is used by the server to authenticate itself to the clients. It is generated in similar fashion as the root certificate, with the major difference that this time CA
is set to FALSE
.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out server.pem
openssl req -x509 -CA ca.crt -CAkey ca.pem -key server.pem -sha1 -addext basicConstraints=CA:FALSE -addext "subjectAltName=DNS:vpn.cbbg.nl" -subj "/C=NL/O=Mad Hatter Inc./CN=vpn.cbbg.nl" -days 365 -out server.crt
Client certificate(s)
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out client.pem
openssl req -x509 -CA ca.crt -CAkey ca.pem -key client.pem -sha1 -addext basicConstraints=CA:FALSE -subj "/C=NL/CN=bram@cbbg.nl" -days 365 -out client.crt
openssl pkcs12 -export -legacy -in client.crt -inkey client.pem -out client.p12 -name "VPN Client key" -CAfile ca.crt -chain
The last command creates a PKCS#12 file which bundles the client certificate, the client private key, and the CA certificate neatly into one file. The first time trying to import the client certificate on Android, I had the cryptic error “type the correct password”. This had nothing to do with password, but instead with the algorithm used for certificate encryption. Adding the -legacy
option resolved this error.
Installing keys and certificates
Finally, copy all certificates and keys to the right places.
cp ca.crt /usr/local/etc/iked/ca
cp server.crt client.crt /usr/local/etc/iked/certs
cp server.pem /usr/local/etc/iked/private/local.key
On Android the PKCS#12 file can be imported from Settings->Biometrics and security->Other security settings->Install from device storage.
Debugging
Hardly ever will something work the first time, so here are some tips and tricks for debugging.
Server side
For printing loads of debug messages about the connection process, start the OpenIKED deamon running in the foreground.
iked -d -vv -f /usr/local/etc/iked.conf
Dumping policies and security associations:
setkey -PD
setkey -D
Print statistics on the Encapsulating Security Payload (ESP) packages and IPsec protocol:
netstat -ss -p esp
netstat -ss -p ipsec
The -ss
option omits counters which are zero. To set them anyway, use a single -s
.
Note that when using tcpdump, you will only see the encapsulated packages. The packages before and after encapsulation will not show up on an interface. If you would like to see these packages or apply filtering on them, have a look at the enc(4) interface.
Client side
On the road warrior side, the strongSwan application has a convenient log viewer to analyse what is happing on the client side.
Certificates
Dump certificate information:
openssl x509 -in client.crt -text -noout
On Windows platforms, the built in certutil can be used:
certutil -dump client.p12
Comments