Deploying a VPN with PKI
Pages: 1, 2, 3
OpenVPN
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
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 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
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_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.
Conclusion
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
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 9 of 9.
-
OpenVPN..openssl s_client -CAfile \
2006-10-26 16:49:08 peteythapitbull [Reply | View]
-
OpenVPN..openssl s_client -CAfile \
2006-10-26 18:33:23 inyotech [Reply | View]
I notice this in the above error message text:
... fopen:No such file or directory ... fopen('client1cert.pem','r')
Maybe you can double check that the certificate file is in your current directory or use the full path on the command line?
Hope this helps,
Scott B -
OpenVPN..openssl s_client -CAfile \
2006-10-27 14:13:04 peteythapitbull [Reply | View]
Thnx for your help...
But I'm confused because I have just been following the instructions below:
OpenSSL Test Framework
Now, after we have issued a couple of user certificates, we can make sure that our procedures are all correct by taking advantage of the two test commands provided by the OpenSSL package. The programs s_server (secure server) and s_client (secure client) can exercise almost the entire library and their operation is straightforward.
Start an OpenSSL secure server session in one terminal window. Start an OpenSSL secure client session in another. The client will contact the server using the SSL/TLS protocol at localhost using port 4433. You will be able to type messages into the console hosting the secure client and see them appear at the secure server. It will be immediately obvious if your certificates are not correct or there is a problem with your OpenSSL library installation.
Here we start an OpenSSL secure server at the command line. For arguments, we include the server certificate and server private key. The argument -verify 1 causes the server to ask any connecting client to send a certificate for authentication. (Note that the output from these commands is more verbose than these trimmed code examples indicate.)
[admin@tamarack admin]$ openssl s_server -cert vpncert.pem \
> -key vpnkey.pem -verify 1
verify depth is 1
Using default temp DH parameters
ACCEPT
...
[admin@tamarack admin]$
Now, in another console window, we start an OpenSSL secure client using the command argument -cert to provide a certificate to send to the server for authentication. The -key argument gives the private key to use when encrypting messages and the -CAfile argument points to the root certificate.
[admin@tamarack admin]$ openssl s_client -CAfile \
> CA-DB/cacert.pem -cert client1cert.pem -key client1key.pem
Enter PEM pass phrase:
...
[admin@tamarack admin]$
When the connection attempt succeeds, you can send sample messages between the client and server by typing text into either secure endpoint. To quit the session, type Q in the terminal window.
Now we know that our certificates can encrypt messages passed between two OpenSSL applications. However, we have not yet made sure that we can use our certificates with any arbitrary X.509-certificate-secured application. Adding the -WWW option to the s_server command will effectively create a secure web server that can serve any local file to a web-browsing client connecting using SSL/TLS. We will exercise this feature next.
Some else suggested I type the full path but the file client1cert.pem doesn't exist. So I thought it was going to be created. just like the vpncert-req.pem file.
Thnx again..I'm just a noob
-
if anyone gets stuck in the same way...
2004-10-26 08:33:11 myriapod [Reply | View]
I'm testing the described setup on Mandrake 10.
First of all I had to download openssl-0.9.7d from the cooker cos the default was 0.9.7c.
Then using the openssl.cnf provided by this article I kept getting this ugly error on every certificate signing attempt:
variable lookup failed for CA_vpn::default_md
15411:error:02001002:system library:fopen:No such file or directory:bss_file.c:104:fopen('/home/vpn/ca/index.txt.attr','rb')
15411:error:2006D080:BIO routines:BIO_new_file:no such file:bss_file.c:107:
15411:error:0E064072:configuration file routines:CONF_load:no such file:conf_def.c:197:
15411:error:0E06D06C:configuration file routines:NCONF_get_string:no value:conf_lib.c:329:group=CA_vpn name=default_md
Adding:
default_md = md5
to openssl.cnf fixes the problem.
Hope it helps.
Bye. -
if anyone gets stuck in the same way...
2004-10-26 13:56:25 inyotech [Reply | View]
I think you might have err'd on cut-n-paste as I can see this in the middle of the config file:
# Issued certificates will be valid for 1 year
default_days = 365
default_crl_days= 30
# Hashing function
default_md = md5
Although maybe it needs to be in a different section. Thanks for the note. -
if anyone gets stuck in the same way...
2006-03-27 11:24:13 amjice [Reply | View]
Can this MD be changed to something like "SHA1"? Sorry if this is a basic questions. I'm a bit of a newbie.
I've already created the keys and certs after changing it to SHA1 but couldn't really make heads or tails about whether it took or not.
Thanks.
-
thanks for the great article!
2004-10-26 03:44:25 myriapod [Reply | View]
Hi, this tutorial was both interesting and useful.
I was wondering: do you consider the described setup safe enough to deploy it in a production environment?
Where should I go from here to make it really secure?
thank you! -
thanks for the great article!
2004-10-26 14:02:04 inyotech [Reply | View]
Hi,
Thanks for the note. In my opinion the articles give a pretty complete beginning introduction to the subject. I wrote them when I was trying to figure out digital certificates and openvpn and could not find all of the basic info in one single place. As such, the articles are general and simplified. I do think that you could use the setup outlined in the tutorial in a small shop with a few permanent users that are not coming or going and where the data stored on the network was not sensative. That is, if you are experienced and can devote the time and energy.
I think that in a larger network where new users are constantly being added and removed and where the network may hold sensative data, the skill and knowlege of the administrator is critical. A commercial package may be a good choice there, and after reading the articles and working the code examples you will have the knowledge to help you make a good choice. I cannot answer your question more fully thant to say that the Internet and OReilly's site is full of security related articles.
Thanks,
Scott B



# openssl s_client -CAfile \
> CA-DB/cacert.pem -cert client1cert.pem -key client1key.pem
unable to get certificate from 'client1cert.pem'
31297:error:02001002:system library:fopen:No such file or directory:/usr/src/lib/libssl/src/crypto/bio/bss_file.c:278:fopen('client1cert.pem','r')
31297:error:20074002:BIO routines:FILE_CTRL:system lib:/usr/src/lib/libssl/src/crypto/bio/bss_file.c:280:
31297:error:140AD002:SSL routines:SSL_CTX_use_certificate_file:system lib:/usr/src/lib/libssl/src/ssl/ssl_rsa.c:515:
Thnx for any help or feed back