Verifying certificates for STARTTLS email delivery and reception

Previously published here

Notes from lab work on verifying certificates in TLS email

Initial Setup

  • OS Debian Lenny
  • MTA Exim 4.69

I installed 2 Debian Lenny servers with commands:-

vserver t1 build --force -m debootstrap --context 3968 --hostname --interface eth0:a.b.c.41/25 -- -d lenny -m
vserver t2 build --force -m debootstrap --context 3768 --hostname --interface eth0:a.b.c.42/25 -- -d lenny -m

did some minimal configuration ( adding users, setting up ssh keys, sudoers ) and installed some further packages

  • mutt
  • exim4-daemon-heavy
  • openssl
  • ca-certificates

On each server, using,

dpkg-reconfigure exim4-config

I configured exim to use a split configuration file, rather than a single configuration file, as I find this easier to work with, and act as an internet site, sending and recieving mail directly through SMTP.

I used the supplied script in /usr/share/doc/exim4/examples/exim-gencert to generate a self signed certificate for each machine, and enabled each machine to advertise TLS to connecting clients by creating the file


and adding the line


I then checked that each machine could act as both a TLS client and server, by bouncing a few messages between them and looking at the logs.

Use Cases

An MTA acts in 2 different ways.

  • As a client delivering messages to another MTA
  • As a server receiving messages from another MTA
eg. sends to
       t2 MTA as client  ---->    t1 MTA as server 

I'm going to look at use case 1 first.

Users at sending to

How can user community at protect themselves from a DNS attack where another machine impersonates the MX's for, and how can they make sure that their mail is always encrypted with TLS to users at ?

Exim has two functions to manage this

tls_verify_certificates # This can be used to verify an X509 certificate chain
hosts_require_tls  # This can be used to force TLS to specific host

Exim has a "transport" function which does the delivery ( local, to a pipe, smtp ) and a "router" function which determines which transport is to be used. To implement this we will create a custom router and transport. The router will check the domain that we wish to send mail to, and, if it requires verification and tls, pass it to a custom transport. The transport will verify the certificate, and force TLS for the listed MX's, so that if verification fails, we will not fall back to plaintext.

to main/00_local_settings add

#  Domains we need to do TLS and verify for
domainlist tls_verify_relay_to_domains = 

create file router/195_exim4_config_tls_verify

t2:/etc/exim4/conf.d/router# cat  195_exim4_config_tls_verify 

# for domains that we do not relay for, and need to verify certs.
#  Since we most probably can't
# have broken MX records pointing to site local or link local IP
# addresses fixed, we ignore target hosts pointing to these addresses.

  debug_print = "R: dnslookup_tls_verify for $local_part@$domain"
  driver = dnslookup
  #  Do we need to verify and force TLS for this domain ?
  domains = ! +local_domains : +tls_verify_relay_to_domains
  transport = remote_smtp_tls_verify 
  same_domain_copy_routing = yes
  # ignore private rfc1918 and APIPA addresses
  ignore_target_hosts = : : :\
               : : :\

Create file transport/30_exim4-config_remote_smtp_tls_verify

### transport/30_exim4-config_remote_smtp_tls_verify
# This transport is used for delivering messages over SMTP connections.
# and forcing/verifying tls

  debug_print = "T: remote_smtp_tls_verify for $local_part@$domain"
  driver = smtp
  # Force TLS for all hosts on this transport
  hosts_require_tls = *
  #  Next 2 lines send our key in case server requests it
  #  Not needed in this example
  #  tls_certificate = /etc/exim4/exim.crt
  #  tls_privatekey = /etc/exim4/exim.key
  tls_verify_certificates =  ${if exists{/etc/ssl/certs/ca-certificates.crt}\

now when we send mail to we should see

we see

2009-05-14 10:38:48 1M4YKu-0003wx-Es <= U=aland P=local S=363
2009-05-14 10:38:49 1M4YKu-0003wx-Es TLS error on connection to [a.b.c.41]: certificate verification failed (invalid)
2009-05-14 10:38:49 1M4YKu-0003wx-Es == R=dnslookup_tls_verify T=remote_smtp_tls_verify defer (-37): failure while setting up TLS session

get the public certificate from

I use

openssl s_client -starttls smtp -showcerts -connect

and cut and paste the certificate into


The fingerprints of this certificate can be compared with the owner through another trusted/secure channel


dpkg-reconfigure ca-certificates

disable all untrusted authorities ( ie all apart from people you know! ) enable

restart exim

and now the log shows

2009-05-14 10:41:47 1M4YNn-0004le-2R <= U=aland P=local S=363
2009-05-14 10:41:47 1M4YNn-0004le-2R => R=dnslookup_tls_verify T=remote_smtp_tls_verify [a.b.c.41] X=TLS1.0:RSA_AES_256_CBC_SHA1:32 DN="C=GB,O=foobar,OU=beer drinkers,"
2009-05-14 10:41:47 1M4YNn-0004le-2R Completed

Problems / Difficulties

  1. Use of ca-certificates package, X509 certificate chains.

I used the debian ca-certificate package tools to build my list of certificates. It is important to remove all certificate authorities from the list. If I'd left in the cacert root certificate ( for example ) an attacker could get a certificate from CACert and it would quite happily validate for me.

Further Action

  1. Investigate Use Case 2 Certificate Validation where MTA is acting as a server. I'm finding it harder to think of how this would be useful in the real world. Any thoughts on this ?