Cryptography and PKI are often difficult to understand and much more difficult to resolve issues with. There are primarily two utilities, OpenSSL and Wireshark, that can aid with peering into the cryptographic components of OpenVPN.
OpenSSL is the ubiquitous library for X.509 certificate PKI. OpenVPN has supported the use of X.509 certificates for TLS connections since before 2002. The OpenSSL command-line utilities allow certificate chain verification, outputting certificate details for inspection, build Diffie-Hellman parameters, and even substantiating an SSL/TLS server or client instance.
I have used the s_client
subcommand to fetch the full SSL certification chain for the Google website. All three certificates are listed: the GeoTrust CA root certificate, the Google Intermediate CA (they get to sign their own certificates), and the server certificate their intermediate CA issued. See the following code:
author@example:~-> openssl s_client -showcerts -connect openvpn.net:443
With this command, I manually copied each certificate block and saved them to individual files, GoogleSrv.crt
(certificate 0), GoogleCA.crt
(certificate 1), and GeoTrustCA.crt
(certificate 2).
A certificate block looks like the following:
-----BEGIN CERTIFICATE-----
MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
[snip]
NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
-----END CERTIFICATE-----
Wireshark was discussed previously, but this is where that utility will demonstrate its capability. In addition to the ability to decode and illustrate various (nearly all) protocol streams, given the private and public keys available to a VPN admin, it can decipher SSL and TLS encrypted streams, including OpenVPN streams.
To demonstrate the ability to decrypt a TLS session, we will use the OpenSSL s_server
command to create a generic HTTPS server. I have created a very simple web page that simply reads, This content is encrypted. I used the following command to create the server. Note that to start the daemon on port 443
, you need to use root or sudo
. To avoid escalating privileges, you can use a port 1024
, such as 4443
.
To begin, create a certificate/key pair:
author@example:~-> openssl req -x509 -newkey rsa:2048 -keyout
key.pem -out cert.pem -days 365 -nodes
Then, we start our server:
author@example:~-> sudo openssl s_server -key key.pem -cert
cert.pem -WWW -accept 443
The s_server
process will use the current working directory for its web root, so I placed our web content there as index.html
.
Tip
The preceding command used sudo
because it opened a listening port on a privileged port. All TCP/UDP ports numbered 1024
and lower are considered privileged, and they require root or administrator permissions to open.
Now, I will start Wireshark and set it to capture traffic on the loopback
interface. Because we are going to connect to the localhost
address (127.0.0.1
or ::1
), the traffic will use this interface. If we connect to the actual system IP address, then capture traffic on the real interface.
Now, open a web browser to the system. In my case, this is the local machine. The URL I will use https://localhost/index.html
, if you changed the port, add it to the URL such as https://localhost:4443/index.html
.
If all the steps mentioned earlier were performed correctly, you should have a browser window with a simple message and a Wireshark window with approximately 25 packets captured:
In the packet capture, you will see some protocol data that is indicative of what is happening. We will touch on the protocol exchanges later, but you can clearly see the TLS handshake and cipher exchange taking place:
The lines in the capture have a black background, indicating the transmission carried encrypted payload data. Next, we will take the certificate and the key we created earlier and import those into Wireshark. This will allow us to view the transaction.
Before we do that, we will examine packets 17 and 19. Both of these are labeled with the generic phrase Application Data
and contain our actual HTML. These packets are encrypted, and they examine them by clicking on them.
By going to Preferences | Protocols | SSL, Wireshark provides a way to import the TLS key we created earlier. On macOS X, the dialog resembles the following screenshot. You can specify the port here, but it is optional. In my case, I simply listed the IP 127.0.0.1
and the key file:
If we go back and inspect our packets now, we can see a new tab in the payload pane. The first is labeled Frame
, and the second is Decrypted SSL data
:
Click on the second tab for packet 19, and we can actually see the decrypted page content:
<html>
<head>
<title>
Hello!
</title>
</head>
<body>
<p>This content is encrypted.</p>
</body>
</html>
Note
The ability to decrypt the OpenVPN TLS streams is significant enough that the Wireshark wiki itself has a page specifically demonstrating this capability: https://wiki.wireshark.org/OpenVPN.