OpenVPN with Modern Cryptography

The standard OpenVPN installation uses RSA and a hefty Diffie-Hellman parameters file. This is not ideal, but it’s possible to run OpenVPN using elliptic curves.

This was all done on OpenVPN 2.4.1. As far as I know, elliptic curve cryptography support in OpenVPN is for 2.4.0+.

PKI

Get Easy-RSA and set up variables in the vars file.

set_var EASYRSA_ALGO     ec
set_var EASYRSA_CURVE    secp521r1
set_var EASYRSA_DIGEST   "sha512"

The choice of curve is a personal one. secp521r1 is P-521. DJB considers it a nice prime. All supported curves are listed with openvpn --show-curves (these are mine).

There’s a bug in Easy-RSA regarding sourcing this file. The workaround is to export EASYRSA_VARS_FILE=/etc/easy-rsa/vars (or put it in .bashrc or whatever).

Make the PKI and build the CA with easyrsa init-pki, easyrsa build-ca.

easyrsa gen-req servername nopass
easyrsa sign-req server servername
easyrsa gen-req clientname [nopass]
easyrsa sign-req client clientname

We now have all the server files

pki/ca.crt
pki/issued/servername.crt
pki/private/servername.key

and all the client files

pki/ca.crt
pki/issued/clientname.crt
pki/private/clientname.key

(there’s some nonsense about 3DES-encrypting the client key, which I’m ignoring).

If you didn’t set the nopass option but now regret it, run openssl ec -in clientname.key -out clientname_nopass.key, enter your password and rename the keys.

VPN

Copy the server and client files to their respective OpenVPN directories.

Here’s an example server configuration.

port 1194
proto udp
dev tun

ca ecc/ca.crt
cert ecc/servername.crt
key ecc/servername.key

dh none

server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1"
push "dhcp-option DNS 1.2.3.4"

keepalive 10 120

tls-crypt ecc/tc.key
auth SHA512
keysize 256
tls-server
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
cipher AES-256-GCM
reneg-sec 360
remote-cert-eku "TLS Web Client Authentication"
script-security 2
auth-user-pass-verify /etc/openvpn/server/auth/auth.py via-file

user nobody
group nobody

persist-key
persist-tun

status openvpn-status.log
explicit-exit-notify 1

And a client configuration.

client
dev tun
proto udp
remote serverurl 1194
resolv-retry infinite
nobind
#user nobody
#group nobody
persist-key
persist-tun
tls-client
mute-replay-warnings
ca servername/ecc/ca.crt
cert servername/ecc/clientname.crt
key servername/ecc/clientname.key
remote-cert-eku "TLS Web Server Authentication"
verify-x509-name 'CN=servername' subject
remote-cert-tls server
tls-crypt servername/ecc/tc.key
cipher AES-256-GCM
auth SHA512
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
reneg-sec 360
#comp-lzo
verb 3
#mute 20

auth-user-pass servername/secret.password
redirect-gateway def1
script-security 2
up /etc/openvpn/client/servername/update-resolv-conf.sh
down /etc/openvpn/client/servername/update-resolv-conf.sh

For several devices/users, managing certs, etc., can be tedious to do by hand. I wrote some code to automate it.