Nov 162001

stunnel – another way to avoid plain text passwords

This article was written by Mike Miller and reviewed by Robert Hough and Jim C. Nasby.

Plain text passwords are the worst! I run a personal mail server on a public network. Every time I check my email from the office I’m sending out my password in plain text! It’s incredibly easy for someone to set up a sniffer on the network and steal my password. I needed a way to secure the connection between my client email program and the mail server.

stunnel gave me the solution I was looking for. It wraps easily around any existing tcp application. Perfect for my pop3 headache. So what is stunnel? If you read /usr/ports/security/stunnel/pkg-descr you’ll find:

The stunnel program is designed to work  as  SSL  encryption
wrapper between remote client and local (inetd-startable) or
remote server. The concept is that having non-SSL aware daemons  
running  on  your  system you can easily setup them to
communicate with clients over secure SSL channel.

stunnel can be used to add  SSL  functionality  to  commonly
used  inetd  daemons  like  POP-2,  POP-3  and  IMAP servers
without any changes in the programs' code.

NOTE: If you upgrade from v3 to v4, the the stunnel invocation has changed! The program no longer accepts command-line options, but is controlled by a config file instead. Please refer to the stunnel(8) manual page for more information. See Upgrading to stunnel 4 for more information.

Installing stunnel

First thing to do is install stunnel. So off to the ports.

	monkey# cd /usr/ports
	monkey# make search key=stunnel
stunnel turns up in the security category.

	monkey# cd /usr/ports/security/stunnel
	monkey# make install

Towards the end of the installation, stunnel prompts me to make a certificate file. I’m going to do this manually later, so for now I just press ENTER at each of the prompts.

Now that stunnel is installed, it seems like a good time to read through man stunnel.

Creating a Certificate with OpenSSL

OpenSSL is installed by default on my 4.3 install, but if you have an older version of FreeBSD you may need to install OpenSSL from the ports first.

I’m going to create an SSL certificate to be used by stunnel when incoming connections come in. If you’ve created certificates before for Apache, this will be quite familiar.

	monkey# openssl req -new -out mail.pem -keyout mail.pem -nodes -x509 -days 365
	Country Name (2 letter code) [AU]:CA
	State or Province Name (full name) [Some-State]:Ontario
	Locality Name (eg, city) []:Toronto
	Organization Name (eg, company) [Internet Widgits Pty Ltd]:Monkey Business Inc.
	Organizational Unit Name (eg, section) []:Wrench Research Division
	Common Name (eg, YOUR name) []
	Email Address []
What have I just done here? I’ve asked openssl to generate a private key, and a certificate file to along with it. Both of these are put into the mail.pem file.

The -x509 states that I’m not requesting a certificate, but generating one myself. -nodes prevents the certificate from being encrypted with a key. If I didn’t include this, a passphrase would be necessary in order to decrypt and read the certificate file. -days indicates that the certificate will expire in 365 days, at which time I’ll need to create a new one.

I’m going to secure the certificate file so it can’t be read by anyone but root and put it in a memorable place like /etc.

	monkey# chown root:wheel mail.pem
	monkey# chmod 600 mail.pem
	monkey# mv ./mail.pem /etc/mail.pem

Configuring stunnel

Time to implement stunnel. It’s a good time to take a look at the rest of the man page in stunnel if you haven’t done so, including the OPTIONS.

I’m going to need to take a look at my current inetd.conf configuration to see what changes I’m going to need to make. This is my current line for pop3 connections.

pop3 stream tcp nowait root /usr/local/libexec/qpopper qpopper -s

To implement secured pop3 access, I’m going to add the following new line. Note the use of ‘pop3s’ instead of ‘pop3’. If you take a look in your /etc/services file you should find that the pop3s service runs on port 995. If it’s not there, add it yourself and save the change.

pop3s stream tcp nowait root /usr/local/sbin/stunnel qpopper -p /etc/mail.pem -l /usr/local/libexec/qpopper qpopper -s

Any incoming connections to the pop3s port will start up stunnel, which in turn reads in our certificate file and runs my qpopper mail server.

Last step is to reload inetd with a quick killall -HUP inetd and I should be set.

Testing stunnel

First I make sure my pop3 server is still accessible on the standard pop3 port.

	monkey# telnet 110
	Connected to
	Escape character is '^]'.
	+OK Qpopper (version 4.0.3) at starting.
	user jimmy
	+OK Password required for jimmy.
	pass jimmy
	+OK jimmy has 0 visible messages (0 hidden) in 0 octets.
	+OK 0 visible messages (0 octets)
	+OK Pop server at signing off.
	Connection closed by foreign host.

OK everything looks like it’s working ok, now let’s try connecting on the pop3s port.

	monkey# telnet 995
	Connected to
	Escape character is '^]'.
	user jimmy
	Connection closed by foreign host.

Dropped connection! Of course, I have to tunnel the client connection through stunnel as well. stunnel can run as a daemon, redirecting incoming connections to a server running under stunnel. To start the stunnel daemon I’ll do the following.

	monkey# stunnel -c -d localhost:110 -r

Now any connections coming in on port 110 of localhost will be redirected to on port 995 with stunnel doing all the talking on both ends, keeping the conversation secure.

Let’s try connecting again, but this time to port 110 on localhost.

	monkey# telnet localhost 110
	Connected to
	Escape character is '^]'.
	+OK Qpopper (version 4.0.3) at starting.
	user jimmy
	+OK Password required for jimmy.
	pass jimmy
	+OK jimmy has 0 visible messages (0 hidden) in 0 octets.
	+OK 0 visible messages (0 octets)
	+OK Pop server at signing off.
	Connection closed by foreign host.

Hey! That’s great. Now any pop3 clients running on that box can connect securely to my pop3 server. I just change the pop3 server addresses in the configuration to connect to “localhost” instead of “”.

Some mail clients have native support for SSL connections, like Microsoft’s Outlook Express. Just look under the Account Properties -> Advanced tab and check the “Use SSL” box under the pop3 port setting.

Setting up the remote end

Reviwer Jim C. Nasby had these recommendations for configuration of the remote end of an stunnel.
I think it would be useful to include a script for /usr/local/etc/rc.d. Here’s a script I use for setting up the remote end:
$ cat /usr/local/etc/rc.d/
# A sample stunnel startup script written by
# $FreeBSD: ports/security/stunnel/files/,v 1.1 2000/07/07 19:27:27 steve Exp $

# Where is the program

case "$1" in
${STUNNEL} -d 6660 -c -N ircs-out -r
#${STUNNEL} -d 993 -r localhost:imap -p /usr/local/etc/stunnel.pem
#${STUNNEL} -d 995 -r localhost:pop3 -p /usr/local/etc/stunnel.pem

killall `basename ${STUNNEL}`

echo ""
echo "Usage: `basename $0` { start | stop }"
echo ""
You can obviously tell where I commented out the default imap and pop3 listeners. From what I’ve seen, stunnel is pretty slow when run from inetd.

  14 Responses to “stunnel – another way to avoid plain text passwords”

  1. Um…just out of curiousity, what does this give that SSH port forwarding doesn’t? I mean, the end result is the same–connections to localhost get transparently forwarded and encrypted to the remote computer. SSH, however, is readily available for all platforms and doesn’t require messing with inetd.

    So, is there something I’m missing that makes stunnel superior? Can it handle situations that SSH port forwarding can’t?


    • There are some situations that are easier to handle with SSL. For one thing, SSH requires you to have an account on the remote machine, while SSL doesn’t. This makes SSL excellent for things such as a secured IRC network (some irc servers, such as Unreal, allow for SSL connections).

      SSL is also often a better choice for automated scripts. To automatically connect to something with SSH, you need to code a password into a script, or use a passphraseless RSA or DSA key. Both of these solutions can dramatically increase your exposure unless you go to great lengths to lock down the account that SSH is using. SSL doesn’t suffer from any of these shortcommings.

    • I set up the POP3 server at my work with stunnel. I force all connections from outside our local net to connect to pop3s, the SSL’d POP3 daemon. I can just tell the windows users to click on the "Secure POP3" checkbox in whatever email client they use (which is invariably outlook, of course). I don’t have to worry about whether they have an ssh client, I don’t have to worry about whether it’s even possible to tunnel from their windows boxes, and it’s no extra work for them. They just select one option and they’re good to go.

      SSH is good for people who actually have some understanding of unix, or at least of computers. Point and click type people would never understand how to get anything done with SSH tunnels but have no problems clicking checkboxes.

  2. Just a thought; wouldn’t it be "correcter" to place the mail.pem file in /usr/local/etc instead of the system wide /etc?

    just a thought – click46

    • Probably, but as long as you remember it probably doesn’t matter. Some apps such as the imap-uw port if built with WITH_SSL defined expect to see the certificates in /usr/local/certs which seems really odd to me…

  3. Although stunnel is useful in itself, qpopper 4 and the latest pop/imap servers from the imap-uw port can both be compiled with built-in SSL support…

    Just another way to do the same thing…

  4. while I use stunnel to access a POP3 server that requires SSL, I will be replacing it with something BSDL’d (or generally, non-GPL’d) soon. I don’t feel comfortable about passing any sensitive data through a program whose license says that all output from the program is covered by the license unless blah blah. I wouldn’t touch GnuPG with a ten feet pole for the very same reason. IANAL, but rather be safe than sorry.

  5. I tried these instructions, and couldn’t for the life of me figure out why I couldn’t get Outlook to talk to my freebsd box. I’d get a cryptic message saying that I should re-check the SSL infomration and port.

    It turned out that the problem was a mismatch between the DNS name I set in outlook ( and the name I entered for my server ( when I created my x509 certificate.

    Hopefully this will save others the time and frustration I spent. :-/


  6. Hi there,

    Great article I enjoyed it quite a bit since I’ve not used stunnel and really want to learn to use it so this was perfect. However I noticed in the passage where it is referring to look at /etc/services etc etc that seemed to be rendered a little in correctly. Glancing at the HTML I noticed that one of the tags is missing a close caret. Here’s the passage in question:

    To implement secured pop3 access, I’m going to add the following new line.
    Note the use of ‘pop3s’ instead of ‘pop3’. If you take a look in your
    &lt;CODE CLASS="code"&gt;/etc/services&lt;/CODE file you should find that the pop3s service runs
    on port 995. If it’s not there, add it yourself and save the change.

    Notice that &lt;/CODE&gt; is actually &lt;/CODE !

    Otherwise thanks for the article it was very informative.

    • Argh, seems HTML tags are interpreted by this bulletin board. But the offending passage was there and one of the CODE tags is missing a closing caret at the very end. I’m not sure if this was a mistake in the original article or elsewhere but figured someone wouldn’t mind knowing.


  7. How can I use the stunnel on vpopmail if this uses the tcpserver program to run?


    • This can be accomplished by using this supervise script (See Life with Qmail for supervise):

      LOCAL=`head -1 /var/qmail/control/me`
      QMAILDUID=`id -u qmaild`
      NOFILESGID=`id -g qmaild`
      MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`

      exec /usr/local/bin/softlimit -m 11000000 \
      /usr/local/bin/tcpserver -v -R -l "$LOCAL" -x /etc/tcp.smtp.cdb -c "$MAXSMTPD" \
      -u "$QMAILDUID" -g "$NOFILESGID" 0 smtps \
      /usr/sbin/stunnel -T ssmtp -p /path/to/stunnel.pem -l \
      /var/qmail/bin/qmail-smtpd 2>&1

      Adjusted to your path, of course…

  8. I’m using the startup scripts to create tunnels between my web and cvs servers so the traffic is encrypted. Works well.