External public key infrastructure (PKI)

Purpose of external PKI

The Access Server External PKI (Public Key Infrastructure) feature allows operation of the Access Server with third-party tools for X509 PKI management, instead of using the built-in certificate management capabilities. When configured for external PKI usage, the Access Server will not manage client certificates directly; instead, the customer's third-party PKI software will be used to generate and distribute client certificate/key pairs to client machines, and a server certificate/key pair to the OpenVPN server.

When managing an Access Server setup that is configured for external PKI usage, distribution of the client must be made over two channels rather than one:

  1. Connection profile - distribution of the OpenVPN Connect client and bundled server-locked profile. These would contain instructions on how to connect to the server, and the software to make a connection. This can be done via normal means, either via the client web UI, or by generating and distributing the client installer via the command line tools and installing it on the client machines. Please note to use the instructions to create server-locked profiles/installers only when using External PKI mode.
  2. Certificate/key - while the standard Access Server (without External PKI enabled) transparently bundles the client certificate/key using the connection profiles themselves, External PKI mode separates this function. Generation of client certificates/keys would be done using a third-party tool for management of the External PKI solution, and installation on client machines would be done using the host OS certificate/key store (iOS, Mac OS X, or Android Keychain, Windows certificate store, or Linux OpenSC).

When operating in External PKI mode, the Access Server only supports server-locked profiles, not user-locked profiles. On the client, the server-locked profile can only be used to make a VPN tunnel connection if a suitable client certificate/key pair has already been installed into the host OS Keychain or certificate/key store. Some hardware devices or tokens contain a certificate inside that is registered with the certificate store with additional software when the token device/card is plugged in.

The Access Server Connect client does not require direct access to the private key, as it is capable of performing RSA operations on the key via the CSP (cryptographic service provider) API provided by the host OS Keychain. This is a beneficial security feature, as it allows the private key to be placed on a cryptographic token or smartcard, which makes it physically impossible for any software running on the client machine (even at root/Administrator level) to directly read the key.

Due to the fact that the External PKI mode disables a lot of the internal certificate management functions of the Access Server itself, and places this in the hands of the system administrator setting up this solution, support on this type of solution is limited. There is after all a third-party product now involved and we have no control over that external system.

UI Considerations

Supporting External PKI profiles in the client UI is fairly straightforward, since an external PKI profile is very similar to a server-locked profile. Here is a sample profile as described by EnumProfiles (a command line function in Connect Client to enumerate profiles that are stored in the Connect Client):

{
  "access_allowed": true,
  "authority": false,
  "external_pki": true,
  "global": false,
  "host": "dfly.yonan.net:443",
  "id": "dfly_yonan_net_externalpki_p4133",
  "name": "dfly.yonan.net/ExternalPKI",
  "org": "Acme Terraforming",
  "owner": "jamesyonan",
  "remote_hosts": [
    "dfly.yonan.net"
  ],
  "type": [
    "dynamic"
  ]
}

There are, however, some notable differences between External PKI profiles and standard server-locked profiles:

  1. External PKI profiles can potentially be auto-login, however the EnumProfiles description of the profile will not show an auto-login attribute, because the auto-login vs. user-login determination is made by the external client certificate, not by the profile, and therefore is not known until connect time. The UI should try not to care whether or not a profile is auto-login, and just respond appropriately to password queries if and when they are made by the client backend.
  2. Server-locked profiles are stubs used to dynamically download a user-locked profile from the server via the XML-RPC web interface of the Access Server. External PKI profiles are already complete in the sense that they contain all the necessary instructions to start the VPN tunnel connection (no user-locked profile download from the server is required), except that the client certificate/key is omitted from the profile, and is accessed at connect time via the host OS certificate/key store.

Test Configuration

It is possible to use the certool script provided with the Access Server to generate a simple external PKI for testing purposes.

First, stop the Access Server:

service openvpnas stop

Configure the Access Server for External PKI usage by editing as.conf with a text editor like nano:

nano /usr/local/openvpn_as/etc/as.conf

Locate the line that starts with certs_db and comment it out (put a # sign in front of it):

# certificates database
#certs_db=sqlite:///~/db/certs.db

Press ctrl+x, then press y, and then press enter, to save and exit the file. No certificate database will be used while the Access Server is configured for External PKI usage. Instead we're relying completely on an external system to handle this. This external must be setup with the steps below or by using third-party tools for an external PKI. We're going to be describing a test configuration in this section, and a production configuration with external tools in the section below.

Initialize the external PKI files in the epki directory, including the CA cert/key:

cd /usr/local/openvpn_as/scripts
mkdir -p epki/root

First make a root cert for signing intermediate CAs:

./certool --dir epki/root --cn "EPKI Root Test" --type ca

Make the intermediate CA:

./certool --dir epki/root --type intermediate --serial 1 --cn "EPKI Intermediate" --name inter
cp epki/root/inter.crt epki/ca.crt
cp epki/root/inter.key epki/ca.key
cat epki/root/ca.crt epki/ca.crt >epki/cabundle.crt

Make a certificate/key pair for the OpenVPN server:

./certool --dir epki --type server --serial 1 --cn server

Make a tls_auth key for the OpenVPN server:

./certool --dir epki --tls_auth

Generate Diffie Hellman parameters for the OpenVPN server:

openssl dhparam -out epki/dh.pem 2048

Load the files we just generated into the Access Server config database:

./confdba -mk external_pki.ta_key --value_file epki/ta.key
./confdba -mk external_pki.ca_crt --value_file epki/cabundle.crt
./confdba -mk external_pki.server_crt --value_file epki/server.crt
./confdba -mk external_pki.server_key --value_file epki/server.key
./confdba -mk external_pki.dh_pem --value_file epki/dh.pem

Configure remote certificate usage to netscape ("ns"):

./confdba -mk external_pki.remote_cert_usage -v ns

Configure use of the X509 "role" attribute for declaration of auto-login permission:

./confdba -mk external_pki.autologin_x509_spec -v "role,,AUTOLOGIN"

Start the Access server service now:

service openvpnas start

Now we will generate a test client under the user etest. Depending on which authentication model you have configured in the Access Server, add a user/password for etest.

For example, if you are using PAM authentication:

useradd -s /sbin/nologin etest
passwd etest

Generate a test client cert/key pair for user etest. The key will be encrypted with a password that you will be prompted for. certool will generate the file epki/etest.p12 which contains the cert/key pair:

./certool --dir epki --type client --serial 2 --cn etest --cabundle epki/cabundle.crt --pkcs12 --prompt

If you would like to test auto-login support as well, generate an autologin cert/key pair for etest. The generated cert/key will be in the file epki/etestauto.p12:

./certool --dir epki --type client --serial 3 --cn etest --name etestauto --cabundle epki/cabundle.crt --pkcs12 --prompt role=AUTOLOGIN
./sacli --user etest --key prop_autologin --value true UserPropPut

Finally, generate a server-locked profile. The profile will be stored in client.ovpn:

./sacli --dest_dir . GetGeneric

This completes the server side setup. Now copy these three files to the client machine:

epki/etest.p12: The userlogin cert/key pair for user etest
epki/etestauto.p12: The autologin cert/key pair for user etest
client.ovpn: The server-locked profile for the Access Server

In a production setting, the client cert/key pairs (the .p12 files) would be distributed to clients via the foreign PKI solution in use, while the client.ovpn could be distributed in the same manner as existing server-locked profiles, such as:

  1. Transparently via the OpenVPN Connect Client.

  2. Using a client software push capability. For example, on Mac OS X, a client installer DMG can be generated which is pre-configured with the server-locked profile:

    ./sacli --itype dmg -o . GetGenericInstaller
    

On Mac OS X clients, start up the Keychain Access application. Go to File / Import Items and import one of the .p12 files you generated above. To decrypt the .p12 file, you will need to enter the password you used when you generated the file. On Windows clients, run Internet Explorer and go to Tools / Internet options. Click on the Content tab then the Certificates button. Click "Import" to import a .p12 file.

Now we are ready to import the server-locked profile and connect:

capi -f client.ovpn importprofile
capi -D -i <PROFILE_ID> -u etest -p <PASSWORD> Connect

Whether or not the profile is an auto-login profile will depend on whether you imported epki/etest.p12 or epki/etestauto.p12 into the system certificate store. If it is an auto-login profile, then the -u and -p parameters above can be omitted as an auto-login profile by its very nature does not use user name and password verification.

You may note that during the connection process, the system certificate store may raise a confirmation dialog box when OpenVPN uses the private key for an RSA sign operation. On some Windows systems, the confirmation dialog may start in the minimized state rather than popping up (the confirmation dialog comes from the system certificate store itself, so OpenVPN doesn't have any control over how it is rendered). You can click it to open it fully and approve it in order to continue the connection process.

Production Configuration

The production configuration assumes the use of a third-party tool for PKI management and certificate/key generation, and not the self-managed certificates and keys as shown in the test configuration section above.

First, stop the Access Server:

service openvpnas stop

Configure the Access Server for External PKI usage by editing as.conf with a text editor like nano:

nano /usr/local/openvpn_as/etc/as.conf

Locate the line that starts with certs_db and comment it out (put a # sign in front of it):

# certificates database
#certs_db=sqlite:///~/db/certs.db

Press ctrl+x, then press y, and then press enter, to save and exit the file. No certificate database will be used while the Access Server is configured for External PKI usage. Instead we're relying completely on an external system to handle this. This external must be setup with the steps below or by using third-party tools for an external PKI. We're going to be describing a production configuration with external tools here.

Make a tls_auth key for the OpenVPN server and load it into the Access Server configuration:

cd /usr/local/openvpn_as/scripts
mkdir epki
./certool --dir epki --tls_auth
./confdba -mk external_pki.ta_key --value_file epki/ta.key

Generate Diffie Hellman parameters for the OpenVPN server and load them into the Access Server configuration:

openssl dhparam -out epki/dh.pem 2048
./confdba -mk external_pki.dh_pem --value_file epki/dh.pem

Using the PKI management tool, generate a certificate/key pair for the OpenVPN server. We cannot show you how this is done with your chosen external PKI system, you have to refer to documentation for your chosen external PKI system to find out how to do that. Once you have the required files follow these next steps:

Then import the CA certificate, server certificate, and server private key (all specified in PEM format) into the Access Server:

./confdba -mk external_pki.ca_crt --value_file <CA_CERT_BUNDLE>
./confdba -mk external_pki.server_crt --value_file <SERVER_CERT_FILE>
./confdba -mk external_pki.server_key --value_file <SERVER_PRIVATE_KEY_FILE>

To avoid a particular type of man-in-the-middle attack where a client certificate could be used to impersonate the server, make sure to designate all certificates generated by your PKI management tool as being explicitly client or server. There are two ways to do this:

  1. Netscape certificate type (a netscape de-facto standard that is well-supported, but shunned by purists). Configure as follows:

    ./confdba -mk external_pki.remote_cert_usage -v ns
  2. X509 explicit/extended key usage based on RFC3280 TLS rules. Configure as follows:

    ./confdba -mk external_pki.remote_cert_usage -v eku

Client Support

When used in External PKI mode, the Connect Client supports the Mac Keychain or Windows certificate store as a source from which to fetch the client certificate.

When the user attempts to connect using the profile, the client backend will enumerate the user's host OS certificate store and automatically select the certificate/key pair that was issued by the OpenVPN Access Server that generated the profile. If more than one certificate/key pair is eligible, the certificate with the latest expiration date will be used.

Certificate naming conventions

Currently, the Access Server uses the following client certificate naming conventions:

  1. The Common Name of the certificate must match the user name of the connecting client.

  2. Autologin certificates, which don't require username/password authentication (only client certificate authentication), must be tagged in some way to indicate that they hold this right. In the above example, we set the X509 role attribute to AUTOLOGIN to specify an autologin right. Then we modify the access server configuration to indicate that autologin is enabled if the X509 "role" attribute contains the "AUTOLOGIN" substring:

    ./confdba -mk external_pki.autologin_x509_spec -v "role,,AUTOLOGIN"
    

    If external_pki.autologin_x509_spec is omitted, all autologin access is disabled.

    The external_pki.autologin_x509_spec string is formatted as follows:

    <X509 Attribute>,<optional flags>,<enabling substring in attribute value>
    

    The flags parameter is reserved for future use and is currently unimplemented.

    So, for example, if external_pki.autologin_x509_spec is set to "role,,AUTOLOGIN", as the confdba command above does, then the Access Server would only allow autologin connections from client certificates where the "role" X509 attribute is present and the substring "AUTOLOGIN" exists within the "role" value.

Advanced features

Split CA, i.e. using a separate CA chain for client and server certificates

By default, one CA chain is assumed for both client and server certificates. To use a separate chain for each, first enable split CA mode:

./confdba -mk external_pki.remote_cert_usage -v split

Next, replace the following line (from above):

./confdba -mk external_pki.ca_crt --value_file <CA_CERT_BUNDLE>

with:

./confdba -mk external_pki.server_ca_crt --value_file <SERVER_CA_CERT_BUNDLE>
./confdba -mk external_pki.client_ca_crt --value_file <CLIENT_CA_CERT_BUNDLE>

When using split CA mode, marking certificates as client or server becomes unnecessary. Therefore, settings for Netscape certificate type or X509 explicit/extended key usage based on RFC3280 TLS rules can be omitted.

Controlling CN/username requirement

By default, it is required that client logins use a username that matches the Common Name on the client certificate. This requirement may be dropped by disabling the external_pki.cn_username_requirement boolean key:

./sacli -k external_pki.cn_username_requirement -v false ConfigPut

Controlling which certificate store the client uses to fetch the client certificate

By default, the client will fetch certificates from the "user" store. This corresponds to the user's ~/Library/Keychains/login.keychain store on Mac, and the the "MY" store on Windows.

On Mac, the store can be selected on the server using the user properties key "cert_store". Set it to "user", "system", or "both" to explicitly control the store that clients use:

user: use ~/Library/Keychains/login.keychain
system: use /Library/Keychains/System.keychain
both: try system keychain, then fall back to user

For example, set the store to "both":

./sacli --user __DEFAULT__ --key cli_cert_store --value "both" UserPropPut