Print

Deploying a VPN with PKI

by Scott Brumbaugh
10/21/2004

This article is the second of two focusing on tunneling VPNs and Public Key Infrastructure (PKI). The first article provided a simple overview of the technology for people without a deep computer security background. This article is a walk-through tutorial that implements the concepts covered previously. We assume that the reader has some knowledge of VPN and digital certificate basics and wants to see exactly what it takes in practice to extend a private network by deploying a secure VPN. This tutorial presents code examples that will require novice- to intermediate-level system administration skills to reproduce, but anyone should be able to follow along with the discussion.

The tutorial implements a certificate-based security infrastructure using OpenSSL and uses this to secure both OpenVPN client and server endpoints. We will highlight two great new features to appear in OpenVPN-2.0 (now in beta) that will make it a good choice for any VPN--single-instance server mode and certificate revocation list support.

Deploying a VPN and Public Key Infrastructure

In part one of this series, we covered VPN and PKI at a conceptual level. We discussed the benefits that VPN technology offers to a business network and touched on three different techniques or protocols that can actually implement a VPN tunnel. These were PPTP, L2TP/IPSec, and the relative newcomer, OpenVPN. An advantage of OpenVPN is that it encapsulates network traffic inside of UDP or TCP packets, which improves the odds of it working when deploying a VPN across unknown third-party network equipment and the Internet as a whole.

Related Reading

Network Security with OpenSSL
Cryptography for Secure Communications
By John Viega, Matt Messier, Pravir Chandra

The previous article also talked about PKI and loosely defined the term as a system for issuing, publishing, and revoking digital certificates. These digital certificates are simple data structures containing, at the minimum, a subject's name, his public key, and the name of an issuer who has verified the subject's identity. When the issuer digitally signs the certificate and attaches the signature, the data structure becomes a digital certificate. The public key inside of the certificate can encrypt any message, producing a message decipherable only by the named subject in the certificate using the closely guarded private key.

For our step-by-step description of establishing connections across a VPN tunnel, secured with PKI, we will focus on two separate software packages, OpenVPN-2.0 (beta 8) and OpenSSL 0.9.7d. This version of OpenSSL was the latest stable version of the package at the time of writing. The OpenVPN beta version includes a couple of new features that really make it quite acceptable for a business VPN, namely, Certificate Revocation List (CRL) support and single-instance server mode. We'll use a generic GNU/Linux system to host both the PKI and VPN server endpoints. Our sample client configuration will be platform-neutral, meaning that the same client configuration should work on any supported OS, including Linux and the BSDs, Solaris, Mac, and Windows. Setup and operation for both OpenSSL and OpenVPN is similar on any supported platform.

First, we will configure OpenSSL to act as our root Certificate Authority (CA) by creating a self-signed certificate that will sit at the top of our trust hierarchy. Then, we will create certificate requests for our clients and actually issue certificates. Next, we will use OpenSSL's built-in test framework to make sure everything works smoothly before we complicate things by throwing a VPN into the mix. After running the OpenSSL test framework, we will configure both the OpenVPN server and client endpoints. Finally, we will demonstrate a CRL by revoking a user certificate, generating a CRL containing the revoked certificate, and effectively terminating the user's access to our VPN.

OpenSSL

OpenSSL is primarily a library of cryptographic functions that provides an extensive crypto API to programmers. However, it also includes a shell tool that exposes that API to users and batch scripts. Start the shell by typing openssl at the command line. From there, you can type commands at the OpenSSL> prompt.

[admin@tamarack admin]$ openssl
OpenSSL> version
OpenSSL 0.9.7d 17 Mar 2004
OpenSSL> 

You can also issue OpenSSL commands in batch mode. In batch mode, each OpenSSL command executes separately. Shell scripts usually use this approach; we'll do the same in this tutorial:

[admin@tamarack admin]$ openssl version
OpenSSL 0.9.7d 17 Mar 2004
[admin@tamarack admin]$ 

Of the many commands provided with the OpenSSL shell, this tutorial will only cover five:

  • ca: Certificate Authority management
  • req: Certificate request management
  • verify: Certificate verification
  • s_server: Secure server test mode
  • s_client: Secure client test mode

The OpenSSL Configuration File

When installing an OpenSSL Certificate Authority, we need to provide a master configuration file. This file contains default parameters for all OpenSSL commands. Compiling the library hard-codes its default location; its name is openssl.cnf. To find the default location of this file, use the version command with the -d option:

[admin@tamarack admin]$ openssl version -d
OPENSSLDIR: "/home/admin/install"
[admin@tamarack admin]$ 

Once you know where to look, edit this file with a text editor. The OpenSSL distribution includes a heavily commented example configuration file, but it's more complex than the simplified version we will work with in this tutorial. Hopefully, by paring the configuration down to a minimum, we will simplify our deployment without sacrificing security. Specifically, our configuration file removes many of the certificate extension definitions that appear in the prepackaged OpenSSL configuration.

It's probably a good time to mention these extensions. Part one of this series listed the minimum amount of information that must appear in a digital certificate: a subject name, the subject's public key, and the name of an issuer. Certificates that limit themselves to this minimum amount of information and conform to the X.509 encoding format are X.509v1 (version 1) certificates. Presently, the current standard specifies additional information that can appear in the certificate to increase security and aid applications that work with them. Most certificates used with Internet-enabled applications currently conform to the X.509v3 (version 3) specification and include some extensions. OpenSSL can produce either v1 or v3 certificates depending on the configuration file settings.

In this tutorial, we will configure OpenSSL to produce v3 certificates and include the basicConstraints extension to limit how people can use the certificates that we issue, as this is the recommended configuration. Here is the configuration file that we will use:

# openssl.cnf
#
# OpenSSL example configuration file.  
#
# This configuration file has been derived from the original
# example file included with the OpenSSL distribution.  It
# has been edited mostly to eliminate extensions in order to
# simplify it for the purpose of an online tutorial.  It has
# also been reformatted to limit the maximum line length to
# 60 characters for online publication.

############################################################
# This section will configure the ca (Certificate Authority)
# command.  We will use the ca command to sign user
# certificates and periodically generate CRLs.  
############################################################

[ ca ]
default_ca      = CA_default      # The default ca section

[ CA_default ]

dir             = /home/admin/CA-DB  # Top
crl_dir         = $dir/crl        # The crl location
database        = $dir/index.txt  # Database index file
new_certs_dir   = $dir/newcerts   # Location for new certs
certificate     = $dir/cacert.pem # The CA certificate
serial          = $dir/serial     # The next serial number
crl             = $dir/crl.pem    # The current CRL

# All DNs need to be unique.  This is the default behavior
# but due to an OpenSSL library bug in the 0.9.7d release,
# if we don't supply this redundant definition here we will
# see a cryptic message when signing certificates.
unique_subject  = yes

# The CA private key
private_key     = $dir/private/cakey.pem 

# Private random number file
RANDFILE        = $dir/private/.rand    

# Issued certificates will be valid for 1 year
default_days    = 365
default_crl_days= 30    

# Hashing function
default_md      = md5

# This assignment causes the extensions defined in the
# 'user_extensions' section to be included in any
# certificates that are signed using the ca command.

x509_extensions = user_extensions

# This sections describes the policy that will be enforced
# on a request to be signed, the subject organization name
# must match that in the CA certificate.  The request may
# contain an optional organizational unit name. The common
# name is assigned the policy format 'supplied' which means
# it must be present in the certificate request.
 
policy          = policy_any

[ policy_any ]

organizationName        = match
organizationalUnitName  = optional
commonName              = supplied

############################################################
# This section configures the req (certificate request)
# command.
############################################################

[ req ]

# The default key length and the filename that will contain
# a private key.  The public key will be contained in the
# certificate request.

default_bits            = 1024
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name

# The makeup of our subject name
[ req_distinguished_name ]

organizationName                = Organization Name (eg, company)
organizationName_default        = Inyo Technical Services

organizationalUnitName          = Organizational Unit (eg, west)

commonName                      = Common Name (eg, YOUR name)
commonName_max                  = 64

# This assignment mimics that in the ca section but causes
# the following extensions to be included in a certificate
# request.  In our case these extensions will only be
# included when we self-sign a certificate using 'req
# -new -x509'.

x509_extensions = CA_extensions

############################################################
# Extensions that will be added to certificates that are
# issued.  The 'user_extensions' sections contains 
# definitions that will be included in certificates that are
# signed by this CA.  The CA_extensions section contains
# extensions that will be included when we create a 
# self-signed certificate using the req command.
############################################################

[ user_extensions ]

# CA:FALSE will not permit this certificate to sign other
# certificates.
basicConstraints        = CA:FALSE

[ CA_extensions ]

# CA:TRUE will allow this certificate to sign others.
basicConstraints        = CA:TRUE

There are quite a few things to note about this file. First, note that comment blocks divide it into logical sections. In this sample, those sections are [ ca ], the configuration for the ca (Certificate Authority) command; [ req ], the section containing items to include in a certificate request with the req command; and finally, a section defining some extensions. We only include one extension and assign it two different values depending on the certificate that we are creating.

Our self-signed CA certificate will include the extension basicConstraints = CA:TRUE. This allows a Certificate Authority to use the certificate to sign other certificates. When we issue certificates to users, we will use the extension basicConstraints = CA:FALSE, denying users the ability to create subordinate certificates and thereby extend the chain of trust beyond our control.

The start of the [ ca ] section defines the directory hierarchy. This lets the OpenSSL library know where to find important files, and the definitions here should be clear. The assignment x509_extensions = user_extensions adds the extensions defined in the [ user_extensions ] section to any certificates signed by this CA. As explained before, the only extension we will include is basicConstraints, which was explained previously. Next come the definitions of the certificate request subject's name-matching policy and Distinguished Name structure.

The [ policy ] section defines the Distinguished Name components to allow in certificate requests. To understand this, we need to describe the encoding of subject names in X.509 certificates.

X.509 certificates encode subject names in a structure called a Distinguished Name (DN)--a sequence of name components called Relative Distinguished Names (RDNs). This naming structure comes from a complex specification for methods and syntaxes defining communication between computer programs as seen in RFC 1274, which gives the attribute definitions for the DN components that we will use in our certificates. The [ policy ] section specifies which RDNs or DN components must appear in a certificate request and which of these components must match the subject DN in the CA certificate prior to signing. Here, we have configured our CA to encode a subject's DN as follows:

  • The subject name must contain an organizationName part that matches our CA certificate exactly--match.
  • The subject name may contain an optional and arbitrary organizationalUnitName--optional.
  • The subject name must contain an arbitrary commonName component--supplied.

In our application, we will try to be consistent and issue user certificates with a commonName component that matches the user's login ID, but OpenSSL will not enforce this.

The next section, labeled [ req ], contains default configuration values for the req command. We will use this command to create certificate requests. The default_bits and default_keyfile definitions set the length of the private key and its location in the file system. More interesting here is the [ req_distinguished_name ] section, which defines default values for the RDN components that will make up our subject's Distinguished Name. Here we define the prompts that will appear at the terminal when we execute the req command. We assign a default value to our organizationName: Inyo Technical Services. Finally, the assignment x509_extensions = CA_extensions includes the extension defined in the [ CA_extensions ] section in a certificate request.

This extension assignment is similar to that in the [ ca ] section. The difference here is that these extensions will appear only in certificate requests, while extensions in the [ user_extensions ] section will appear in a certificate signed by our CA. By default, if an extension is present in a certificate request but does not appear in the [ user_extensions ] section, then the extension will not be present in the issued certificate. The extension basicConstraints = CA:TRUE will only appear in the certificate when we use the req command with the -x509 option to create a self-signed root certificate.

Pages: 1, 2, 3

Next Pagearrow