OpenVPN with Dual CA
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
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
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!