15. Adding TLS support to Postfix

TLS (formerly SSL) stands for Transport Layer Security. Once this layer is established, it encrypts the communication between two hosts. If we use SMTP AUTH and the mechanisms PLAIN or LOGIN usernames and passwords are sent plaintext over the internet. This means that anyone could sniff the communication and read the passwords. If you don't want this - we bet you don't - you can use TLS to help.

Procedure 8. Process to SMTP AUTH using plaintext passwords and TLS

  1. Connect to your Postfix-server

  2. establish a TLS encrypted communication layer and

  3. only then send our SMTP AUTH PLAIN or LOGIN

Procedure 9. Steps for integration

  1. Check if our Postfix build supports TLS

  2. Build the certificates that are issued when a TLS connection is being established

  3. Add configuration parameters to Postfix main.cf that enable TLS

  4. Advise Postfix only to SMTP AUTH when a TLS connection has successfully been established.

15.1. Check Postfix for TLS support

If you built the RPMS you may wonder why we check for TLS support. This section also applies for NON-RPM configuration and people that might just jump in on this HOWTO. Anyway it's a good exercise. You'll find out how to query binaries for the libraries they support.

In our HOWTO the smtpd daemon is in /usr/libexec/postfix/. So we do the following at the command line:

[root@example.com]# ldd /usr/libexec/postfix/smtpd
libsasl.so.7 => /usr/lib/libsasl.so.7 (0x4001e000)
libssl.so.2 => /lib/libssl.so.2 (0x4002a000)
libcrypto.so.2 => /lib/libcrypto.so.2 (0x40057000)
libdb-3.2.so => /lib/libdb-3.2.so (0x4011a000)
libnsl.so.1 => /lib/libnsl.so.1 (0x401c1000)
libresolv.so.2 => /lib/libresolv.so.2 (0x401d7000)
libgdbm.so.2 => /usr/lib/libgdbm.so.2 (0x401ea000)
libc.so.6 => /lib/i686/libc.so.6 (0x401f1000)
libdl.so.2 => /lib/libdl.so.2 (0x4032c000)
libcrypt.so.1 => /lib/libcrypt.so.1 (0x40330000)
libpam.so.0 => /lib/libpam.so.0 (0x4035d000)
libgssapi_krb5.so.2 => /usr/kerberos/lib/libgssapi_krb5.so.2 (0x40365000)
libkrb5.so.3 => /usr/kerberos/lib/libkrb5.so.3 (0x40378000)
libk5crypto.so.3 => /usr/kerberos/lib/libk5crypto.so.3 (0x403d1000)
libcom_err.so.3 => /usr/kerberos/lib/libcom_err.so.3 (0x403e2000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

The smtpd daemon supports TLS. If you cannot find the libssl in the output you either built Postfix with static libraries or building Postfix with TLS didn't work. In this case you'll have to reconfigure your Postfix SOURCE, recompile or rebuild it, backup the data in /etc/postfix/ and reinstall the newly compiled Postfix binaries.

15.2. Which certificates are required?

15.2.1. CA cert (cacert.pem)

We need a cert from a Cert-Authority that we can refer to when a client wants to validate the cert that we issued from our Postfix-server. There are two possibilities and it all boils down that “It's a matter of trust”.

15.2.1.1. Become your own CA

If you are a private user and simply want to enjoy encrypted communication, but don't want to pay for a cert, you can become your own CA. You'll only will use it for yourself and hey who shouldn't trust yourself more that you. This HOWTO will show you how to do that.

15.2.1.2. Get an official certificate

If you will use your server for business purposes (ISP, etc.) you should go and get a valid cert for your server from an official CA. Your customers will appreciate. Meanwhile this should not keep you from reading on and building your own CA authority certificate for testing purposes.

15.2.2. Public server.cert (newcert.pem)

We will need to issue a certificate when we establish the connection. This certificate is the public server.cert.

15.2.3. Private server cert (newreq.pem)

What do we need this for? Anyway, it's the private server cert.

15.3. Build certificates for TLS use

When a TLS connection is being established the host establishing the connection has to validate itself. This is because someone else could hijack the connection and establish an encrypted connection. The remote host probably wouldn't notice and pass sensible information. Therefore certificates are used to provide unique information that proves that the host encrypting the communication really is the host your client wants to talk to.

You are right when you argue that anyone even a hostile server could issue a certificate if it wasn't for that little detail we left out: Each certificate that is issued provides information about an authority that will validate the cert that is issued when an TLS connection is established. Now that you understand the concept you'll understand what we need:

[Note]Note

The following information was written for RedHat 7.x users. If you run a different version or distribution your mileage may vary.

On RedHat machines OpenSSL has its configuration file for creating certs in /usr/share/ssl. So we go there and edit that file first as it carries the default values that will be offered to us later. You can skip this section, but don't complain when you mistype your values and must start the whole script again. ;-)

[root@example.com]# cd /usr/share/ssl/
[root@example.com]# vi openssl.cnf

edit countryName_default and 0.organizationName_default and provide values that make sense to your setting. This HOWTO will use Germany (DE) and HOWTO as values.

countryName_default          = DE
0.organizationName_default   = HOWTO

then uncomment organizationalUnitName_default and add a value. We will use Mail server in this HOWTO.

organizationalUnitName_default = Mailserver

add the lines commonName_default (must be the name of your Mail server!) and emailAddress_default and provide values specific to your setting. Our Mail servers hostname is mail.example.com and postmaster@example.com is in charge.

commonName_default    = mail.example.com
emailAddress_default  = postmaster@example.com

That's it and it will save us a lot of typing as we will build not only one cert. Save the file and read on as we will have to edit yet another file.

Consider this: Usually certs are crypted. That's a good idea when you take them along with yourself and the disc you have it on gets lost. It won't be of any use to the finder unless that person also knows your secret passphrase... But then if you don't take it with you, but leave it on a server this feature can become a real problem to the availability of your service. Why?

Any time you restart the server and the server wants to get its hand on the cert, the cert wants to be given the secret passphrase and the server hangs in there waiting to pass that task on its start list. And it waits and waits and waits... until you enter the secret passphrase at the command prompt. The bottom line is: No passphrase, no service.

So we will not create certs with secret passphrases, as we will not always be available when the server needs to be restarted or starts itself, say after a power failure.

In order to have certs that aren't crypted we will have to add a parameter to the script that we run when we create a cert. So let's cd to the directory that holds the script and create a backup first before we edit it.

[root@example.com]# cd misc/
[root@example.com]# cp CA CA_nodes
[root@example.com]# edit CA_nodes
[Note]Note

Either it's CA or CA.pl. This depends on your RedHat distribution. Both scripts will help you generate certs.

Search for # create a certificate and add -nodes to the line below that begins with $REQ. When your done with this search for # create a certificate request and do the same again.

When your done it should look like this:

-newcert)
# create a certificate
$REQ -new -nodes -x509 -keyout newreq.pem -out newreq.pem $DAYS
RET=$?
echo "Certificate (and private key) is in newreq.pem"
;;
-newreq)
# create a certificate request
$REQ -new -nodes -keyout newreq.pem -out newreq.pem $DAYS
RET=$?
echo "Request (and private key) is in newreq.pem"
;;

That's it for preparations. Let's create the certs.

15.3.1. Generating the CA certificate

The first cert we will create is the Authority cert. We do this by calling the CA script and telling it that we want it to create a new CA:

[root@example.com]# ./CA_nodes -newca
CA certificate filename (or enter to create)
MAKING CA CERTIFICATE ...
Using configuration from /usr/share/ssl/openssl.cnf
Generating a 1024 bit RSA private key
................++++++
......................++++++
writing new private key to './demoCA/private/./cakey.pem'
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [DE]:
State or Province Name (full name) [Germany]:
Locality Name (eg, city) []:Munich
Organization Name (eg, company) [ExampleOrganisation]:
Organizational Unit Name (eg, section) [Mailserver]:
Common Name (eg, your name or your server's hostname) [mail.example.com]:
Email Address [postmaster@example.com]:

15.3.2. Generating the server certificate

Then we will create the server cert request that will be signed by the CA Authority:

[root@example.com]# ./CA_nodes -newreq
Using configuration from /usr/share/ssl/openssl.cnf
Generating a 1024 bit RSA private key
.........................++++++
.............++++++
writing new private key to 'newreq.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [DE]:
State or Province Name (full name) [Germany]:
Locality Name (eg, city) []:Munich
Organization Name (eg, company) [ExampleOrganisation]:
Organizational Unit Name (eg, section) [Mailserver]:
Common Name (eg, your name or your server's hostname) [mail.example.com]:
Email Address [postmaster@example.com]:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:certpass
An optional company name []:
Request (and private key) is in newreq.pem

15.3.3. Signing the server certificate

Finally we sign the server cert request with our own CA cert:

[root@example.com]# ./CA_nodes -sign
Using configuration from /usr/share/ssl/openssl.cnf
Enter PEM pass phrase:
Check that the request matches the signature
Signature ok
The Subjects Distinguished Name is as follows
countryName :PRINTABLE:'DE'
stateOrProvinceName :PRINTABLE:'Germany'
localityName :PRINTABLE:'Munich'
organizationName :PRINTABLE:'ExampleOrganisation'
organizationalUnitName:PRINTABLE:'Mailserver'
commonName :PRINTABLE:'mail.example.com'
emailAddress :IA5STRING:'postmaster@example.com'
Certificate is to be certified until Mar 15 07:45:17 2003 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
...
Signed certificate is in newcert.pem

Abstract

Let's review what we have generated:

newreq.pem

This is the private SERVER CERT. We generated it in order to request an CA to sign it. It contains our private key.

newcert.pem

That is your public SERVER CERT. It has been signed by a CA in this case ourselves.

demoCA/cacert.pem

This is the CERT of the CA Authority. We created it when we made ourselves a CA.

15.3.4. Installing the certificates

We want the certs that we use for TLS support in SMTP to stick closely with our Postfix configuration files. So we copy them to the Postfix CONFIG_DIR.

[root@example.com]# cp newcert.pem /etc/postfix/
[root@example.com]# cp newreq.pem /etc/postfix/
[root@example.com]# cp demoCA/cacert.pem /etc/postfix/

15.4. Enabling TLS in Postfix

We got the certs. Next we will tell Postfix where they are and that we want it to offer TLS using them.

[root@example.com]# cd /etc/postfix
[root@example.com]# vi main.cf

There is no TLS configuration in the main.cf. So we start wherever we want to and add some documentation as we enter the configuration:

## TLS
#  Transport Layer Security
#  TLS-Patch by Lutz Jänicke
#
smtpd_use_tls = yes
#smtpd_tls_auth_only = yes
smtpd_tls_key_file = /etc/postfix/newreq.pem
smtpd_tls_cert_file = /etc/postfix/newcert.pem
smtpd_tls_CAfile = /etc/postfix/cacert.pem
smtpd_tls_loglevel = 3
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom

There's one parameter that we leave commented out for the moment, as we want to check only if we can initiate a TLS session without 'hiding' SMTP AUTH at the moment.

[Note]Note

If you want to understand what these parameters are for you might want to read Postfix/TLS - Configuring main.cf and master.cf by Lutz Jänicke the creator and maintainer of Postfix/TLS support.

15.5. Reloading Postfix

So we're done with the configuration. We now need to reload postfix and make it reread the new configuration.

[root@example.com]# postfix reload

15.6. Checking for TLS support

Next we will check if we can initiate a TLS session. We telnet to the server and check, if the string STARTTLS shows up when Postfix advertises it's capabilities. Then we simply type in STARTTLS and wait for Postfix to respond that it is ready to start TLS. This is how our successful telnet session should look like:

C: [root@example.com]# telnet mail.example.com 25
S: 220 mail.example.com ESMTP Postfix (1.1.5)
C: EHLO example.com
S: 250-mail.example.com
S: 250-PIPELINING
S: 250-SIZE 10240000
S: 250-VRFY
S: 250-ETRN
S: 250-STARTTLS
S: 250-AUTH PLAIN LOGIN DIGEST-MD5 CRAM-MD5 GSSAPI
S: 250-AUTH=PLAIN LOGIN DIGEST-MD5 CRAM-MD5 GSSAPI
S: 250-XVERP
S: 250 8BITMIME
C: STARTTLS
S: 220 Ready to start TLS

So Postfix advertises TLS and it can start a session. Time to go for the full experience and configure a mail client.

15.7. Configure mail client to use SSL for SMTP

Again we will be using MS Outlook in this HOWTO. Open Extras --> Accounts --> mailaccount and switch to the advanced tab. Then check the box that reads: Server requires secure connection.

TLS configuration: Outlook Express: Properties

15.8. Enabling Postfix to offer SMTP AUTH only when TLS is established

That leaves us with one major step to be done. We want to make sure that SMTP AUTH PLAIN will only be available to users who use TLS. So we advise Postfix to issue the SMTP AUTH command only when TLS has been established. This brings us back to the one line we had left commented out in main.cf when we added TLS support.

[root@example.com]# vi main.cf

Search for smtpd_tls_auth_only and uncommented the line. It should read like this:

smtpd_tls_auth_only = yes

15.9. Reloading Postfix

We edited main.cf, we must tell Postfix. So we reload it.

[root@example.com]# postfix reload

Now when we send messages to the server SMTP AUTH will only be offered after the TLS layer has been established. You can see that when you telnet to the server. The AUTH announcement is gone and still when you use a mail client you can relay using SMTP AUTH.

C: [root@example.com]# telnet mail.example.com 25
S: 220 mail.example.com ESMTP Postfix (1.1.5)
C: EHLO example.com
S: 250-mail.example.com
S: 250-PIPELINING
S: 250-SIZE 10240000
S: 250-VRFY
S: 250-ETRN
S: 250-STARTTLS
S: 250-XVERP
S: 250 8BITMIME
C: STARTTLS
S: 220 Ready to start TLS

That's it. Your done. Have fun.