Folks,
The way we configure OpenSSL and the amount of special stuff we have to
do is a bit of a mess. GnuTLS is a bit better, because you can put TLS
protocol versions into the Priority String, but with OpenSSL, we're
stuck trying to support every last thing and caught when some folks
stuck supporting bad clients hold us back from letting everyone else
move forward.
Several years ago, I added the openssl_options config knob to Exim,
which at least made things a bit better, but we're creaking now.
This is a rough proposal, with not a single line of code written to
support it, but I'm looking for considered informed feedback as to
whether it makes sense to postmasters out there.
We've said "we only support versions of OpenSSL supported by the
upstream project", so now it's time to take advantage of that. I'm
proposing a new configuration section, when built against OpenSSL, which
uses an API introduced with OpenSSL 1.0.2, the minimum version still
supported upstream. We would use SSL_CONF_cmd(3) and pass settings
through from Exim's configure file, straight to OpenSSL.
How it would look:
~~~~~~~~~~~~~~~~~~~~~~~~8< hooking: variant 1 >8~~~~~~~~~~~~~~~~~~~~~~~~
# Variant 1: main section config, handled like tls_require_ciphers now:
openssl = ${if eq{$received_port}{25}{server_mx}{server_submission}}
~~~~~~~~~~~~~~~~~~~~~~~~8< hooking: variant 1 >8~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~8< hooking: variant 2 >8~~~~~~~~~~~~~~~~~~~~~~~~
# main section:
acl_smtp_connect = acl_connect
begin acl
acl_connect:
warn condition = ${if eq{$received_port}{25}}
control = openssl/server_mx
warn condition = ${if !eq{$received_port}{25}}
control = openssl/server_submission
~~~~~~~~~~~~~~~~~~~~~~~~8< hooking: variant 2 >8~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~8< hooking: smtp transport >8~~~~~~~~~~~~~~~~~~~~~~
begin transports:
remote_smtp:
driver = smtp
openssl = ${if dane{client_dane}{client_insecure}}
~~~~~~~~~~~~~~~~~~~~~8< hooking: smtp transport >8~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~8< new config section >8~~~~~~~~~~~~~~~~~~~~~~~~
# This section is ignored if built against GnuTLS
#
# Warning: no string expansion is performed here (but may be in future).
# Macros are allowed.
begin openssl
server_mx:
CipherString DEFAULT:!SSLv2:!LOW:aNULL:!eNULL
MinProtocol TLSv1 # requires OpenSSL 1.1.0.
Certificate /etc/exim/tls/mx.crt
PrivateKey /etc/exim/tlx/mx.key
server_submission:
Ciphersuites TLS13-CHACHA20-POLY1305-SHA256:... # used for TLS1.3
CipherString ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:HIGH:!MD5:!RC4:!aNULL:!ADH:!DES:!EXP:!NULL
MinProtocol TLSv1.2
Groups X25519
Options -SessionTicket
Certificate /etc/exim/tls/submission.crt # private CA, perhaps
PrivateKey /etc/exim/tls/submission.key
client_dane:
MinProtocol TLSv1.2
CipherString something modern-ish here
# VerifyCAPath irrelevant here, DANE only supports usages 2/3 which
# ignores this ... although if the remote server doesn't send a full
# chain and uses fingerprint-based pinning, this might unbreak things
# enough?
client_insecure:
MinProtocol TLSv1
VerifyCAPath /etc/ssl/certs # Exim's require/try options still affect this
CipherString something broad here
# This isn't referenced above, but fancier config options could make it
# required for domains in a whitelist, eg to say "use better security
# for gmail.com":
client_secure:
MinProtocol TLSv1.2
CipherString something modern-ish here
VerifyCAPath /etc/ssl/certs
~~~~~~~~~~~~~~~~~~~~~~~~8< new config section >8~~~~~~~~~~~~~~~~~~~~~~~~
Some settings come in with newer versions of OpenSSL. We wouldn't have
to do anything special to support them, that's _why_ we'd just pass
things through. If someone shouts and wants MinProtocol with older
OpenSSL, we'd shrug and say "upgrade OpenSSL, we use what they export
and are not getting sucked into replicating their work."
We simply split on whitespace to a "key" and a "value", where the value
can have internal whitespace we don't touch, but we strip off leading
and trailing whitespace. Then we pass each key/value down.
The openssl main setting, or ACL control, and openssl SMTP transport
would all only be valid when built with OpenSSL and be parse errors with
GnuTLS. The "begin openssl" could be allowed and ignored with GnuTLS.
At daemon startup, before backgrounding, where we do validation right
now, we'd go through every defined config block in the openssl section,
and for each one we're create an OpenSSL context, call SSL_CONF_cmd() to
set each line, and make sure there's no error. If there's an error,
that's a fatal configuration error and is passed back. These contexts
are all discarded. This would then automatically be visible as an error
when running "exim -bV"/"exim --version".
Then at runtime, these values are just passed in when configuring the
context.
For sanity, at first we'd skip string expansion, but would allow macros.
If there's an argument to be made for allowing string expansion, we
could switch to allowing it but would need to figure out what startup
validation looks like in that case.
I've introduced a hypothetical expansion condition "dane" for dispatch.
Exim settings which would become obsolete for OpenSSL:
* tls_require_ciphers
* tls_certificate
* tls_privatekey
* tls_dhparam, tls_dh_max_bits, tls_dh_min_bits
* tls_verify_certificates
* tls_ocsp_file
* openssl_options
* smtp transport: tls_require_ciphers
* smtp transport: dane_require_tls_ciphers
To not break backwards compatibility, we'd allow all of those options to
exist and work as long as the "openssl" option is not set. Whether and
when to break them is a larger issue.
Regards,
-Phil