Exim Specification - 38. Encrypted SMTP connections using TLS/SSL

Go to the first, previous, next, last section, table of contents.

# 38. Encrypted SMTP connections using TLS/SSL

Support for TLS (Transport Layer Security), otherwise known as SSL (Secure Sockets Layer), is implemented by making use of the OpenSSL library. There is no cryptographic code in the Exim distribution itself. In order to use this feature you must install OpenSSL, and then build a version that includes TLS support. You also need to understand the basic concepts of encryption at a managerial level, and in particular, the way that public keys, private keys, and certificates are used.

RFC 2487 defines how SMTP connections can make use of encryption. Once a connection is established, the client issues a STARTTLS command. If the server accepts this, they negotate an encryption mechanism. If the negotiation succeeds, the data that subsequently passes between them is encrypted.

## 38.1 Configuring Exim to use TLS as a server

When Exim has been built with TLS support, it advertises the availability of the STARTTLS command to client hosts that match tls_advertise_hosts, but not to any others. The default value of this option is unset, which means that STARTTLS is not advertised at all. This default is chosen because it is sensible for systems that wans to use TLS only as a client. To make it work as a server, you must set tls_advertise_hosts to match some hosts. You can, of course, set it to * to match all hosts. However, this is not all you need to do. TLS sessions to a server won't work without some further configuration at the server end (see below).

If a client issues a STARTTLS command and there is some configuration problem in the server code, the command is rejected with a 454 error. If the client persists in trying to issue SMTP commands, all except QUIT are rejected with the error

    554 Security failure

If a STARTTLS command is issued within an existing TLS session, it is rejected with a 554 error code.

It is rumoured that all existing clients that support TLS/SSL use RSA encryption. To make this work you need to set, in the server,

    tls_certificate = /some/file/name
    tls_privatekey = /some/file/name

The first file contains the server's X509 certificate, and the second contains the private key that goes with it. These files need to be readable by the Exim user. They can be the same file if both the certificate and the key are contained within it. If you don't understand about certificates and keys, please try to find a source of this background information, which is not Exim-specific. (There are a few comments below.)

With just these two options set, Exim will work as a server with clients such Netscape. It does not require the client to have a certificate (but see below for how to insist on this). There is one other option that may be needed in other situations. If

    tls_dhparam = /some/file/name

is set, the SSL library is initialized for the use of Diffie-Hellman ciphers with the parameters contained in the file. This increases the set of ciphers that the server supports. (See the command

    openssl dhparam

for a way of generating this data.)

The strings supplied for these options are expanded every time a client host connects. It is therefore possible to use different certificates and keys for different hosts, if you so wish, by making use of the client's IP address in $sender_host_address to control the expansion. If a string expansion is forced to fail, Exim behaves as if the option is not set.

The variable $tls_cipher is set to the cipher that was negotiated for an incoming TLS connection. It is included in the Received: header of an incoming message (by default -- you can, of course, change this), and it is also included in the log line that records a message's arrival, keyed by `X=', unless tls_log_cipher is set false.

If you want to enforce conditions on incoming TLS connections, you must set tls_verify_hosts to match the relevant clients. By default this host list is unset. You could, of course, use

    tls_verify_hosts = *

to make it apply to all TLS connections. When a client host is in this list, two further options are relevant:

- tls_verify_ciphers contains a colon-separated list of permitted ciphers. The list is passed to the OpenSSL library, so it must always be colon-separated -- Exim's alternate separator feature does not apply. For example:

      tls_verify_ciphers = DES-CBC3-SHA:IDEA-CBC-MD5

  With this option set, all TLS sessions must use one of the listed ciphers.
- tls_verify_certificates contains the name of a file or a directory that contains a collection of expected certificates. A file can contain multiple certificates, concatenated end to end. If a directory is used, each certificate must be in a separate file, with a name (or a symbolic link) of the form <hash>.0, where <hash> is a hash value constructed from the certificate. You can compute the relevant hash by running the command

      openssl x509 -hash -noout -in /cert/file

  where /cert/file contains a single certificate. When tls_verify_certificates is set, Exim always requests a certificate from the client, and fails if one is not provided. The value of the Distinguished Name of the certificate is made available in the variable $tls_peerdn during subsequent processing of the message. Because it is often a long text string, it is not included in the log line or Received: header by default. You can arrange for it to be logged, keyed by `DN=', by setting tls_log_peerdn, and you can use received_header_text to change the Received: header.

Both these options are expanded before use, so again you can make them do different things for different hosts.

You can insist that certain client hosts use TLS, by setting tls_hosts to match them. When a host is in tls_hosts, STARTTLS is always advertised to it, even if it is not in tls_advertise_hosts. If such a host attempts to send a message without starting a TLS session, the MAIL command is rejected with the error

    503 Use of TLS required

You can permit client hosts to relay, provided they are in a TLS session, by setting tls_host_accept_relay. Note that all the host relay checks are alternatives. Relaying is permitted if any of the checks is passed, that is, if

- The host matches host_accept_relay, OR
- The host is authenticated and matches host_auth_accept_relay OR
- The host is using a TLS session and matches tls_host_accept_relay.

Using tls_host_accept_relay probably makes sense only if you are checking the client's certificate.

You can insist that any client that uses the AUTH command for authentication must start a TLS session first, by setting auth_over_tls_hosts. For example,

    auth_over_tls_hosts = *

means that all authentication must take place over secure sessions. This setting does not force the matching hosts to use AUTH, but if they do, they must issue STARTTLS first. The availability of the AUTH command is advertised to such hosts only after a TLS session has been started.

## 38.2 Configuring Exim to use TLS as a client

The tls_log_cipher and tls_log_peerdn options apply to outgoing SMTP deliveries as well as to incoming, the latter one causing logging of the server certificate's DN. The remaining client configuration for TLS is all within the smtp transport.

It is not necessary to set any options to have TLS work in the smtp transport. If TLS is advertised by a server, the smtp transport will attempt to start a TLS session. However, this can be prevented by setting hosts_avoid_tls (an option of the transport) to a list of server hosts for which TLS should not be used.

If an attempt to start a TLS session fails for a temporary reason (for example, a 4xx response to STARTTLS), delivery to this host is not attempted. If there are alternative hosts, they are tried; otherwise delivery is deferred. If, on the other hand, the STARTTLS command is rejected with a 5xx error code, the smtp transport attempts to deliver the message in clear, unless the server matches hosts_require_tls, in which case delivery is again deferred unless there are other hosts to try.

There are a number of options for the smtp transport which match the global TLS options for the server, and have the same names. They are all expanded before use, with $host and $host_address containing the name and address of the server to which the client is connected. Forced failure of an expansion causes Exim to behave as if the relevant option were unset.

- tls_certificate, and tls_privatekey provide the client with a certificate, which is passed to the server if it requests it. (If the server is Exim, it will request it only if tls_verify_certificates is set.)
- tls_verify_certificates and tls_verify_ciphers on the smtp transport act exactly like their namesakes on the server: they do appropriate verification on the server's certificate and the negotiated cipher, respectively.

## 38.3 Multiple messages on the same TCP/IP connection

Exim sends multiple messages down the same TCP/IP connection by starting up an entirely new delivery process for each message, passing the socket from one process to the next. This implementation does not fit well with the use of TLS, because there is quite a lot of state associated with a TLS connection, not just a socket identification. Passing all the state information to a new process is not feasible. Consequently, Exim shuts down an existing TLS session before passing the socket to a new process. The new process may then try to start a new TLS session, and if successful, may try to re-authenticate if AUTH is in use, before sending the next message. If the server is Exim, this reinitialization works. It is not known if other servers operate successfully in these circumstances. If they do not, it may be necessary to set

    batch_max = 1

on the smtp transport, to disable multiple messages down a single TCP/IP connection.

## 38.4 Certificates and all that

In order to understand fully how TLS works, you need to know about certificates, certificate signing, and certificate authorities. This is not the place to give a tutorial, especially as I don't know very much about it myself. Some helpful introduction can be found in the FAQ for the SSL addition to Apache, at

    http://www.modssl.org/docs/2.6/ssl_faq.html#ToC24

and other parts of the modssl documentation are also helpful, and have links to further files.

You can create a self-signed certificate using the req command provided with OpenSSLL, like this:

    openssl req -x509 -newkey rsa:1024 -keyout file1 -out file2 \
                -days 9999 -nodes

file1 and file2 can be the same file; the key and the certificate are delimited and so can be identified independently. The -days option specifies a period for which the certificate is valid. The -nodes option is important: if you do not set it, the key is encryped with a pass phrase that you are prompted for, and any use that is made of the key causes more prompting for the pass phrase. This is not helpful if you are going to use this certificate and key in a mailer, where prompting is not possible.

A self-signed certificate made in this way is sufficient for testing, and may be adequate for all your requirements if you are mainly interested in encrypting transfers, and not in secure identification.

Go to the first, previous, next, last section, table of contents.