After creating our certificate infrastructure and testing our server and client certificates, we are ready to set up the VPN itself. OpenVPN uses a secure protocol called Diffie-Hellman to negotiate authentication (see RFC 2631 for a technical overview). We need to generate a set of parameters to facilitate this in a file called dh1024.pem. This file only needs to exist at the server VPN endpoint.
[admin@tamarack admin]$ openssl dhparam -out dh1024.pem 1024 Generating DH parameters, 1024 bit long safe prime, generator 2 This is going to take a long time ...................................................+........ [admin@tamarack admin]$
Next, we need to configure our operating system for OpenVPN. This is the only
platform-dependent configuration step in this tutorial. As we noted earlier,
our target server platform is generic GNU/Linux. If you are installing OpenVPN
on a Windows platform from pre-compiled binaries, the installer will
automatically perform the following step. On our Linux system, we configure the
tun (tunneling) software driver. If it does not already exist, use the following
commands to create the device interface file in /dev/net/ and load the
tun kernel module.
[root@tamarack /]# mkdir /dev/net [root@tamarack /]# mknod /dev/net/tun c 10 200 [root@tamarack /]# /sbin/modprobe tun
tun module allows the operating system kernel to redirect
network packets between the tunneling network device driver and a user-space
program, in our case OpenVPN. When an application wants to send a network
packet out through the VPN, it will send it through the
The kernel will then pass the packet to OpenVPN, which will use functions from
the OpenSSL library to encrypt the packet before sending it out a real network
interface to the client. Applications will receive packets from the client in
a similar way. OpenVPN will read the packet from the real network device,
decrypt it using OpenSSL functions, and then pass the decrypted packet to the
kernel that will redirect it to the
Server And Client Endpoint Configuration
A configuration file tells OpenVPN how to operate. There are many different variations possible. Here, we will set up separate server and client configurations. We want the VPN to operate in single-instance server mode. This allows all client connections to go through the same server port, and it makes configuration much easier. As mentioned before, this single-instance mode greatly reduces the burden on an administrator to support multiple clients connecting simultaneously. Previously, each client connection would require its own separately configured server instance.
In single-instance server (hereafter simply referred to as "server") mode,
ifconfig parameter works a little differently than the way it
used to in older versions of OpenVPN. The first parameter is the IP address of
the local end of the tunnel, but the second parameter is not the remote IP
address. Instead, it is the address of the gateway interface that OpenVPN will
ipconfig-pool parameter gives a range of IP addresses to
distribute to connecting clients. The
route parameter is the route
that will be set up on the local network to direct packets out of the VPN, while
push "route ..." command is the network route to set up on the
client. Here is the configuration file for our OpenVPN server endpoint.
# openvpn-server.conf # # Tunnel mode dev tun # Run as a single instance server mode server # Server endpoint appears first, followed # by the gateway interface ip ifconfig 10.1.0.1 10.1.0.2 # Range of IP addresses reserved for clients ifconfig-pool 10.1.0.4 10.1.0.254 # route setup on the server route 10.1.0.0 255.255.255.0 # route command pushed to the client push "route 10.1.0.1 255.255.255.255" # Specify tls-server for certificate exchange tls-server # Diffie-Hellman Parameters (tls-server only) dh dh1024.pem # Root certificate ca CA-DB/cacert.pem # Server certificate cert vpncert.pem # Server private key key vpnkey.pem # Check for revoked client certificates. crl-verify CA-DB/crl/crl.pem
Notice that we use the
dh option to specify the file containing
the Diffie-Hellman parameters that we created earlier. The
option only needs to appear in the server's configuration file and not in the
client's. Next, we list files containing the certificates that we will use,
starting with the root. Finally, we indicate that we want OpenVPN to check our
certificate revocation list before authorizing a client to connect to our
private network by specifying the
crl-verify option and assigning
it the location of a current CRL. We will demonstrate the CRL verification
The client configuration file is a little simpler. The only configuration
item that we have not seen before is
pull, which complements the
push "route ..." command we included in the server configuration.
pull will set up the route that we want packets destined for
our VPN to use by receiving it from the server.
# openvpn-client.conf # # Set tunnel mode dev tun # Hostname for the VPN server remote vpn.inyotech.com # This end takes the client role for # certificate exchange tls-client # Certificate Authority file ca cacert.pem # Our certificate/public key cert client1cert.pem # Our private key key client1key.pem # Get the rest of our configuration # from the server. pull
The next step is to install OpenVPN on the client. This step will only be covered here by saying that installation of OpenVPN as a client is identical to installing it as a server. After installation, complete the process by distributing the following files to the client:
- The user's private key.
- The user's certificate.
- A copy of the root certificate (so the VPN client endpoint can verify the server).
- The client configuration file.
Before starting the server, we have one last step to perform. We need to
initialize the CRL. The CRL will hold a list of user certificates that our CA
has revoked. Even though we have not revoked any user certificates yet, our
configuration still asks the OpenVPN server to check the CRL using the
crl-verify option in the server configuration. If our VPN server
cannot find a CRL, it will exit prematurely.
For now, we will initialize an empty CRL. Later, we will revoke a user
certificate and update the CRL. To initialize the CRL simply ask the CA to
generate one. (The cryptic message beginning
DEBUG[load_index] comes from a harmless bug in this particular
release of OpenSSL; ignore it.)
[admin@tamarack admin]$ openssl ca -gencrl -out \ > CA-DB/crl/crl.pem Using configuration from /home/admin/install/openssl.cnf Enter pass phrase for /home/admin/CA-DB/private/cakey.pem: DEBUG[load_index]: unique_subject = "yes" [admin@tamarack admin]$ cat CA-DB/crl/crl.pem
Now we are ready to use the following command line to start a VPN server endpoint on our local network. After executing this command, clients can connect.
[root@tamarack admin]# openvpn --config openvpn-server.conf
After the server starts, attempt to connect to it from a client. The command line at the client will be very similar, but remember to use the name of the proper configuration file. On Windows, right-clicking on the configuration file and selecting Start OpenVPN on this config file from the context menu is sufficient. Later, you will probably want to set up a shortcut on the desktop.
You should immediately be able to communicate over the VPN. If there is a
problem, it is time to troubleshoot. In this case, you will be glad that you
tested your certificate infrastructure using
s_client so you can better isolate what may be wrong.
Of course, to use the VPN tunnel fully, you will probably want to make
applicable additions to the client DNS and make sure that the routing table
that OpenVPN automatically sets up is correct for your network. We have only
provided a single host route from the client to the server. This tutorial will
not cover configuring DNS and routing. Treat the
tun device like
any other network interface.
Verifying Client Access Against a CRL
The final task that we will tackle is reliably terminating VPN access for
users when we no longer want them to connect to our network. To do this, we will
revoke their certificates and update our CRL. To figure out what certificate
belongs to which client, use the file index.txt, located in the
certificate directory tree. Look in the file to find the record containing the
commonName attribute assigned to the certificate to revoke
(remember that we established a policy of assigning the user's unique login ID
commonName attribute). This record will also contain the
serial number that the CA assigned to this certificate.
Having identified the serial number, we can locate the client certificate under newcerts in our CA directory. This directory will contain a copy of each certificate issued by our CA. The file names contain the serial numbers assigned to these certificates.
In this example, we decide to revoke the certificate for user3.
We issued this certificate earlier following the procedure described in the
section User Certificates. After looking in index.txt, we
find that the serial number assigned to the certificate with the
commonName attribute matching user3 is
04. We then know
that the correct certificate to revoke is newcerts/04.pem.
[admin@tamarack admin]$ openssl ca -revoke \ > CA-DB/newcerts/04.pem Using configuration from /home/admin/install/openssl.cnf Enter pass phrase for /home/admin/CA-DB/private/cakey.pem: DEBUG[load_index]: unique_subject = "yes" Revoking Certificate 04. Data Base Updated [admin@tamarack admin]$
The command has revoked the certificate and updated index.txt appropriately. Now we need to generate a new CRL that will contain this newly revoked certificate. Until we do this, OpenVPN will not know that we have revoked this certificate.
[admin@tamarack admin]$ openssl ca -gencrl -out CA-DB/crl/crl.pem Using configuration from /home/admin/install/openssl.cnf Enter pass phrase for /home/admin/CA-DB/private/cakey.pem: DEBUG[load_index]: unique_subject = "yes" [admin@tamarack admin]$
From this point on, user3 will not have access to the VPN, as long as the OpenVPN server endpoint checks the CRL. Remember, whenever you revoke a user's certificate, make sure to regenerate the CRL.
OpenSSL also includes the
verify command, which accepts the
-crl_check option that will allow you to make sure that your
certificate revocation list works. The
verify command requires
that the root certificate and CRL live in the same file. Before you exercise
this command, create a new temporary CRL by concatenating it with your CA
[admin@tamarack admin]$ cat \ > CA-DB/cacert.pem CA-DB/crl/crl.pem > tempcrl.pem
verify command with the
to specify the CRL to use. Here's how to verify the revocation of the
certificate for user3.
[admin@tamarack admin]$ openssl verify -CAfile tempcrl.pem \ > -crl_check user3cert.pem user3cert.pem: /O=Inyo Technical Services/CN=user3 error 23 at 0 depth lookup:certificate revoked [admin@tamarack admin]$
In order to try this with your own setup, revoke the certificate that you created for your client VPN endpoint and regenerate the CRL. You will find that you can no longer connect to the OpenVPN server from that client.
If you have followed along and experimented with the code samples provided, you should have an understanding of the basics of implementing a PKI using OpenSSL and a VPN using OpenVPN.
We have set up a certificate infrastructure including a root CA and issued
user certificates. This included configuring the OpenSSL library to add a v3
extension into the certificates issued by the CA. We have also summarized the
s_client test framework, which you can
explore further through the manual pages included with the OpenSSL
distribution. We demonstrated setting up both client and server VPN endpoints
and provided certificates for both authentication and encryption. Finally, we
have shown how to use a CRL to revoke user certificates and terminate access to
This concludes our two-part series on VPN and Public Key Infrastructure. We hope you have found it useful. Of course, we need to extend special appreciation to the creators of the OpenVPN and OpenSSL software packages and the GNU/Linux operating system that provides the solid foundation that lets us all work and build great software together. If you have any questions, feel free to contact us.
Scott Brumbaugh has worked professionally as a software/systems engineer since 1987.
Return to the Security DevCenter