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 for implementing TLS. In order to use this feature you must install OpenSSL, and then build a version of Exim that includes TLS support (see section 4.5). 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, the client and the server negotiate an encryption mechanism. If the negotiation succeeds, the data that subsequently passes between them is encrypted.
Exim's ACLs can detect whether the current SMTP session is encrypted or not, and if so, what cipher is in use, whether the client supplied a certificate, and whether or not that certificate was verified. This makes it possible for an Exim server to deny or accept certain commands based on the encryption state.
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 you need to set some other options in order to make TLS avaliable, and also it is sensible for systems that want to use TLS only as a client.
If a client issues a STARTTLS command and there is some configuration problem in the server, 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.
To enable TLS operations on 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.
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 do not 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 in section 36.5.)
With just these two options set, Exim will work as a server with clients such as 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
for a way of generating this data.
The strings supplied for these three 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 the tls_cipher log selector is turned off.
The ACLs that run for subsequent SMTP commands can check the name of the cipher and vary their actions accordingly. The cipher names are those used by OpenSSL. These may differ from the names used elsewhere. For example, OpenSSL uses the name DES-CBC3-SHA for the cipher which in other contexts is known as TLS_RSA_WITH_3DES_EDE_CBC_SHA. Check the OpenSSL documentation for more details.
If you want an Exim server to request a certificate when negotiating a TLS session with a client, you must set either tls_verify_hosts or tls_try_verify_hosts. You can, of course, set either of them to * to apply to all TLS connections. For any host that matches one of these options, Exim requests a certificate as part of the setup of the TLS session. The contents of the certificate are verified by comparing it with a list of expected certificates. These must be available in a file or directory that is identified by tls_verify_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.
The difference between tls_verify_hosts and tls_try_verify_hosts is what happens if the client does not supply a certificate, or if the certificate does not match any of the certificates in the collection named by tls_verify_certificates. If the client matches tls_verify_hosts, the attempt to set up a TLS session is aborted, and the incoming connection is dropped. If the client matches tls_try_verify_hosts, the (encrypted) SMTP session continues. ACLs that run for subsequent SMTP commands can detect the fact that no certificate was verified, and vary their actions accordingly. For example, you can insist on a certificate before accepting a message for relaying, but not when the message is destined for local delivery.
When a client supplies a certificate (whether it verifies or not), 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 the tls_peerdn log selector, and you can use received_header_text to change the Received: header. When no certificate is supplied, $tls_peerdn is empty.
The tls_cipher and tls_peerdn log selectors 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 Exim is built with TLS support, and TLS is advertised by a server, the smtp transport always tries 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 the 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. If STARTTLS is accepted, but the subsequent attempt to negotiate an encrypted session fails, Exim closes the connection, opens a new one to the same host, and sends the message in clear.
If you do not want Exim to attempt to send messages in clear when an attempt to set up an encrypted connection fails, you can set hosts_require_tls to a list of hosts for which encryption is mandatory. For those hosts, delivery is deferred if an encrypted connection cannot be set up.
The tls_certificate and tls_privatekey options of the smtp transport provide the client with a certificate, which is passed to the server if it requests it. If the server is Exim, it will request a certificate only if tls_verify_hosts or tls_try_verify_hosts matches the client.
If tls_verify_certificates is set, it must name a file or directory that contains a collection of expected certificates. The client verifies the server's certificate against this collection. If tls_require_ciphers is set on the smtp transport, it must contain a list of permitted ciphers. If either of these checks fail, delivery to the current host is abandoned, and the smtp transport tries to deliver to alternative hosts, if any.
All the TLS options in the smtp transport are 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.
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 information 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 shutdown and reinitialization works. It is not known which other servers operate successfully if the client closes a TLS session and continues with unencrypted SMTP. If you encounter a server which fails, you must stop Exim passing the socket on to another process. If you set
connection_max_messages = 1
on the smtp transport, all multiple messages down a single TCP/IP connection are disabled. You probably do not want to do that unless you are using TLS for all remote deliveries. A more selective approach is to set hosts_nopass_tls on the smtp transport to match those hosts for which the default action is known to fail.
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 do not know very much about it myself. Some helpful introduction can be found in the FAQ for the SSL addition to Apache, currently at
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 OpenSSL, 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 encrypted with a passphrase that you are prompted for, and any use that is made of the key causes more prompting for the passphrase. This is not helpful if you are going to use this certificate and key in an MTA, 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.
However, many clients require that the certificate presented by the server be a user (also called ``leaf'' or ``site'') certificate, and not a self-signed certificate. In this situation, the self-signed certificate described above must be installed on the client host as a trusted root certification authority (CA), and the certificate used by Exim must be a user certificate signed with that self-signed certificate.
For information on creating self-signed CA certificates and using them to sign user certificates, see the General implementation overview chapter of the Open-source PKI book, available online at http://ospkibook.sourceforge.net/.