This tutorial will look at how to configure an OpenVPN server using a certificate issued by a recognized certificate authority.

In this arrangement, an internal CA will be used by the server to verify clients, while the clients, use an external CA to verify the server. Because this server has chain of trust leading to a trusted root, Android will not show an annoying 'your internet access may be monitored message'. Although informing users of potentially rogue certificates is important, in this case, it hinders security by crying wolf.  

Part 1 - Configure internal CA

Let's begin by setting up the internal CA. For this I will use the graphical XCA utility. We begin by encrypting the CA database. If you're already familiar with setting up an internal CA, skip part 1

Then we generate a the key for the certificate authority

Next comes creating the self signed certificate. Annoyingly, XCA doesn't randomize the serial numbers for the certificate, so we have to manually run "openssl rand -hex 16" to get a random serial

Next comes generating a certificate signining request. We do this on the clients machine, and send only the CSR file to the CA

×
-
+
Konsole

openssl req -new -sha256 -nodes \
-newkey rsa:4096 \
-keyout /etc/ssl/client_key.pem \
-subj /CN=rohan@example.com/ \
-out /etc/ssl/client_csr.pem


Next comes issuing the signed certificate for the client. Import the CSR, and right click sign.

The entity certificate can be sent to the client machine. The CA self-signed root certificate needs to be sent to the server, as it's how clients get verified

Next, let's configure the server. The first and most important thing is to configure it so that it clients are validated using the self signed CA created earlier.

ca /etc/openvpn/server/ROHAN_DEMO_CA_ROOT.pem

Part 2: Server configuration

Next, the server needs to generate a certificate signing request, send the request to a CA, and order to obtain a certificate. The main difference here is that server uses a commercial CA (such as Comodo or LetsEncrypt) to obtain its certificatr.

Once we've got the signed certificate from the CA, the server is configured to use it

cert /etc/openvpn/server/vpn-server-comodo-cert.pem
key /etc/openvpn/server/vpn-server-comodo-key.pem

However, for clients to be connect, the client needs to be satisfied the server is trusted. This means the server needs to distribute its issuer certificates (Comodo CA) to the clients. While the clients use these CA certificates to verify the server, the server does not use these certificate to verify the clients.

First, let's download the intermediate certificates and place them in comodo-ca.pem.

curl -fSsL https://support.comodo.com/index.php?/Knowledgebase/Article/GetAttachment/979/1056458 > comodo-ca.pem

curl -fSsL http://crt.comodoca.com/AddTrustExternalCARoot.crt | openssl x509 -inform der >> comodo-ca.pem

Now we configure the server to append these certificates so that the clients are sent a full certificate chain. This is done with the extra-certs option

extra-certs /etc/openvpn/server/comodo-ca.pem

Let's view this file

We can see that it's still one level below the root; clients require 'AddTrust External CA root in order to complete the chain and perform full verification of the server.

Part 3 Configuring the client

This is my (sanitized) template for clients
Pay special attention to the verify-x509-name setting, as we don't want to trust any Comodo issued certificate; only ones where the CN corresponds to our validated domainname

cat > client.ovpn << EOF
client
dev tun
remote [snip] 53
proto udp
pkcs12 vpn-client.p12
auth SHA512
cipher AES-256-CBC
tls-version-min 1.2
remote-cert-eku "TLS Web Server Authentication"
verify-x509-name "OU=Domain Control Validated, OU=PositiveSSL, CN=[snip]"
tls-client
key-direction 1
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
[snip]
-----END OpenVPN Static key V1-----
</tls-auth>
EOF

Next, we append the CA to it

{
    echo "<ca>"
    curl -fSsL https://support.comodo.com/index.php?/Knowledgebase/Article/GetAttachment/979/1056458
    echo
    curl -fSsL http://crt.comodoca.com/AddTrustExternalCARoot.crt | openssl x509 -inform der 
    echo "</ca>"
} >> client.ovpn

Now let's run client ovpn with -verb 3

×
-
+
Konsole

Mon Oct 29 18:06:53 2018 VERIFY OK: depth=3, C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root
Mon Oct 29 18:06:53 2018 VERIFY OK: depth=2, C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Certification Authority
Mon Oct 29 18:06:53 2018 VERIFY OK: depth=1, C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Domain Validation Secure Server CA
Mon Oct 29 18:06:53 2018 Validating certificate extended key usage
Mon Oct 29 18:06:53 2018 ++ Certificate has EKU (str) TLS Web Server Authentication, expects TLS Web Server Authentication
Mon Oct 29 18:06:53 2018 VERIFY EKU OK
Mon Oct 29 18:06:53 2018 VERIFY X509NAME OK: OU=Domain Control Validated, OU=PositiveSSL, CN=[snip]
Mon Oct 29 18:06:53 2018 VERIFY OK: depth=0, OU=Domain Control Validated, OU=PositiveSSL, CN=[snip]


It works!