Verifying certificates for STARTTLS email delivery and reception

Previously published here http://aland.burngreave.net/archives/2009/12/30/index.html#e2009-12-30T16_26_49.txt

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 t1.example.org --interface eth0:a.b.c.41/25 -- -d lenny -m http://ftp.uk.debian.org/debian
vserver t2 build --force -m debootstrap --context 3768 --hostname t2.example.org --interface eth0:a.b.c.42/25 -- -d lenny -m http://ftp.uk.debian.org/debian

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

/etc/exim4/conf.d/main/00_local_settings

and adding the line

MAIN_TLS_ENABLE = yes

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.  user@t2.example.org sends to aland@t1.example.org
       t2 MTA as client  ---->    t1 MTA as server 

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

Users at t2.example.org sending to t1.example.org

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

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 = t1.example.org 

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.

dnslookup_tls_verify:
  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 = 0.0.0.0 : 127.0.0.0/8 : 192.168.0.0/16 :\
                        172.16.0.0/12 : 10.0.0.0/8 : 169.254.0.0/16 :\
            255.255.255.255
  no_more

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

remote_smtp_tls_verify:
  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}\
                                    {/etc/ssl/certs/ca-certificates.crt}\
                                    {/dev/null}}

now when we send mail to t1.example.org we should see

we see

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

get the public certificate from t1.example.org

I use

openssl s_client -starttls smtp -showcerts -connect t1.example.org:25

and cut and paste the certificate into

/usr/share/ca-certificates/t1.example.org/t1.example.org.crt

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

using

dpkg-reconfigure ca-certificates

disable all untrusted authorities ( ie all apart from people you know! ) enable t1.example.org

restart exim

and now the log shows

2009-05-14 10:41:47 1M4YNn-0004le-2R <= user@t2.example.org U=aland P=local S=363
2009-05-14 10:41:47 1M4YNn-0004le-2R => user@t1.example.org R=dnslookup_tls_verify T=remote_smtp_tls_verify H=t1.example.org [a.b.c.41] X=TLS1.0:RSA_AES_256_CBC_SHA1:32 DN="C=GB,O=foobar,OU=beer drinkers,CN=t1.example.org"
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 ?