VPN Certificate management for strongswan
Templating openssl
Openssl is found to work best with a templating strategy, with different config files for each application, so we make a .cnf file for each target certificate, though in some situations the same .cnf can make several targets.
They are based on /etc/ssl/openssl.cnf
,
and can define files such as /etc/ipsec.d/req/phone.cnf or /etc/ipsec.d/req/gate.cnf
Reference sections
- oid_section = new_oids
Define some oids
- [ new_oids ]
- dnssecEmbeddedChain = 1.3.6.1.4.1.11129.2.1.4
- xmppAddr = 1.3.6.1.5.5.7.8.5
- xpserver_ext = 1.3.6.1.5.5.7.3.1
- xpclient_ext = 1.3.6.1.5.5.7.3.2
- ipsec_end_sys = 1.3.6.1.5.5.7.3.5
- ipsec_tunnel = 1.3.6.1.5.5.7.3.6
- ipsec_user = 1.3.6.1.5.5.7.3.7
- pkinit_usage_client = 1.3.6.1.5.2.3.4
- pkinit_usage_kdc = 1.3.6.1.5.2.3.5
Define the ingredients of a certificate request
- [ req ]
- default_bits = 4096
- distinguished_name = req_distinguished_name
- attributes = req_attributes
- x509_extensions = v3_ca
- req_extensions = v3_req
- utf8 = yes
Define the name of the target certificate
This defines the friendly name, some implementations may expect it to match a node DNS name, even though that is what alternate names are for.
- [ req_distinguished_name ]
- commonName =
- commonName_default =Example Station
No request attributes are required
- [ req_attributes ]
Define CA section
- [ ca ]
- default_ca = CA_default
CA section
All work relates to ipsec directory.
- [ CA_default ]
- unique_subject = no
- dir = /etc/ipsec.d
- certificate = $dir/cacerts/example.crt
- private_key = $dir/private/example.key
- database = $dir/reqs/example.ca.txt
- serial = $dir/reqs/example.ca.serial
- certs = $dir/certs
- new_certs_dir = $dir/certs
- default_days = 365
- x509_extensions = usr_cert
- default_md = default
- policy = policy_anything
Define the policy
- [ policy_anything ]
- commonName = supplied
Tell CA about settings for certificate extensions.
- [ usr_cert ]
- basicConstraints = CA:FALSE
- subjectKeyIdentifier=hash
- authorityKeyIdentifier=keyid,issuer
- subjectAltName=@example_alt_names
Tell request module settings for certificate extensions.
- [ v3_req ]
- basicConstraints = CA:FALSE
- keyUsage = nonRepudiation, digitalSignature, keyEncipherment
- #extendedKeyUsage = ipsec_user,ipsec_tunnel,ipsec_end_sys
- subjectAltName=@example_alt_names
Tell ca module settings for certificate extensions.
- [ v3_ca ]
- ##dnssecEmbeddedChain = ASN1:FORMAT:HEX,OCT:${ENV::CHAIN}
- #dnssecEmbeddedChain = DER:${ENV::CHAIN}
- basicConstraints = CA:TRUE
- subjectKeyIdentifier=hash
- authorityKeyIdentifier=keyid:always,issuer
- subjectAltName=@example_alt_names
- keyUsage = nonRepudiation, digitalSignature, keyEncipherment
- #extendedKeyUsage = ipsec_user,ipsec_tunnel,ipsec_end_sys
- [ example_alt_names ]
- DNS.0 = example.
- #otherName.0 = xmppAddr;UTF8:example.
Regeneration script
Here it is kept in /etc/ipsec.d/ipsecinit to keep it with the other files
The key regeneration hopefully is only rarely needed, so is commented off; that is, if a compromise is suspected.
A choice of elliptic curve or power modulus keys is possible.
- #!/bin/sh
- #openssl genrsa 4096 > /etc/ipsec.d/private/gate.key
- #openssl genrsa 4096 > /etc/ipsec.d/private/phone.key
- #openssl ecparam -genkey -name secp521r1 -noout -out /etc/ipsec.d/private/gate.key
- #openssl ecparam -genkey -name secp521r1 -noout -out /etc/ipsec.d/private/phone.key
The remainder of script will be run much more often to adjust certificate parameters to handle any new features in future versions of clients and servers.
Intentionally we keep nothing that is key derived, this means certificates etc, except config files and scripts.
(Re)generating all the selfsigned certificates
- for N in gate phone
- do
- S=/etc/ipsec.d/reqs/$N.cnf
- K=/etc/ipsec.d/private/$N.key
- P=/etc/ipsec.d/reqs/$N.pub
- C=/etc/ipsec.d/cacerts/$N.crt
- R=/etc/ipsec.d/reqs/$N.req
- #openssl rsa -pubout -in $K > $P
- D=`grep ^default_days $S | cut -d= -f2` # openssl took no notice of the days in the .cnf
- openssl req -new -batch -key $K -config $S -out $R
- openssl req -new -batch -key $K -config $S -x509 -out $C -days $D
- done
Regenerate cross certificates for the gateway
- rm /etc/ipsec.d/reqs/gate.ca.*
- touch /etc/ipsec.d/reqs/gate.ca.txt
- echo 00 > /etc/ipsec.d/reqs/gate.ca.serial
- openssl ca -batch -config /etc/ipsec.d/reqs/gate.cnf -in /etc/ipsec.d/reqs/phone.req -out /etc/ipsec.d/certs/phone-by-gate.crt
Regenerate cross certificates for the phone
- rm /etc/ipsec.d/reqs/phone.ca.*
- touch /etc/ipsec.d/reqs/phone.ca.txt
- echo 00 > /etc/ipsec.d/reqs/phone.ca.serial
- openssl ca -batch -config /etc/ipsec.d/reqs/phone.cnf -in /etc/ipsec.d/reqs/gate.req -out /etc/ipsec.d/certs/gate-by-phone.crt
Make a certificate package for android
- openssl pkcs12 -name "IPSEC fun pack"
-in /etc/ipsec.d/certs/phone-by-gate.crt
-inkey /etc/ipsec.d/private/phone.key
-certfile /etc/ipsec.d/cacerts/gate.crt
-export -out /tmp/$USER-phone.p12
Store the $USER-phone.p12 and /etc/ipsec.d/cacerts/phone.crt to the android SDCARD, as it is usually preserved if the android needs a factory reset.
Use the native filesystem to import the .p12, saying it is for VPN and apps. Use the strongswan app to import phone.crt, it appears in the IMPORTED and may appear in USER. It can be then removed from USER (leaving it in IMPORTED) to stop Android generating security warnings, which makes USER effectively useless.
Can now configure an IKEv2 Certificate connection strongswan app in android with independence from pkix, selecting the imported ca from IMPORTED.
The cross certifying where the phone's keypair was used to sign the gateway keypair allows a VPN to be setup using the native android client, such as IPSEC hybrid RSA, in this case there is no warning about trusting "an app" strongswan but it did not support both ipv4 and ipv6 over ipv4. When creating a connection,
select the same p12 as both server certificate and ca certificate.
Next steps
See the strongswan ipsec setup