Security DevCenter
oreilly.comSafari Books Online.Conferences.


Deploying a VPN with PKI
Pages: 1, 2, 3


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

The 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 tun device. 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 tun device.

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, the 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 use locally.

The 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 the 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

# Range of IP addresses reserved for clients

# route setup on the server

# route command pushed to the client
push "route"

# Specify tls-server for certificate exchange

# 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 dh 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 feature later.

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. Here 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

# This end takes the client role for
# certificate exchange

# 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.

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_server and 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 to the 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 certificate.

[admin@tamarack admin]$ cat \
> CA-DB/cacert.pem CA-DB/crl/crl.pem > tempcrl.pem

Use the verify command with the -crl_check option 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_server and 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 our VPN.

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

Sponsored by: