Bringing military-grade cybersecurity solutions to the enterprise and critical systems.
Telephone: 310.356.7869

Secure relaying with Postfix TLS

Category: Linux

3:15 PM, Sat, Dec 8 2007

The requirement: Users outside the corporate network need to be able to send email from their corporate accounts. This is needed by home users, remote office users, and traveling users. This post is all about outgoing (sending) mail from users. Incoming mail is handled by entirely separate protocols, usually IMAP or POP, which are easier to configure.

Back in the Sendmail days, it was normal for mail servers to run as open relays, meaning they would accept and attempt to deliver mail for any host on the Internet. This practice was convenient but did not survive the advent of spam. Today, any mail server that acts as an open relay will quickly end up on the open relay blocking system and will not be able to send mail to other hosts. Relays must be secure, which means mail servers must be configured to handle different email sources, destinations, and connection types differently.

The rules of secure relaying are simple. Assume that our domain name is example.com. Assume we have an internal, trusted network, and we have the external, untrusted Internet. Which mail should the mail server accept?

  1. Mail addressed to anyone@example.com should be accepted and processed
  2. Mail which originates on the internal network (ie, corporate network) to anyone@anydomain.com, should be sent out to the appropriate mail exchangers. This means that the MTA must make decisions based on the connecting client's IP address.
  3. Mail sent from anyone@example.com, from the untrusted Internet, from an authenticated connection, should be relayed

All other mail should be rejected, but not bounced.

This example will be based on the Postfix MTA, version 2.2.9. The latest version is Postfix 2.4.6, which added support for Dovecot as the Simple Authentication and Security Layer (SASL) server. Postfix prior to 2.3 did supported only Cyrus Project's SASL support. We are using SuSE 10.1's MTA, which is Postfix 2.2.9, so we must use Cyrus SASL. This is unnecessarily complex, when Dovecot by itself can serve both IMAP and SASL, but is the only option until we upgrade from SuSE 10.1 on the server. (In late April 2008, we will switch to Ubuntu Server 8.04 Long Term Support LTS "Hardy Heron".)

The goal is to have Postfix deny relaying of mail, except to users who have authenticated using password authentication. Of course, sending unencrypted passwords over the net is not safe and should not be done so we'll also need to enable Transport Layer Security (TLS) within Postfix.

SASL is a simple protocol which allows a server to make authentication requests to a SASL server. Think of it as PAM over a network. One server, such as Postfix, needs to authenticate a user, so Postfix connects to a SASL server to find out if the user is authorized. PAM could do the same thing but PAM requires linking in a library and is more Linux-specific. SASL operates over sockets so the SASL client (Postfix in this case) can connect to a SASL server which might be on a different computer, in a different architecture. In this case we will be using the Cyrus SASL server, which has good support within Postfix. We're using cyrus-sasl-2.1.21-18, which comes with SuSE 10.1. The latest version is Cyrus SASL 2.1.22.

Configuration can be broken into these steps:

  1. Verify the packages are installed
  2. Configure Cyrus to serve SASL
  3. Configure Postfix to make authentication requests to SASL
  4. Configure Postfix to use TLS
  5. Test the TLS configuration on Postfix using OpenSSL
  6. Test the server to make sure it is not an open relay
  7. Configure the Mozilla Thunderbird email client to use this setup

Step 1: verify the packages: The necessary packages are Postfix, compiled with Cyrus SASL libraries, and Cyrus SASL. In our case, these packages were provided in the Suse 10.1 distribution.

Step 2: configure Cyrus to serve SASL: We'll be using plain old Linux system users. Cyrus can use many other user sources, including LDAP and a database, but for this simple installation, we're using /etc/passwd, without even using PAM. The Cyrus SASL library puts together the path to find its configuration file. In our case, it is looking for /usr/lib/sasl2/smtpd.conf. This file should contain:

pwcheck_method: saslauthd
mech_list: plain login

mech_list is necessary to prevent Postfix from reporting other authentication methods which SASL does not actually support. This file must be named smtpd.conf.

Step 3: Configure Postfix to make authentication requests to SASL: Edit the Postfix main.cf file, and add:

smtp_sasl_auth_enable = no
smtpd_sasl_auth_enable = yes
smtpd_use_tls = yes # we'll configure this later
smtpd_sasl_security_options = noanonymous
smtp_use_tls = no

smtpd_recipient_restrictions = permit_sasl_authenticated
  permit_mynetworks
  reject_unauth_destination

At this point we can test sending mail. Hint: Many ISPs block port 25 connection, to prevent "spam zombies" from sending outgoing spam. You can make Postfix listen on additional ports by adding a line like:

10025  inet   n    -            n       -       -       smtpd

to master.cf. This will make Postfix also listen on 10025, so if users are being blocked on port 25, they can make a simple configuration change in their email software and get through on the higher port.

The main.cf file says smtpd_use_tls = yes, but we haven't configured any SSL keys for the server. What happens in this situation?

telnet chiralsoftware.net 10025
Trying 205.134.230.202...
Connected to chiralsoftware.net.
Escape character is '^]'.
220 chiralsoftware.net ESMTP Postfix
ehlo example.com
250-chiralsoftware.net
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH LOGIN PLAIN
250 8BITMIME
starttls
454 TLS not available due to local problem
                

This is not good. smtpd_use_tls = yes could be set, and the administrator could think that it's working, and clients could connect, and all the while plaintext passwords would be going over the net. Even worse, an installation could be set up correctly, and then if the keys were deleted by accident, the system would silently switch into a non-secure mode, and most clients will fall back to non-encrypted authorization sessions. To fix this, add:

smtpd_tls_auth_only = yes

Now Postfix will only accept authentication in connections which are TLS encrypted.

Step 4: Configure Postfix to use TLS: This is the most complicated part of the setup. Note that Postfix TLS configuration changed somewhat between 2.2 and 2.3, and we're configuring for 2.2, so this will be somewhat different if you're using the current version. The ideas are the same.

We're using a GoDaddy certificate. GoDaddy became a root authority by acquiring Starfield Technologies, which purchased the Valicert Class 2 Policy Validation Authority. This presents a problem: all browsers, and OpenSSL, come with the major CA root certificates, but not with GoDaddy's new root certificate. To get around this we need to install a bundle of intermediate certificates which link the Valicert certification, which everyone has, to the GoDaddy certificate authority (CA) certificate, which then has signed our site certificate.

Here's the process with GoDaddy: First, we created a key pair using the Java keytool command. This command creates a keystore, which contains the public key / private key pair. The keystore is secured with a passphrase. After generating the key pair, we again use keytool to generate a signing request. We purchase a certificate credit from GoDaddy. GoDaddy gives instructions for submitting the public key of the key pair for signing with GoDaddy's Certificate Authority public key. When that is done, GoDaddy emails back a link to a zip file which is downloaded, and which contains the signed site certificate, and GoDaddy's intermediate certificates bundle. The signing request contained only the public key data. Private key data never leave the server.

We used keytool again and followed the instructions to install this key and signed certificate and intermediate certificate into our Tomcat keystore file. Then it is a simple matter to have Tomcat use those keys to enable secure connections. All works, and now you can access chiralsoftware.com with either http: or https: connections. We need this level of security to protect our employees' access to our internal web applications, and to protect customer access to their applications during development.

The Java-format keystore is the only copy of the keys we have. We need to take the same private key and certificates from the Java keystore and put them into a form which is usable for Postfix. Like most Unix software, Postfix uses the OpenSSL library. Postfix requires key data in a PEM file (entirely different from a Java keystore) and it requires a private key with no passphrase. The PEM file must include:

  1. Our secret key
  2. Our signed certificate
  3. GoDaddy's intermediate certificate, which is signed by the old Vericert root certificate

Extracting the secret key from our keystore requires a trick. The keytool created the key and put it in the keystore, so keytool must be able to get it out, right? Wrong. keytool can extract public certificates, but it has no ability to extract private keys. Why Sun did it this way makes little sense. It's perfectly easy to write a key extraction program in a few lines of Java, and any Java application which wants to be a TLS-protected server will need access to private key data. If keytool can't do it, GetKey.java can. To use GetKey find the alias of the key you want in the keystore, using our favorite keytool:

% keytool -list -keystore tomcat.keystore
Enter keystore password:

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 3 entries

tomcat, Jun 16, 2007, PrivateKeyEntry,
Certificate fingerprint (MD5): F0:A0:.....
intermed, Jun 16, 2007, trustedCertEntry,
Certificate fingerprint (MD5): D5:2F:.....
cross, Jun 16, 2007, trustedCertEntry,
Certificate fingerprint (MD5): 82:6D:.....

We need the tomcat private key, the tomcat certificate, and the intermed intermediate certificate. That's one private key (requires GetKey) and two certificates (can be extracted with plain old keytool).

Download the GetKey command, and start extracting:

java -jar GetKey.jar /tomcatpath/tomcat.keystore my-passphrase tomcat >
   /etc/postfix/example.pem

That gives us the private key. The next two items we need are public certificates, so we extract them with keytool. We grab the aliases for tomcat (keytool will only get tomcat's public certificate) and GoDaddy's intermediate certificate, which has the alias intermed in this keystore.

% keytool -exportcert 
  -keystore tomcat.keystore -storepass my-passphrase -alias tomcat -rfc >>
  /etc/postfix/example.pem
% keytool -exportcert 
  -keystore tomcat.keystore -storepass my-passphrase -alias intermed -rfc >>
  /etc/postfix/example.pem

Set the path to the certificate file in main.cf:

smtpd_tls_cert_file = /etc/postfix/example.pem
smtpd_tls_key_file = /etc/postfix/example.pem

Restart Postfix:

/etc/rc.d/postfix restart

and I got this error in the log:

Dec  9 00:24:18 server postfix/smtpd[16617]: 
  warning: connect to private/tlsmgr: No such file or directory
Dec  9 00:24:18 server postfix/smtpd[16617]: 
  warning: problem talking to server private/tlsmgr: No such file or directory
                

To fix that, find the line:

tlsmgr    unix  -       -       n       1000?   1       tlsmgr

in master.cf and uncomment it if it is commented out.

Now everything should be ready.

Step 5: test TLS using the OpenSSL command line utility: OpenSSL ships with a very handy CLI utility. You'll have this available on any Linux or OS X system. It can also be installed on Microsoft Windows. Let's test the server:

openssl s_client -starttls smtp -connect example.com:25

It displays detailed information about the TLS connection. After that it shows the following SMTP commands:

ehlo foo
250-chiralsoftware.net
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH LOGIN PLAIN
250 8BITMIME
quit
221 Bye
                

Note that it offers AUTH LOGIN PLAIN. If we telnet in, without using openssl, we see instead:

% telnet example.com 25
Trying 192.168.1.99...
Connected to example.com.
Escape character is '^]'.
220 example.com ESMTP Postfix
ehlo somename
250-example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250 8BITMIME
                

It does offer STARTTLS, but does not offer AUTH LOGIN PLAIN. Perfect. We have tested both positive and negative cases.

Sending mail through a mail client, such as Mozilla Thunderbird, works at this point. I'll show the configuration at the end.

Step 6: Test the server to make sure it is not an open relay: If your server, by some chance, functions as an open relay, it will quickly be used as a spam gateway. Use the Abuse.net open relay test service to test your server. This open relay testing service tries over a dozen different ways to relay mail through the server. If it can relay mail, your server is misconfigured and should be fixed promptly.

Step 7: Configure a mail client, such as Mozilla Thunderbird: Go to Edit / Account Settings. Select "Outgoing Server (SMTP)". Add or edit an outgoing server, like this:

Mozilla Thunderbird, Postfix TLS

In this example, I'm using 10025, which is not the default SMTP port. As explained above, many ISPs block port 25 from customer connections, so it's handy to have Postfix listening on some non-standard port, in addition to port 25.

Conclusion: We have configured a secure way for our corporate users to send mail when they are outside the corporate network. Our configuration relied on Postfix, Cyrus SASL and OpenSSL, components which are standard in any Linux server distribution. We also used keytool and a short Java program called GetKey to extract keys from a Java keystore file. These keys were signed by GoDaddy.

This was a fairly complicated process, mainly due to getting the TLS data into the right format and location. This whole process would be simpler if all the various network servers could find key and certificate data in a common format and common location. All Java programs can use the keystore file, so if we were using a Java mailer such as Apache James, we could have it share key data with Tomcat. Also, some future release of Java, perhaps based on OpenJDK, might be able to use OpenSSL for its keys and encryption, which could allow it to share key data with all the other software which uses OpenSSL, such as Apache HTTPD and many others.

In a future article we could explore more advanced mail configuration, such as virtual domains and keeping user data in a database. We could also explore improving security by issuing certificates to users, so that we would have mutual authentication. Mutual authentication would give us more assurance than a password.