How do I connect to an OpenVPN server and dump the certificate chain presented when connecting?

Solution 1:

I happen to be running an OpenVPN server in TCP mode, and I can confirm that you cannot use openssl s_client to get the certificate:

[me@risby 17]$ openssl s_client -connect openvpn.example.com:1194
CONNECTED(00000003)
140413456672632:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 205 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---

I can only presume that although OpenVPN uses SSL, it does so in a different way from a standard SSL/TLS connection. So I don't think this is the way to go.

I'd hoped to find an openvpn client invocation that would dump the certficates, but thus far have not. I'm sorry not to have more for you, but I thought it worth writing an answer that might prevent you from wasting time.

Solution 2:

Building on the mostly complete solution in this thread by Peter Šurda (see there for some explanation regarding the used openvpn options), this should do the work to get the server certificates.

I assume you have a working OVPN configuration file in config.ovpn and that you are authenticating the client with a username and a password (this can be omitted, depending on your setup).

Prepare working directory:

WD=/tmp/openvpn-cert
mkdir $WD

Prepare the script to extract the server certificates and some fake credentials file (we don't need to get past successful authentication):

echo -e '#!'"/bin/sh\ncp \$peer_cert $WD/server-cert-\$1.pem" >$WD/extract-cert.sh
chmod +x $WD/extract-cert.sh

echo -e "fakeusername\nfakepassword" >$WD/creds.dat

Try to connect with openvpn:

openvpn --config config.ovpn --auth-user-pass $WD/creds.dat --tls-export-cert $WD \
    --script-security 2 --tls-verify $WD/extract-cert.sh --log /dev/null

Now you should have the server certificate available in $WD/server-cert-0.pem and can operate on it, e.g. get the notBefore and notAfter dates:

openssl x509 -in $WD/server-cert-0.pem -noout -dates

The other certificates in the chain will be available in $WD/server-cert-1.pem etc. The number comes from the first argument passed to extract-cert.sh, which is the certificate depth. See the --tls-verify documentation in the Script Hooks section of the man page.

Solution 3:

I was facing the same problem and it can be resolved by using openvpn with particular arguments. The important ones are --tls-verify and --tls-export-cert. --tls-verify needs to be followed by filename of a script you want to execute. The environment variable peer_cert will contain a location of the dumped certificate chain. The --tls-export-cert needs to be followed by a directory name where the certificate will be dumped. The certificate is auto-deleted once the tls-verify script finishes.

The only problem I found was that it requires you to already have the CA certificate. If you don't have it, the script won't execute and I haven't found a way to work around it.

Example in use:

openvpn --remote remote.host.to.check 1194 --dev tun --proto udp --ca tmp/openvpnca.cert --client --auth-user-pass tmp/noauth.txt --remote-cert-tls server --tls-verify tmp/tls-verify.sh --script-security 2 --tls-export-cert tmp/tlsverifies

tmp/noauth.txt is a dummy file with two lines containing a fake username/password. tmp/tlsverifies is a directory where the chain file will be dumped. tmp/tls-verify.sh is a shell script that processes the peer_cert environment variable