Thursday, February 28, 2008

SMTP and POP with SSL (ucspi-tls-qmail-howto)

Why You Want To Use UCSPI-TLS

UCSPI-TLS is a protocol for adding "delayed encryption" to Dan Bernstein's Unix Client/Server Program Interface protocol. "Delayed encryption" means a session starts off in plaintext, then a command is issued to turn on encryption, encryption is negotiated, and the session restart. This has become a very common way to handle encryption, because it simplifies client configuration and requires only one TCP port.

These are the goals of UCSPI-TLS:

  • Simple, UCSPI-compatible use.
  • Support for both traditional SSL and delayed encryption through STARTTLS or similar.
  • All SSL/TLS code in one place.
  • Minimal changes required for each server.
  • Support for "privilege separation", so that encryption can happen in a low-privilege subprocess.

In particular, I believe the privilege separation feature increases your system's security significantly. It creates a dedicated process to handle each encrypted connection, and this process can change its root directory and switch to a low-privilege user and group. Because of its complexity, OpenSSL has had its share of security bugs. Doing encryption in a low-privilege process ensures that the impact of any security bugs is minimized.

How to install UCSPI-TLS for netqmail-1.05

UCSPI-TLS is currently implemented as patches to existing programs. To install it, first download the programs you want to use, apply the UCSPI-TLS patches, install the programs as you normally would, and finally make the appropriate changes to your configuration files.

Here are more details on doing this with netqmail version 1.05.

  1. Become root, using su or sudo bash. Some of these steps require you to have superuser privileges, and its easier just to get them now than to switch back and forth throughout the process.

    Do a base qmail install

  2. Install qmail according to Life with qmail , and make sure everything works with a standard setup.

    Install a patched ucspi-ssl+tls

  3. Make sure you have a recent version of OpenSSL installed on your system, along with the files required for development with the library. If you don't already have it installed, this should be available from your OS install CDs, with a name like libssl-dev or openssl-devel. If all else fails, you can download OpenSSL and compile it yourself.
  4. Download ucspi-ssl 0.70, and unpack it. It will create a directory host/superscript.com/net/ucspi-ssl-0.70; cd into this directory. Here's some commands to cut-n-paste:
    wget http://www.superscript.com/ucspi-ssl/ucspi-ssl-0.70.tar.gz
    gunzip -cd ucspi-ssl-0.70.tar.gz |tar xf -
    cd host/superscript.com/net/ucspi-ssl-0.70
  5. Download ucspi-tls patch to ucspi-ssl (you can also read the ucspitls for ucsp-ssl patch README), and apply the patch:
    wget http://www.suspectclass.com/~sgifford/ucspi-tls/files/ucspi-ssl-0.70-ucspitls-0.1.patch
    patch -p1 < ucspi-ssl-0.70-ucspitls-0.1.patch
  6. If anything is already using an older copy of sslserver, shut it off now.
  7. Compile and install the patched ucspi-ssl+tls, by running package/compile base then package/install base:
    package/compile base
    package/install base
    You now have a patched copy of sslserver in /usr/local/bin/sslserver. Congratulations!

    Patch qmail

  8. The next step is to patch qmail to add TLS support to its SMTP and POP servers. If you followed Life with qmail religiously, your qmail source code will be in /usr/local/src/netqmail-1.05/netqmail-1.05. cd to that directory, or wherever you have the qmail source:
    cd /usr/local/src/netqmail-1.05/netqmail-1.05
  9. Now download the ucspi-tls patch to netqmail (and read the ucspitls patch for netqmail README), and apply the patch:
    wget http://www.suspectclass.com/~sgifford/ucspi-tls/files/netqmail-1.05-ucspitls-0.3.patch
    patch -p2 < netqmail-1.05-ucspitls-0.3.patch
  10. If qmail is running, shut it down. On a Life with qmail setup, you do this by running:
    /var/qmail/bin/qmailctl stop
  11. Recompile and re-install qmail by running make setup check:
    make setup check
    You now have a copy of qmail-smtpd and qmail-popup with TLS support

    Make your certificates

  12. Next you'll need SSL certificates. These certificates contain the encryption keys used to communicate with your servers, and possibly a signature from a trusted authority confirming your server's identity. The first thing you'll need is a place to store them. Let's put them in /var/qmail/ssl:
    mkdir /var/qmail/ssl
    chown root /var/qmail/ssl
    chmod 700 /var/qmail/ssl
    cd /var/qmail/ssl
  13. Create the SSL keys for your system. We'll store the certificate in a file named cert, and the key in key. If you already have certificates you'd like to use, separate out the certificate part (the key part will generally be labeled RSA PRIVATE KEY, and the cert part CERTIFICATE. You can just copy these sections from your certificate file, and paste them into the appropriate files.

    You'll have to decide whether you want to use an unsigned certificate or a certificate signed by a Certificate Authority (CA). If you hire a CA to verify your identity and sign your certificate, clients are more likely to accept this certificate without prompting the user. If you use your own unsigned certificate, clients may have to confirm that they trust your certificate.

    If you'd like to use a signed certificate, choose a CA, and follow their directions to obtain a signed certificate. Save the certificate in a file called cert, and the key in a file called key. If you just have one file containing both of these, see the beginning of this step for suggestions on how to split it up.

    If you'd like to use an unsigned certificate, follow these steps:

    1. Make sure openssl is installed on your system.
    2. Set a umask that will keep your files protected, by running:
      umask 077
    3. Generate a certificate by running:
      openssl req -new -x509 -keyout key.enc -out cert -days 360
      Answer the questions you're asked. Your password is temporary, so it doesn't matter what it is as long as you remember it for a few minutes; you can even write it down. Make sure you use the server's host name, as clients will be configured to connect to it, as the "Common Name" for the certificate. Note that this certificate will expire in 360 days, and you'll have to create a new one before then.

      You'll now have a file called key.enc containing your encrypted key, and a file called cert containing your certificate.

    4. Remove the password from your certificate, so the server can start automatically. You can do this by running:
      openssl rsa -in key.enc -out key
      Enter the password you chose above, and you'll have a file called key containing an unencrypted copy of your key.
  14. Create a Diffie-Hellman parameter file. I usually create 1024-bit dhparam files, but I'll admit I don't know exactly what they do. I should probably find out and put it here. You can use the command
    openssl dhparam -out dhparam 1024
    to generate a 1024-bit Diffie-Hellman parameter file.
  15. Add a user and group for SSL to drop privileges too; name them both ssl. How to do this depends on your OS and what tools it provides; you can find some examples in the qmail source directory in a file called INSTALL.ids. For example, on Linux you would run:
    groupadd ssl
    useradd -g ssl -d /var/qmail ssl
    If you can't figure out any OS-specific commands, edit the /etc/group and /etc/passwd files directly, using the file format described in the system manpages for group(5) and passwd(5).
  16. Create a file to set shell variables in /var/qmail/ssl/env. Put these lines in that file:
    # Set these three
    SSL_USER=ssl
    SSL_GROUP=ssl
    SSL_DIR=/var/qmail/ssl
    # Enable UCSPI-TLS
    UCSPITLS=1
    # The rest are set based on the above three
    SSL_CHROOT="$SSL_DIR"
    CERTFILE="$SSL_DIR/cert"
    KEYFILE="$SSL_DIR/key"
    DHFILE="$SSL_DIR/dhparam"
    SSL_UID=`id -u "$SSL_USER"`
    if [ $? -ne 0 ]; then echo "No such user '$SSL_USER'" >&2; exit; fi
    SSL_GID=`id -g "$SSL_GROUP"`
    if [ $? -ne 0 ]; then echo "No such group '$SSL_GROUP'" >&2; exit; fi
    # Export the variables used by other scripts
    export SSL_CHROOT SSL_UID SSL_GID UCSPITLS CERTFILE KEYFILE DHFILE
  17. Now set your umask back to something more usable, like 022:
    umask 022

    Set up qmail-smtpd

  18. Edit the qmail-smtpd run file, in /var/qmail/supervise/qmail-smtpd/run. There are three changes required:
    • The top of the file has several variable settings. Below these lines, include the SSL environment variable script we created above, using the shell's "dot" command, typed as a single period:
      . /var/qmail/ssl/env
    • On the line that contains softlimit, add 10MB (10,000,000) the number after the -m flag. This allows qmail-smtpd to use the extra memory required for SSL. For example, if it's currently 2000000, you would have for that line:
      exec /usr/local/bin/softlimit -m 12000000 \
    • On the line that contains tcpserver, change tcpserver to sslserver -e -n, leaving all of the other flags in place. The line will now look something like:
      /usr/local/bin/sslserver -e -n -v -R -l "$LOCAL" -x /etc/tcp.smtp.cdb -c "$MAXSMTPD" \
  19. Restart qmail to use the new configuration:
    /var/qmail/bin/qmailctl restart
  20. Now we'll try a few tests to make sure everything works. If any of these steps fails, double-check the steps above, look for errors in the error logs, and use your common sense to see what's going wrong. Look in the logs to see if there are any errors:
    tail /var/log/qmail/smtpd/current
    You should see something like this:
    @40000000431fb29d10e09c2c sslserver: cafile 32655
    @40000000431fb29d10e120fc sslserver: ccafile 32655
    @40000000431fb29d10e14bf4 sslserver: cadir 32655 /usr/local/ssl/certs
    @40000000431fb29d10e176ec sslserver: cert 32655 /var/qmail/ssl/cert
    @40000000431fb29d10e1a9b4 sslserver: key 32655 /var/qmail/ssl/key
    @40000000431fb29d10e1d4ac sslserver: param 32655 /var/qmail/ssl/dh 512
    @40000000431fb29d10e226b4 sslserver: status: 0/20
  21. Make sure the server is now offering TLS. To test this, you can connect to the server on port 25 and issue an "extended HELO" command (EHLO) and see what extensions the server offers. To do this, start at a shell and type in the lines marked below with *:
      * telnet localhost 25
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    220 host.example.com ESMTP
    * EHLO there
    250-host.example.com
    250-PIPELINING
    250-8BITMIME
    250 STARTTLS
    * QUIT
    221 host.example.com
    The line that says STARTTLS after you type EHLO means that the server has TLS configured.
  22. Now test with a client to make sure things basically work. First start watching the logfile for errors:
    tail --follow=name /var/qmail/supervise/qmail-smtpd/log/main/current

    Unfortunately the client included with sslserver doesn't support TLS. If you have a copy of stunnel version 3 lying around, you can do something like this:

    stunnel -r localhost:25 -f -c -n smtp -D debug -P none
    Otherwise, just skip this test and try the test in the next step.
  23. Finally, try turning on TLS in the mail clients you'll be using and sending a test message. Make sure there are no errors from the client or in the logs, and that the messages arrives successfully.

    If this step works, you've set everything up correctly. Congratulations!

    Set up qmail-pop3d

    If you want to run a POP3 server, make sure you've set up qmail-pop3d as described in Life with qmail, then continue to follow these steps. If you're not running a POP3 server, you can skip this entire section.
  24. Edit the qmail-pop3d run file, in /var/qmail/supervise/qmail-pop3d/run. There are three changes required:
    • Near the top of the file, between the #!/bin/sh line and the line that begins with exec, include the SSL environment variable script we created above, using the shell's "dot" command, typed as a single period:
      . /var/qmail/ssl/env
    • On the line that contains softlimit, add 10MB (10,000,000) the number after the -m flag. This allows qmail-smtpd to use the extra memory required for SSL. For example, if it's currently 2000000, you would have for that line:
      exec /usr/local/bin/softlimit -m 12000000 \
    • On the line that contains tcpserver, change tcpserver to sslserver -e -n, leaving all of the other flags in place. The line will now look something like:
      /usr/local/bin/sslserver -e -n -v -R -H -l 0 0 110 /var/qmail/bin/qmail-popup \
  25. Restart qmail to use the new configuration:
    /var/qmail/bin/qmailctl restart
  26. Now we'll try a few tests to make sure everything works. If any of these steps fails, double-check the steps above, look for errors in the error logs, and use your common sense to see what's going wrong. Look in the logs to see if there are any errors:
    tail /var/log/qmail/pop3d/current
    You should see something like this:
    @40000000431fb29d10e09c2c sslserver: cafile 32655
    @40000000431fb29d10e120fc sslserver: ccafile 32655
    @40000000431fb29d10e14bf4 sslserver: cadir 32655 /usr/local/ssl/certs
    @40000000431fb29d10e176ec sslserver: cert 32655 /var/qmail/ssl/cert
    @40000000431fb29d10e1a9b4 sslserver: key 32655 /var/qmail/ssl/key
    @40000000431fb29d10e1d4ac sslserver: param 32655 /var/qmail/ssl/dh 512
    @40000000431fb29d10e226b4 sslserver: status: 0/20
  27. Make sure the server is now offering TLS. To test this, you can connect to the server on port 110, then ask for a list of its capabilities. To do this, start at a shell, and type in the lines marked below with *:
      * telnet localhost 110
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    +OK
    * CAPA
    +OK capability list follows
    STLS
    .
    * QUIT
    +OK
    Connection closed by foreign host.

    The STLS line after you type CAPA indicates that the server supports TLS.

  28. Now test with a client to make sure things basically work. First start watching the logfile for errors:
    tail --follow=name /var/qmail/supervise/qmail-pop3d/log/main/current

    Unfortunately the client included with sslserver doesn't support TLS. If you have a copy of stunnel version 3 lying around, you can do something like this:

    stunnel -r localhost:110 -f -c -n pop3 -D debug -P none
    Otherwise, just skip this test and try the test in the next step.
  29. Finally, try turning on TLS in the mail clients you'll be using and receiving some test messages. Make sure there are no errors from the client or in the logs, and that the messages arrives successfully.

    If this step works, you've set everything up correctly. Congratulations!

Optional Step: If desired, set up SSL servers

If you'd like to support SSL (not delayed encryption through TLS), you can still use the modified sslserver, and get the security advantages of chroot and privilege separation.

These steps will help you create an SSL service from a TLS service. The instructions are for qmail-smtpd; they will work for qmail-pop3d if you simply replace smtpd with pop3d everywhere.

  1. Change directory to /var/qmail/supervise:
    cd /var/qmail/supervise
  2. Create a service directory and log directory:
    mkdir -p qmail-smtpd-ssl/log
  3. Copy the run file from the original service, and make it executable:
    cp qmail-smtpd/run qmail-smtpd-ssl/
    chmod 755 qmail-smtpd-ssl/run
  4. Edit the run file (qmail-smtpd-ssl/run) in the following ways:
    • On the line after . /var/qmail/ssl/env, add unset UCSPITLS
    • On the line that contains sslserver line, remove the -n flag.
    • On the next line, which will contain something like 0 smtp, change smtp to smtps; that tells sslserver to listen on the appropriate port for the SSL version of this service.
  5. Set up a logging directory for this new service:
    mkdir /var/log/qmail/smtpd-ssl
    chown qmaill /var/log/qmail/smtpd-ssl
  6. Set up the logging program for this new service, by creating a file in qmail-smtpd-ssl/log/run with these contents:
    #!/bin/sh
    exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t \
    /var/log/qmail/smtpd-ssl
    Make sure the script is executable:
    chmod 755 qmail-smtpd-ssl/log/run
  7. Link the new service into the /service directory, to have it start automatically on boot:
    ln -s /var/qmail/supervise/qmail-smtpd-ssl /service
  8. Add the following to qmailctl's "start" section:
    if svok /service/qmail-smtpd-ssl ; then
    svc -u /service/qmail-smtpd-ssl /service/qmail-smtpd-ssl/log
    else
    echo qmail-smtpd-ssl supervise not running
    fi
  9. Add the following to qmailctl's "stop" section:
    echo "  qmail-smtpd-ssl"
    svc -d /service/qmail-smtpd-ssl /service/qmail-smtpd-ssl/log
  10. Add the following to qmailctl's "stat" section:
    svstat /service/qmail-smtpd-ssl
    svstat /service/qmail-smtpd-ssl/log
  11. Add the following to qmailctl's "pause" section:
    echo "Pausing qmail-smtpd-ssl"
    svc -p /service/qmail-smtpd-ssl
  12. Add the following to qmailctl's "cont" section:
    echo "Continuing qmail-smtpd-ssl"
    svc -c /service/qmail-smtpd-ssl
  13. Add the following to qmailctl's "restart" section:
    echo "* Restarting qmail-smtpd-ssl."
    svc -t /service/qmail-smtpd-ssl /service/qmail-smtpd-ssl/log
  14. To test, use an SSL-enabled mail client, or use stunnel version 3:
    stunnel -r localhost:smtps -f -c -D debug -P none

Optional Step: If desired, set up other servers

If you have any other TLS or SSL servers you'd like to set up, such as an IMAP server, you should be able to use the above steps as a template to get you started.

Required Step: Sleep better at night

Knowing your TLS- and SSL-protected mail server is secure.

Thanks

No comments: