Secure your data channel with stunnel
Confidential
Transmitting confidential data over an insecure connection is not a good idea and should always be avoided, but what do you do if a service does not offer a secure communication channel, and no VPN is available?
Everyone will be familiar with the following situation: You are sitting comfortably in a cafe or hotel, registered on the local WiFi network, and happily browsing the Internet. However, you might not want other users of the same wireless network to be able to track your Internet usage behavior. Worse still, you come across a service that requires you to enter sensitive data, such as login credentials, but does not provide data protection through a secure TLS connection. Unfortunately, such cases can still be found in 2020. So what now?
Most Linux distributions offer the stunnel package, a TLS wrapper that lets you build a tunnel between two endpoints. The tool can operate in both client and server modes.
Preparing the Tunnel
After you have downloaded and installed the stunnel package from the distribution repository [1], you need to install the /etc/stunnel/stunnel.conf
configuration file. If this is not available, sample configurations can usually be found in the documentation directory, /usr/share/doc/stunnel*/
. The example in Listing 1 shows a very simple configuration that uses stunnel as a plain vanilla TLS client.
Listing 1
Stunnel as a TLS Client
; global settings sslVersion = TLSv1.2 chroot = /var/run/stunnel setuid = nobody setgid = nobody pid = /stunnel.pid socket = l:TCP_NODELAY=1 socket = r:TCP_NODELAY=1 CAfile = /etc/pki/tls/certs/roots.pem verifyChain = yes [gmail-smtp] client = yes accept = 127.0.0.1:1234 connect = smtp.gmail.com:465 checkHost = smtp.gmail.com OCSPaia = yes
This example creates a TLS tunnel between the local computer and the Google SMTP server on port 465. On accessing the tunnel, the server's certificate chain is verified with CA certificates from the /etc/pki/tls/certs/roots.pem
file. When a connection to local port 1234 on the local computer is opened, data enters the tunnel and comes out on the Google SMTP server at the other end (Listing 2).
Listing 2
Connection to a Local Port
telnet 127.0.0.1 1234 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. 220 smtp.gmail.com ESMTP x20sm3297437wrg.52 - gsmtp HELP 214 2.0.0 https://www.google.com/search?btnI=RFC+5321 x20sm3297437wrg.52 - gsmtp QUIT 221 2.0.0 closing connection x20sm3297437wrg.52 - gsmtp Connection closed by foreign host.
Things become interesting, of course, if you need to access a service that does not offer a secure connection of its own. In this case, stunnel can be operated in server mode on a secure network (e.g., on an enterprise computer to establish a tunnel endpoint there). To illustrate this scenario, the next example simply opens a connection to Google's SMTP server via port 25. Communication on this port is usually in plain text. Two stunnel instances are now required. The first instance again runs as a client on the laptop (Listing 3), and the second instance on a remote computer (Listing 4) within a secure network.
Listing 3
Client Configuration in stunnel.conf
; global settings sslVersion = TLSv1.2 chroot = /var/run/stunnel setuid = nobody setgid = nobody pid = /stunnel.pid socket = l:TCP_NODELAY=1 socket = r:TCP_NODELAY=1 CAfile = /etc/stunnel/stunnel.crt verifyChain = yes [gmail-smtp] client = yes accept = 127.0.0.1:1234 connect = server.example.com:1234
Listing 4
Server Configuration in stunnel.conf
; global settings sslVersion = TLSv1.2 chroot = /var/run/stunnel setuid = nobody setgid = nobody pid = /stunnel.pid socket = l:TCP_NODELAY=1 socket = r:TCP_NODELAY=1 cert = /etc/stunnel/stunnel.pem CAfile = /etc/pki/tls/certs/roots.pem verifyChain = yes [gmail-smtp-server] client = no accept = 1234 connect = smtp.gmail.com:25
If you now establish a connection to local port 1234 on the client, a tunnel to the stunnel server instance is set to port 1234 on the server.example.com host. Within this tunnel, communication is secured with TLS v1.2. This host, then, establishes a connection to the target system – in this case smtp.gmail.com – over insecure port 25. In this example, it is simply a matter of protecting the client's communication on the local network (Listing 5).
Listing 5
Client Communication
telnet 127.0.0.1 1234 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. 220 smtp.gmail.com ESMTP z19sm6017985wmi.7 - gsmtp HELP 214 2.0.0 https://www.google.com/search? btnI&q=RFC+5321 z19sm6017985wmi.7 - gsmtp KE:
stunnel Certificates
The configuration refers to an X.509 certificate in several places. On the server, you can integrate the certificate and verify the server certificate by typing
cert = /etc/stunnel/stunnel.pem CAfile = /etc/stunnel/stunnel.crt
on the client. The certificate is used to encrypt the communication and to authenticate the stunnel server instance. For test purposes, you can create a certificate with the commands in Listing 6. In this example, the private key and the certificate are stored together in /etc/stunnel/stunnel.pem
. Therefore, you need to adjust the permissions for this file restrictively.
Listing 6
Creating a Certificate
openssl genrsa -out /etc/stunnel/stunnel.key 4096 openssl req -new -x509 -key /etc/stunnel/stunnel.key -out /etc/stunnel/stunnel.crt -days 365 cat /etc/stunnel/stunnel.key /etc/stunnel/stunnel.crt > /etc/stunnel/stunnel.pem chmod 440 /etc/stunnel/stunnel.pem
In production environments, of course, a certificate signed by a certificate authority (CA) should be used. To generate a corresponding certificate signing request (CSR), use the command:
openssl req -new -sha256 -key /etc/stunnel/stunnel.key -out /etc/stunnel/stunnel.csr
Once you have received the signed certificate back from the CA, you integrate it on the server as usual with the cert
statement. On the server, use CAfile
to specify the certificate from the CA to verify the server's certificate chain correctly.
Also interesting to note is that stunnel v5.09 allows you to authenticate a client with a preshared key (PSK), which means you can use access control to determine who is allowed to use the tunnel. On the server, add the following two statements to the tunnel configuration:
ciphers = PSK PSKsecrets = /etc/stunnel/psk.txt
On the client, define the file in which the authentication keys are stored:
PSKsecrets = /etc/stunnel/psk-client1.txt
On the server, the file /etc/stunnel/psk.txt
must contain all keys of all clients; an example can be seen in Listing 7.
Listing 7
Example /etc/stunnel/psk.txt
client1:Wf44zFw33FeMxCqobcA13lb28IgizxyZJOUoUsZGlkk client2:q0eL78zFrbnESW6c/F0qit5MNCpS8IBgyh1BdXiyyuI client3:zkq8eT31Nib3IHWfp0yyu15BCW52VMbY8+LhVUt3ylA
The client uses the appropriate password in the /etc/stunnel/psk-client1.txt
file:
client1:Wf44zFw33FeMxCqobcA13lb28IgizxyZJOUoUsZGlkk
The recommendation is that when multiple clients are used, they use different keys. In this way, if one key is compromised, you do not need to change all the client configurations.
Conclusions
On public WiFi networks, stunnel is useful for protecting your data traffic from overly inquisitive users on the same network. In principle, however, the tool can also be operated on any other network to secure services that are not TLS-capable.
Infos
- stunnel downloads: https://www.stunnel.org/downloads.html
Buy this article as PDF
(incl. VAT)