This tutorial will be showing you how to set up certificate authentication in OpenConnect VPN server (ocserv) on Debian/Ubuntu/CentOS/RHEL. OpenConnect (ocserv) is an open-source implementation of the Cisco AnyConnect VPN protocol.

In a previous article, I explained the steps to set up OpenConnect VPN server with Let’s Encrypt TLS server certificate. Let’s Encrypt does not issue client certificate, so in that article, we used password authentication. Entering username and password every time can be a hassle, especially if the client software, such as the Cisco AnyConnect app on iOS, doesn’t offer an option to remember password. Many OpenConnect client software can import user certificate, which will free the user from entering username and password. Certificate authentication is also more secure than password authentication.

Prerequisites

To follow this tutorial, it’s assumed that you have already set up an OpenConnect VPN server with Let’s Encrypt TLS server certificate. If not, please follow one of the following tutorials.

We will set up our own CA (Certificate Authority) to sign client certificate. The ocserv daemon should continue using the TLS server certificate issued by Let’s Encrypt, so client software won’t display security warning.

Setting up Your Own CA (Certificate Authority)

We want to use certificate authentication, but Let’s Encrypt does not issue client certificate, so we need to create our own CA. You can openssl to do the job, but ocserv recommends GnuTLS, so I will show you how to use GnuTLS.

Install gnutls-bin package on Debian/Ubuntu server.

sudo apt install gnutls-bin

Install gnutls-utils package on CentOS/RHEL.

sudo dnf install gnutls-utils

Create a sub-directory in /etc/ocserv/ to hold private keys and certificates.

sudo mkdir /etc/ocserv/ssl/

Change your working directory.

cd /etc/ocserv/ssl/

Generate a private key for the CA with the certtool command, which is provided by the gnutls-bin or gnutls-utils package. By default, it generates a 3072 bit RSA key, which is sufficient.

sudo certtool --generate-privkey --outfile ca-privkey.pem

Before generating the CA certificate, let’s create the CA certificate template file. The template file format can be found in certtool manual (man certtool).

sudo nano ca-cert.cfg

Add the following lines to the file. Replace placeholders with the appropriate values.

# X.509 Certificate options

# The organization of the subject.
organization = "vpn.example.com"

# The common name of the certificate owner.
cn = "Example CA"

# The serial number of the certificate.
serial = 001

# In how many days, counting from today, this certificate will expire. Use -1 if there is no expiration date.
expiration_days = -1

# Whether this is a CA certificate or not
ca

# Whether this certificate will be used to sign data
signing_key

# Whether this key will be used to sign other certificates.
cert_signing_key

# Whether this key will be used to sign CRLs.
crl_signing_key

Save and close the file. Now generate the CA certificate using configurations from the template file.

sudo certtool --generate-self-signed --load-privkey ca-privkey.pem --template ca-cert.cfg --outfile ca-cert.pem

Now we have a CA certificate file (ca-cert.pem).

Generating Client Certificate

Now run the following command to generate client private key.

sudo certtool --generate-privkey --outfile client-privkey.pem

Create the client certificate template file.

sudo nano client-cert.cfg

Add the following lines into the file. The uid must be a username in the /etc/ocserv/ocpasswd file.

# X.509 Certificate options
# The organization of the subject.
organization = "vpn.example.com"

# The common name of the certificate owner.
cn = "John Doe"

# A user id of the certificate owner.
uid = "username"

# In how many days, counting from today, this certificate will expire. Use -1 if there is no expiration date.
expiration_days = 3650

# Whether this certificate will be used for a TLS server
tls_www_client

# Whether this certificate will be used to sign data
signing_key

# Whether this certificate will be used to encrypt data (needed
# in TLS RSA ciphersuites). Note that it is preferred to use different
# keys for encryption and signing.
encryption_key

Save and close the file. Then run the following command to generate client certificate, which will be signed by the CA private key.

sudo certtool --generate-certificate --load-privkey client-privkey.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-privkey.pem --template client-cert.cfg --outfile client-cert.pem

Combine the client private key and certificate in a PKCS #12 file that is protected by a PIN.

sudo certtool --to-p12 --load-privkey client-privkey.pem --load-certificate client-cert.pem --pkcs-cipher aes-256 --outfile client.p12 --outder

Now we have the client private key and certificate combined into one file client.p12.

Note that the Ciso AnyConnect app on iOS doesn’t support AES-256 cipher, so if the user is using iOS device, then you can use the 3des-pkcs12cipher.

sudo certtool --to-p12 --load-privkey client-privkey.pem --load-certificate client-cert.pem --pkcs-cipher 3des-pkcs12 --outfile ios-client.p12 --outder

The client private key and certificate combined into one file ios-client.p12.

Certificate Signing Request

In order to keep end users’ private keys secret, users can generate certificate signing request (CSR) with their own private keys, then send certificate requests to admin, who then issues client certificates to users. First, they have to generate private key and the client certificate template using the commands mentioned above. Then generate a CSR with the following command. The request.pem file is signed by user’s private key.

certtool --generate-request --load-privkey client-privkey.pem --template client-cert.cfg --outfile request.pem

Next, the user sends the request.pem and client-cert.cfg file to admin, who runs the following command to generate client certificate.

sudo certtool --generate-certificate --load-ca-certificate ca-cert.pem --load-ca-privkey ca-privkey.pem --load-request request.pem --template client-cert.cfg --outfile client-cert.pem

After that, the admin sends client-cert.pem certificate file to the user.

Enabling Certificate Authentication in ocserv Daemon

Edit ocserv configuration file.

sudo nano /etc/ocserv/ocserv.conf

In the previous tutorial, we added the following line to enable password authentication.

auth = "plain[passwd=/etc/ocserv/ocpasswd]"

To enable certificate authentication, uncomment the following line.

auth = "certificate"

If the above two lines are both uncommented, that means the user must pass both password authentication and certificate authentication. So if certificate authentication is enough to prove identity, then comment out the first line.

If you allow users to chose either certificate authentication or password authentication, then you should have the following lines instead.

enable-auth = "plain[passwd=/etc/ocserv/ocpasswd]"
auth = "certificate"

Now find the ca-cert parameter. On Debian/Ubuntu, it’s set to

ca-cert = /etc/ssl/certs/ssl-cert-snakeoil.pem

On CentOS 8/RHEL 8, it’s set to

ca-cert = /etc/pki/ocserv/cacerts/ca.crt

We need to use our own CA certificate to verify client certificate, so change this line to

ca-cert = /etc/ocserv/ssl/ca-cert.pem

Next, find the following line.

cert-user-oid = 0.9.2342.19200300.100.1.1

You don’t need to change it. I just want to tell you that 0.9.2342.19200300.100.1.1 represents the UID filed in client certificate. The above line tells ocserv daemon to find the username from the UID field of client certificate. If the client certificate is successfully verified by the CA certificate and ocserv daemon can find a matching username in /etc/ocserv/ocpasswd file, then the client can login.

Save and close the file. Then restart ocserv.

sudo systemctl restart ocserv

Using Certificate Authentication on Debian/Ubuntu/CentOS/RHEL Desktop

Use the scp command to download the client.p12 file to your Debian/Ubuntu/CentOS/RHEL desktop.

scp [email protected]:/etc/ocserv/ssl/client.p12 ~

Then install the openconnect client software.

Debian/Ubuntu:

sudo apt install openconnect

CentOS/RHEL:

sudo dnf install epel-release
sudo dnf install openconnect

To use certificate authentication, run

sudo openconnect -b vpn.example.com -c client.p12

You will be asked to unlock client private key with the passphrase you set ealier in this tutorial.

If the passphrase is entered correctly, you should now be connected to VPN server.

Using Certificate Authentication on Windows and MacOS Desktop

Download OpenConnect GUI client for Window or MacOS from OpenConnect GUI Github Page. Then create a new VPN connection profile and import the PKCS #12 file to user certificate field. Click the Save button. You will need to enter the PIN to unlock the private key. Once imported, you don’t have to enter username and password anymore.

Using Certificate Authentication on iOS Device

iOS users can use the Cisco AnyConnect app. To import client certificate in AnyConnect app, you can first send the PKCS #12 file to your email address in an attachment. Then open the mail app on iOS. Tap the attachment a few seconds and share it with AnyConnect. Then enter the PIN to import the file.

Once it’s imported, edit your VPN connection in AnyConnect. Go to Advanced -> Certificate and select the client certificate. Save your settings.

Now you don’t have to enter username and password anymore on your iOS device. The Cisco AnyConnect app doesn’t remember username and password, so in password authentication mode, VPN connection will drop when the phone is not in use. In certificate authentication mode, the app will automatically reconnect to VPN server if connection is dropped.

I hope this tutorial helped you set up certificate authentication in OpenConnect VPN server. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial

[Total: 6 Average: 4.5]