The first step when setting up OpenVPN is to create a Public Key Infrastructure (PKI). The PKI consists of:
- A public master Certificate Authority (CA) certificate and a private key.
- A separate public certificate and private key pair (hereafter referred to as a certificate) for each server and each client.
To facilitate the certificate creation process, OpenVPN comes with a collection of RSA key manangement scripts (based on the openssl command line tool) known as easy-rsa.
In this article the needed certificates are created by root in root’s home directory. This ensures that the generated files have the right ownership and permissions, and are safe from other users.
Installing the easy-rsa scripts
Install the scripts by doing the following:
# pacman -S easy-rsa
# cp -r /usr/share/easy-rsa /root
Creating certificates
Change to the directory where you installed the scripts.
# cd /root/easy-rsa
To ensure the consistent use of values when generating the PKI, set default values to be used by the PKI generating scripts. Edit /root/easy-rsa/vars and at a minimum set the KEY_COUNTRY, KEY_PROVINCE, KEY_CITY, KEY_ORG, and KEY_EMAIL parameters (do not leave any of these parameters blank). Change the KEY_SIZE parameter to 2048 for the SSL/TLS to use 2048bit RSA keys for authentication.
/root/easy-rsa/vars
# easy-rsa parameter settings # NOTE: If you installed from an RPM, # do not edit this file in place in # /usr/share/openvpn/easy-rsa -- # instead, you should copy the whole # easy-rsa directory to another location # (such as /etc/openvpn) so that your # edits will not be wiped out by a future # OpenVPN package upgrade. # This variable should point to # the top level of the easy-rsa # tree. export EASY_RSA="`pwd`" # # This variable should point to # the requested executables # export OPENSSL="openssl" export PKCS11TOOL="pkcs11-tool" export GREP="grep" # This variable should point to # the openssl.cnf file included # with easy-rsa. export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA` # Edit this variable to point to # your soon-to-be-created key # directory. # # WARNING: clean-all will do # a rm -rf on this directory # so make sure you define # it correctly! export KEY_DIR="$EASY_RSA/keys" # Issue rm -rf warning echo NOTE: If you run ./clean-all, I will be doing a rm -rf on $KEY_DIR # PKCS11 fixes export PKCS11_MODULE_PATH="dummy" export PKCS11_PIN="dummy" # Increase this to 2048 if you # are paranoid. This will slow # down TLS negotiation performance # as well as the one-time DH parms # generation process. export KEY_SIZE=2048 # In how many days should the root CA key expire? export CA_EXPIRE=3650 # In how many days should certificates expire? export KEY_EXPIRE=3650 # These are the default values for fields # which will be placed in the certificate. # Do not leave any of these fields blank. export KEY_COUNTRY="US" export KEY_PROVINCE="CA" export KEY_CITY="Acme Acres" export KEY_ORG="Acme" export KEY_EMAIL="roadrunner@acmecorp.org" #export KEY_EMAIL=mail@host.domain export KEY_CN=Acme-CA export KEY_NAME=Acme-CA export KEY_OU="" export PKCS11_MODULE_PATH=changeme export PKCS11_PIN=1234
Export the environment variables.
# source ./vars
Delete any previously created certificates.
# ./clean-all
The build-ca script generates the Certificate Authority (CA) certificate.
# ./build-ca
Generating a 2048 bit RSA private key ..............++++++ ...++++++ writing new private key to 'ca.key' ----- 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) [US]: State or Province Name (full name) [CA]: Locality Name (eg, city) [Acme Acres]: Organization Name (eg, company) [Acme]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) [Acme-CA]: Name [Acme-CA]: Email Address [roadrunner@acmecorp.org]:
The build-key-server script # ./build-key-server <server name>
generates a server certificate. Make sure that the server name (Common Name when running the script) is unique.
# ./build-key-server elmer
Generating a 2048 bit RSA private key .....................++++++ .......................................................++++++ writing new private key to 'elmer.key' ----- 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) [US]: State or Province Name (full name) [CA]: Locality Name (eg, city) [Acme Acres]: Organization Name (eg, company) [Acme]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) [elmer]: Name [Acme-CA]: Email Address [roadrunner@acmecorp.org]: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: Using configuration from /root/easy-rsa/openssl-1.0.0.cnf Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'US' stateOrProvinceName :PRINTABLE:'CA' localityName :PRINTABLE:'Acme Acres' organizationName :PRINTABLE:'Acme' commonName :PRINTABLE:'elmer' name :PRINTABLE:'Acme-CA' emailAddress :IA5STRING:'roadrunner@acmecorp.org' Certificate is to be certified until Dec 27 19:11:59 2021 GMT (3650 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
The build-dh script generates the Diffie-Hellman parameters .pem file needed by the server.
# ./build-dh
Generating DH parameters, 2048 bit long safe prime, generator 2 This is going to take a long time ..+............................................................................. . . . ............+...............+................................................... ..................................................................++*++*
The build-key script # ./build-key <client name>
generates a client certificate. Make sure that the client name (Common Name when running the script) is unique.
# ./build-key bugs
Generating a 2048 bit RSA private key ....++++++ .............................................................++++++ writing new private key to 'bugs.key' ----- 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) [US]: State or Province Name (full name) [CA]: Locality Name (eg, city) [Acme Acres]: Organization Name (eg, company) [Acme]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) [bugs]: Name [Acme-CA]: Email Address [roadrunner@acmecorp.org]: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: Using configuration from /root/easy-rsa/openssl-1.0.0.cnf Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'US' stateOrProvinceName :PRINTABLE:'CA' localityName :PRINTABLE:'Acme Acres' organizationName :PRINTABLE:'Acme' commonName :PRINTABLE:'bugs' name :PRINTABLE:'Acme-CA' emailAddress :IA5STRING:'roadrunner@acmecorp.org' Certificate is to be certified until Dec 27 19:18:27 2021 GMT (3650 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
Generate a secret Hash-based Message Authentication Code (HMAC) by running: # openvpn --genkey --secret /root/easy-rsa/keys/ta.key
This will be used to add an additional HMAC signature to all SSL/TLS handshake packets. In addition any UDP packet not having the correct HMAC signature will be immediately dropped, protecting against:
- Portscanning.
- DOS attacks on the OpenVPN UDP port.
- SSL/TLS handshake initiations from unauthorized machines.
- Any eventual buffer overflow vulnerabilities in the SSL/TLS implementation.
All the created keys and certificates have been stored in /root/easy-rsa/keys. If you make a mistake, you can start over by running the clean-all script again.
Converting certificates to encrypted .p12 format
Some software (such as Android) will only read VPN certificates that are stored in a password-encrypted .p12 file. These can be generated with the following command:
# openssl pkcs12 -export -inkey keys/bugs.key -in keys/bugs.crt -certfile keys/ca.crt -out keys/bugs.p12
Checking Using OpenSSL
If you need to check the information within a Certificate, CSR or Private Key, use these commands. You can also check CSRs and check certificates using our online tools.
- Check a Certificate Signing Request (CSR)
openssl req -text -noout -verify -in CSR.csr
- Check a private key
openssl rsa -in privateKey.key -check
- Check a certificate
openssl x509 -in certificate.crt -text -noout
- Check a PKCS#12 file (.pfx or .p12)
openssl pkcs12 -info -in keyStore.p12