Package: exim4-config
Version: 4.92-8+deb10u4
Severity: important
Tags: security

Dear Maintainer,

When configured using the 'smarthost' or 'satellite' configuration from
exim4-config 4.92-8+deb10u4 (Debian 10 / buster), that configuration will by
default not enforce encrypted connections to the smarthost.  There is
documentation in README.Debian.gz on how to enable encryption, but the steps
laid out there have no effect, and Exim can still fall back to using
unencrypted connection when connecting to the smarthost.  And even if an
encrypted connection is used, the certificate of the server is not verified.

Workaround
----------

Set

  hosts_require_tls = *
  tls_verify_hosts = *

on the remote_smtp_smarthost transport.  Any encrypted connection for which
certificate verification fails will be closed, and delivery will be deferred.
The client Exim will never use unencrypted connections to the smarthost.

Alternatively, the same effect can be achieved by setting

  REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *
  REMOTE_SMTP_SMARTHOST_TLS_VERIFY_HOSTS = *

in /etc/exim4/conf.d/main/000_localmacros, although the latter one is only
available since Debian 11 (bullseye).

Details
=======

When configuring Exim to use a smarthost by name
(e.g. `smarthost.example.com`, but not `smarthost.example.com/MX`) and to
encrypt the connection to the smarthost, I expect Exim to
- require encryption (no fallback to an unencrypted connection),
- verify the certificate (e.g. validity period, purpose, etc),
- verify that the certificate is (recursily) signed by a trusted CA,
- require the configured hostname to match the certificate,
- and to refrain from using the connection if any of the above steps fail.

This is what I'll call _fully verified SSL_.  Connections that use encryption
but don't ensure that all of those verification steps succeed I'll call
_unverified SSL_.

I'm excluding smarthosts looked up via MX records here, because I'm currently
not in that situation, and also I have no clue how that is supposed to be
matched to certificates.  So I have no expectations there.

To avoid the mail content being intercepted between client and smarthost, I'd
like to require fully verified SSL on that connection.
`/usr/share/doc/exim4/README.Debian.gz`, section 2.2.1. "Exim 4 as TLS/SSL
client" explains that

> Exim will use TLS via STARTTLS automatically as client if the server Exim
> connects to offers it.

This is opportunistic SSL/TLS, which makes sense in the context of independent
mailservers talking with each other.  As a client talking to a smarthost, I
should know whether the server supports TLS or not, and in the case considered
here it does support it.  In this situation, doing SSL/TLS opportunistically
will lower security.

The documentation then goes on to talk about client certificates.  Sandwiched
between two paragraphs dealing with those is a paragraph

> The certificate presented by the remote host is not checked unless you
> specify a tls_verify_certificate option on the transport.

So to enable verification of certificates I need to set an option.  Nowhere
does it say how to switch from opportunistic encryption to required and fully
verified SSL.  But verifying the certificate does not really make sense in an
opportunistic setting, where the client is prepared to fall back to an
unencrypted connection.  So from that documentation I'd consider it is
reasonable to assume that by turning on that option I will implicitly make
fully verified SSL mandatory.

What should the option be set to?  `README.Debian.gz` does not say.  Exim's
`spec.info` does not know that option either, strictly speaking, but there is
a setting on the smtp transport named `tls_verify_certificates` (note the `s`
at the end), so let's go with that.

`spec.info` says in "Private options for smtp":
```
‘tls_verify_certificates’Use: _smtp_     Type:             Default:
                                         _string_*__       _system_

   The value of this option must be either the word "system" or the
absolute path to a file or directory containing permitted certificates
for servers, for use when setting up an encrypted connection.

   The "system" value for the option will use a location compiled into
the SSL library.  [...]

[...]

   For back-compatibility, if neither tls_verify_hosts nor
tls_try_verify_hosts are set (a single-colon empty list counts as being
set) and certificate verification fails the TLS connection is closed.
```

So, this option actually has a default value `system`, which seems to imply
reasonable behaviour.  The last paragraph also sounds reasonable: if no host
is explicitly configured to be checked, then check every host.  Closing the
TLS connection on verification failure sounds reasonable as well (what else
would you do?).  So from this I'd expect that after setting that option to
`system` I'll definitely require fully verified SSL.

It's a bit odd that `README.Debian.gz` instructs me to set an option that
already has a reasonable default, but maybe that is cleared in Debian's
configuration somewhere?  So let's try it out.

How to Reproduce
================

I checked that indeed encryption and successfull certificate verification is
not enforced using the following setup.  This setup is meant to model e.g. a
client Exim running on a laptop, connecting to the internet via a public wifi
under the control of the attacker.

I'm using three QEMU virtual machines connected via a VDE switch.
- client(.example.com) is the machine with the Exim under scrutiny.
- smarthost(.example.com) is used by the client to send mail
- (mail.)target(.com) is used as an external system to send mail to

The external target system is necessary since sending mail from client to
smarthost is not considered relaying, and thus the client is not asked to
authenticate.

What follows is a high-level overview over the setup, further details are in
the "Configuration Details" section below.

Basic test setup
----------------

All systems were installed from `debian-10.4.0-amd64-netinst.iso`, updating to
current Debian 10 (buster) from the debian mirrors.  Various additional
software was installed, as required.

I use one dnsmasq instance on each system to provide DNS services.  I provide
one A record each for smarthost.example.com and mail.target.com, plus an MX
record for target.com pointing to mail.target.com.

The client's Exim setup is initially a standard 'smarthost' configuration with
`smarthost.example.com` as the smarthost.  Credentials are provided to
authenticate against the smarthost.

The basic configuration for the smarthost is an 'internet' configtype, with
- some additions to function in the test environment,
- TLS and submissions support,
- support for plain, login, and cram_md5 authentication from clients, and
- a password configured for the client so it can authenticate.

The target system's setup is a normal internet site with hostname
mail.target.com, set up to accept mail for the `target.com` domain.

The certificate of the Exim server on the smarthost matches the hostname
smarthost.example.com.  It is signed by a CA created for the purpose of this
test, which the client has been configured to trust.

This setup can be used to verify basic functionality e.g. that the client is
able to sent mail via the smarthost to target.com when no attack is in
progress.

Attack setup
------------

I verified the attack by removing the CA that signed the smarthost's
certificate from the certificate store on the client again, so the client
should *not* trust the smarthost's Exim.

I appended `tls_verify_certificates=system` to
`/etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost` on the
client.  I then sent a mail from the client to r...@target.com:
```
client> exim4 -i r...@target.com <<EOF
testmarker
EOF
```

The mail appeared on the target host:
```
target> grep testmarker /var/mail/mail
testmarker
```

I started combing through `/etc/exim4/conf.d` for macros and looking deeper at
Exim's `spec.info`.  I tried these settings, all of them on the smarthost
transport:
- `tls_verify_certificates = system`,
- `tls_verify_hosts = *`, and
- `hosts_require_tls = *` (by way of setting
  `REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *` in
  `/etc/exim4/conf.d/main/000_localmacros`)

None of these were effective in isolation, they either did not enforce
encryption, or did not enforce successful certificate verification, or both.
I did not try every combination, but the combination of
`REMOTE_SMTP_SMARTHOST_HOSTS_REQUIRE_TLS = *` and `tls_verify_hosts = *` was
effective in preventing mail to be delivered and passwords being leaked when
the ssl-sniffer was active.  From `/var/log/exim4/mainlog` on the client:

```
2020-09-02 07:17:05 1kDQlF-0000et-Ln <= r...@client.example.com U=root P=local 
S=321
2020-09-02 07:17:05 1kDQlF-0000et-Ln == r...@target.com R=smarthost 
T=remote_smtp_smarthost defer (-37) H=smarthost.example.com [10.0.3.1]: TLS 
session: (certificate verification failed): certificate invalid
```

When reenabling the smarthosts CA on the client:
```
2020-09-02 07:14:44 1kDQiy-0000eq-NN <= r...@client.example.com U=root P=local 
S=321
2020-09-02 07:14:44 1kDQiy-0000eq-NN => r...@target.com R=smarthost 
T=remote_smtp_smarthost H=smarthost.example.com [10.0.3.1] 
X=TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256 CV=yes 
DN="C=US,CN=smarthost.example.com" A=cram_md5 K C="250- 330 byte chunk, total 
330\\n250 OK id=1kDQiy-0000RC-Sx"
2020-09-02 07:14:44 1kDQiy-0000eq-NN Completed
```

Configuration Details
=====================

Basic DNS configuration
-----------------------

dnsmasq was used to provide DNS services.  One instance was installed on each
system and provided the following configuration in
`/etc/dnsmasq.d/testconfig`:
```
address=/smarthost.example.com/$(<conf/smarthost.ip)
address=/mail.target.com/$(<conf/target.ip)
mx-host=target.com,mail.target.com,1
```

Certificates
------------

To have some certificates to test with, create a CA key and cert with
```
openssl genrsa -out demo-ca.key 2048
openssl req -new -nodes -x509                                           \
                -sha256 -out demo-ca.crt -key demo-ca.key       \
                -config ca_cert.cnf -extensions v3_ca           \
                -subj "$(cat conf/demo.subj)"                           \
                -set_serial 0 -days 3650
```
where the content of  `ca_cert.cnf` is:
```
[ req ]
distinguished_name = reqdn

[ reqdn ]

[ v3_ca ]
basicConstraints        = CA:TRUE
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
```

Install this CA on the client by copying the certificate to
`/usr/local/share/ca-certificates/demo-ca.crt` and running
`update-ca-certificates`.

For the smarthost certificate, create a key and a certificate request, then
use the CA to sign that request:
```
openssl genrsa -out smarthost.key 2048
openssl req -new -nodes -out smarthost.req -key smarthost.key   \
        -config smarthost_cert.cnf
rm -f smarthost.srl # ensure we use a random serial each time
openssl x509 -req -in smarthost.req -out smarthost.crt          \
        -CA demo-ca.crt -CAkey demo-ca.key -CAcreateserial      \
        -CAserial smarthost.srl
```
where the content of `smarthost_cert.cnf` is:
```
[ req ]
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
countryName = US
commonName = smarthost.example.com
```

Client Exim Configuration
-------------------------

The basic configuration for the client is exactly what you'd get through
debconf-configuration with 'smarthost' configtype.

`/etc/exim4/update-exim4.conf.conf`:
```
dc_eximconfig_configtype='smarthost'
dc_other_hostnames='client.example.com'
dc_local_interfaces='127.0.0.1 ; ::1 ; $(< conf/client.ip)'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost='smarthost.example.com'
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'
```

`/etc/exim4/passwd.client`:
```
smarthost.example.com:client:$client_password
```

Smarthost Exim Configuration
----------------------------

`/etc/exim4/update-exim4.conf.conf`:
```
dc_eximconfig_configtype='internet'
dc_other_hostnames='smarthost.example.com'
dc_local_interfaces='127.0.0.1 ; ::1 ; $(< conf/smarthost.ip)'
dc_readhost=''
dc_relay_domains='example.com'
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'
```

In `/etc/exim4/conf.d/router/200_exim4-config_primary`, the item
`!10.0.3.0/24` must be prepended in front of the `ignore_target_hosts`
hostlist, so Exim won't refuse to deliver mail to the target host.

`/etc/exim4/exim.key`, `/etc/exim4/exim.crt`: The private key and certificate
for Exim, owned by `root:Debian-exim` and with permissions `640`.

TLS is enabled in `/etc/exim4/conf.d/main/000_localmacros` by adding:
```
MAIN_TLS_ENABLE = 1
```

Support for TLS-on-connect on the `submissions` port is enabled by dropping in
the file `/etc/exim4/conf.d/main/03_tls_on_connect` with content
```
tls_on_connect_ports = 465
```
and by appending
```
SMTPLISTENEROPTIONS='-oX 25:465:587 -oP /var/run/exim4/exim.pid'
```
to `/etc/default/exim4`.

Support for client authentication methods is enabled by adding the files
`/etc/exim4/conf.d/auth/30-$auth-server` for `$auth` in `plain`, `login` and
`cram_md5`.  The contents of these files was lifted from the respective
comments in `/etc/exim4/conf.d/auth/30_exim4-config_examples`.

A client password is set in `/etc/exim4/passwd`:
```
client:$(mkpasswd --method=sha512crypt 
"$(<conf/client.pass)"):$(<conf/client.pass)
```

Target Exim Configuration
-------------------------

`/etc/mailname`:
```
target.com
```

`/etc/exim4/update-exim4.conf.conf`:
```
dc_eximconfig_configtype='internet'
dc_other_hostnames='target.com'
dc_local_interfaces='127.0.0.1 ; ::1 ; $(< conf/target.ip)'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_mailname_in_oh='true'
dc_localdelivery='mail_spool'
```


This was initially reported 2020-09-04 to secur...@debian.org.

Regards,
Jorrit Fahlke.




-- Package-specific info:
Exim version 4.92 #5 built 13-May-2020 16:01:31
Copyright (c) University of Cambridge, 1995 - 2018
(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2018
Berkeley DB: Berkeley DB 5.3.28: (September  9, 2013)
Support for: crypteq iconv() IPv6 GnuTLS move_frozen_messages DANE DKIM DNSSEC 
Event OCSP PRDR SOCKS TCP_Fast_Open
Lookups (built-in): lsearch wildlsearch nwildlsearch iplsearch cdb dbm dbmjz 
dbmnz dnsdb dsearch nis nis0 passwd
Authenticators: cram_md5 plaintext
Routers: accept dnslookup ipliteral manualroute queryprogram redirect
Transports: appendfile/maildir/mailstore autoreply lmtp pipe smtp
Fixed never_users: 0
Configure owner: 0:0
Size of off_t: 8
Configuration file search path is 
/etc/exim4/exim4.conf:/var/lib/exim4/config.autogenerated
Configuration file is /var/lib/exim4/config.autogenerated

-- System Information:
Debian Release: 10.8
  APT prefers stable
  APT policy: (990, 'stable'), (500, 'stable-updates'), (500, 'stable-debug'), 
(1, 'testing-debug'), (1, 'experimental-debug'), (1, 'experimental'), (1, 
'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 5.10.0-0.bpo.3-amd64 (SMP w/4 CPU cores)
Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8), 
LANGUAGE=de_DE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages exim4-config depends on:
ii  adduser                3.118
ii  debconf [debconf-2.0]  1.5.71

exim4-config recommends no packages.

exim4-config suggests no packages.

-- Configuration Files:
/etc/email-addresses changed [not included]
/etc/exim4/conf.d/router/200_exim4-config_primary changed [not included]
/etc/exim4/conf.d/transport/30_exim4-config_remote_smtp_smarthost changed [not 
included]
/etc/exim4/passwd.client [Errno 13] Keine Berechtigung: 
'/etc/exim4/passwd.client'

-- debconf information excluded

-- 

Attachment: signature.asc
Description: PGP signature

Reply via email to