-DMARC Support
---------------------------------------------------------------
-
-DMARC combines feedback from SPF, DKIM, and header From: in order
-to attempt to provide better indicators of the authenticity of an
-email. This document does not explain the fundamentals, you
-should read and understand how it works by visiting the website at
-http://www.dmarc.org/.
-
-DMARC support is added via the libopendmarc library. Visit:
-
- http://sourceforge.net/projects/opendmarc/
-
-to obtain a copy, or find it in your favorite rpm package
-repository. If building from source, this description assumes
-that headers will be in /usr/local/include, and that the libraries
-are in /usr/local/lib.
-
-1. To compile Exim with DMARC support, you must first enable SPF.
-Please read the Local/Makefile comments on enabling the SUPPORT_SPF
-feature. You must also have DKIM support, so you cannot set the
-DISABLE_DKIM feature. Once both of those conditions have been met
-you can enable DMARC in Local/Makefile:
-
-EXPERIMENTAL_DMARC=yes
-LDFLAGS += -lopendmarc
-# CFLAGS += -I/usr/local/include
-# LDFLAGS += -L/usr/local/lib
-
-The first line sets the feature to include the correct code, and
-the second line says to link the libopendmarc libraries into the
-exim binary. The commented out lines should be uncommented if you
-built opendmarc from source and installed in the default location.
-Adjust the paths if you installed them elsewhere, but you do not
-need to uncomment them if an rpm (or you) installed them in the
-package controlled locations (/usr/include and /usr/lib).
-
-
-2. Use the following global settings to configure DMARC:
-
-Required:
-dmarc_tld_file Defines the location of a text file of valid
- top level domains the opendmarc library uses
- during domain parsing. Maintained by Mozilla,
- the most current version can be downloaded
- from a link at http://publicsuffix.org/list/.
- See also util/renew-opendmarc-tlds.sh script.
-
-Optional:
-dmarc_history_file Defines the location of a file to log results
- of dmarc verification on inbound emails. The
- contents are importable by the opendmarc tools
- which will manage the data, send out DMARC
- reports, and expire the data. Make sure the
- directory of this file is writable by the user
- exim runs as.
-
-dmarc_forensic_sender Alternate email address to use when sending a
- forensic report detailing alignment failures
- if a sender domain's dmarc record specifies it
- and you have configured Exim to send them.
-
- If set, this is expanded and used for the
- From: header line; the address is extracted
- from it and used for the envelope from.
- If not set, the From: header is expanded from
- the dsn_from option, and <> is used for the
- envelope from.
-
- Default: unset.
-
-
-3. By default, the DMARC processing will run for any remote,
-non-authenticated user. It makes sense to only verify DMARC
-status of messages coming from remote, untrusted sources. You can
-use standard conditions such as hosts, senders, etc, to decide that
-DMARC verification should *not* be performed for them and disable
-DMARC with a control setting:
-
- control = dmarc_disable_verify
-
-A DMARC record can also specify a "forensic address", which gives
-exim an email address to submit reports about failed alignment.
-Exim does not do this by default because in certain conditions it
-results in unintended information leakage (what lists a user might
-be subscribed to, etc). You must configure exim to submit forensic
-reports to the owner of the domain. If the DMARC record contains a
-forensic address and you specify the control statement below, then
-exim will send these forensic emails. It's also advised that you
-configure a dmarc_forensic_sender because the default sender address
-construction might be inadequate.
-
- control = dmarc_enable_forensic
-
-(AGAIN: You can choose not to send these forensic reports by simply
-not putting the dmarc_enable_forensic control line at any point in
-your exim config. If you don't tell it to send them, it will not
-send them.)
-
-There are no options to either control. Both must appear before
-the DATA acl.
-
-
-4. You can now run DMARC checks in incoming SMTP by using the
-"dmarc_status" ACL condition in the DATA ACL. You are required to
-call the spf condition first in the ACLs, then the "dmarc_status"
-condition. Putting this condition in the ACLs is required in order
-for a DMARC check to actually occur. All of the variables are set
-up before the DATA ACL, but there is no actual DMARC check that
-occurs until a "dmarc_status" condition is encountered in the ACLs.
-
-The dmarc_status condition takes a list of strings on its
-right-hand side. These strings describe recommended action based
-on the DMARC check. To understand what the policy recommendations
-mean, refer to the DMARC website above. Valid strings are:
-
- o accept The DMARC check passed and the library recommends
- accepting the email.
- o reject The DMARC check failed and the library recommends
- rejecting the email.
- o quarantine The DMARC check failed and the library recommends
- keeping it for further inspection.
- o none The DMARC check passed and the library recommends
- no specific action, neutral.
- o norecord No policy section in the DMARC record for this
- sender domain.
- o nofrom Unable to determine the domain of the sender.
- o temperror Library error or dns error.
- o off The DMARC check was disabled for this email.
-
-You can prefix each string with an exclamation mark to invert its
-meaning, for example "!accept" will match all results but
-"accept". The string list is evaluated left-to-right in a
-short-circuit fashion. When a string matches the outcome of the
-DMARC check, the condition succeeds. If none of the listed
-strings matches the outcome of the DMARC check, the condition
-fails.
-
-Of course, you can also use any other lookup method that Exim
-supports, including LDAP, Postgres, MySQL, etc, as long as the
-result is a list of colon-separated strings.
-
-Performing the check sets up information used by the
-${authresults } expansion item.
-
-Several expansion variables are set before the DATA ACL is
-processed, and you can use them in this ACL. The following
-expansion variables are available:
-
- o $dmarc_status
- This is a one word status indicating what the DMARC library
- thinks of the email. It is a combination of the results of
- DMARC record lookup and the SPF/DKIM/DMARC processing results
- (if a DMARC record was found). The actual policy declared
- in the DMARC record is in a separate expansion variable.
-
- o $dmarc_status_text
- This is a slightly longer, human readable status.
-
- o $dmarc_used_domain
- This is the domain which DMARC used to look up the DMARC
- policy record.
-
- o $dmarc_domain_policy
- This is the policy declared in the DMARC record. Valid values
- are "none", "reject" and "quarantine". It is blank when there
- is any error, including no DMARC record.
-
-A now-redundant variable $dmarc_ar_header has now been withdrawn.
-Use the ${authresults } expansion instead.
-
-
-5. How to enable DMARC advanced operation:
-By default, Exim's DMARC configuration is intended to be
-non-intrusive and conservative. To facilitate this, Exim will not
-create any type of logging files without explicit configuration by
-you, the admin. Nor will Exim send out any emails/reports about
-DMARC issues without explicit configuration by you, the admin (other
-than typical bounce messages that may come about due to ACL
-processing or failure delivery issues).
-
-In order to log statistics suitable to be imported by the opendmarc
-tools, you need to:
-a. Configure the global setting dmarc_history_file.
-b. Configure cron jobs to call the appropriate opendmarc history
- import scripts and truncating the dmarc_history_file.
-
-In order to send forensic reports, you need to:
-a. Configure the global setting dmarc_forensic_sender.
-b. Configure, somewhere before the DATA ACL, the control option to
- enable sending DMARC forensic reports.
-
-
-6. Example usage:
-(RCPT ACL)
- warn domains = +local_domains
- hosts = +local_hosts
- control = dmarc_disable_verify
-
- warn !domains = +screwed_up_dmarc_records
- control = dmarc_enable_forensic
-
- warn condition = (lookup if destined to mailing list)
- set acl_m_mailing_list = 1
-
-(DATA ACL)
- warn dmarc_status = accept : none : off
- !authenticated = *
- log_message = DMARC DEBUG: $dmarc_status $dmarc_used_domain
-
- warn dmarc_status = !accept
- !authenticated = *
- log_message = DMARC DEBUG: '$dmarc_status' for $dmarc_used_domain
-
- warn dmarc_status = quarantine
- !authenticated = *
- set $acl_m_quarantine = 1
- # Do something in a transport with this flag variable
-
- deny condition = ${if eq{$dmarc_domain_policy}{reject}}
- condition = ${if eq{$acl_m_mailing_list}{1}}
- message = Messages from $dmarc_used_domain break mailing lists
-
- deny dmarc_status = reject
- !authenticated = *
- message = Message from $dmarc_used_domain failed sender's DMARC policy, REJECT
-
- warn add_header = :at_start:${authresults {$primary_hostname}}
-
-
-
DSN extra information
---------------------
If compiled with EXPERIMENTAL_DSN_INFO extra information will be added
-Early pipelining support
-------------------------
-Ref: https://datatracker.ietf.org/doc/draft-harris-early-pipe/
-
-If compiled with EXPERIMENTAL_PIPE_CONNECT support is included for this feature.
-The server advertises the feature in its EHLO response, currently using the name
-"X_PIPE_CONNECT" (this will change, some time in the future).
-A client may cache this information, along with the rest of the EHLO response,
-and use it for later connections. Those later ones can send esmtp commands before
-a banner is received.
-
-Up to 1.5 roundtrip times can be taken out of cleartext connections, 2.5 on
-STARTTLS connections.
-
-In combination with the traditional PIPELINING feature the following example
-sequences are possible (among others):
-
-(client) (server)
-
-EHLO,MAIL,RCPT,DATA ->
- <- banner,EHLO-resp,MAIL-ack,RCPT-ack,DATA-goahead
-message-data ->
-------
-
-EHLO,MAIL,RCPT,BDAT ->
- <- banner,EHLO-resp,MAIL-ack,RCPT-ack
-message-data ->
-------
-
-EHLO,STARTTLS ->
- <- banner,EHLO-resp,TLS-goahead
-TLS1.2-client-hello ->
- <- TLS-server-hello,cert,hello-done
-client-Kex,change-cipher,finished ->
- <- change-cipher,finished
-EHLO,MAIL,RCPT,DATA ->
- <- EHLO-resp,MAIL-ack,RCPT-ack,DATA-goahead
-
-------
-(tls-on-connect)
-TLS1.2-client-hello ->
- <- TLS-server-hello,cert,hello-done
-client-Kex,change-cipher,finished ->
- <- change-cipher,finshed
- <- banner
-EHLO,MAIL,RCPT,DATA ->
- <- EHLO-resp,MAIL-ack,RCPT-ack,DATA-goahead
-
-Where the initial client packet is SMTP, it can combine with the TCP Fast Open
-feature and be sent in the TCP SYN.
-
-
-A main-section option "pipelining_connect_advertise_hosts" (default: *)
-and an smtp transport option "hosts_pipe_connect" (default: unset)
-control the feature.
-
-If the "pipelining" log_selector is enabled, the "L" field in server <=
-log lines has a period appended if the feature was advertised but not used;
-or has an asterisk appended if the feature was used. In client => lines
-the "L" field has an asterisk appended if the feature was used.
-
-The "retry_data_expire" option controls cache invalidation.
-Entries are also rewritten (or cleared) if the adverised features
-change.
-
-
-NOTE: since the EHLO command must be constructed before the connection is
-made it cannot depend on the interface IP address that will be used.
-Transport configurations should be checked for this. An example avoidance:
-
- helo_data = ${if def:sending_ip_address \
- {${lookup dnsdb{>! ptr=$sending_ip_address} \
- {${sg{$value} {^([^!]*).*\$} {\$1}}} fail}} \
- {$primary_hostname}}
-
-
+TLS Session Resumption
+----------------------
+TLS Session Resumption for TLS 1.2 and TLS 1.3 connections can be used (defined
+in RFC 5077 for 1.2). The support for this can be included by building with
+EXPERIMENTAL_TLS_RESUME defined. This requires GnuTLS 3.6.3 or OpenSSL 1.1.1
+(or later).
+
+Session resumption (this is the "stateless" variant) involves the server sending
+a "session ticket" to the client on one connection, which can be stored by the
+client and used for a later session. The ticket contains sufficient state for
+the server to reconstruct the TLS session, avoiding some expensive crypto
+calculation and one full packet roundtrip time.
+
+Operational cost/benefit:
+ The extra data being transmitted costs a minor amount, and the client has
+ extra costs in storing and retrieving the data.
+
+ In the Exim/Gnutls implementation the extra cost on an initial connection
+ which is TLS1.2 over a loopback path is about 6ms on 2017-laptop class hardware.
+ The saved cost on a subsequent connection is about 4ms; three or more
+ connections become a net win. On longer network paths, two or more
+ connections will have an average lower startup time thanks to the one
+ saved packet roundtrip. TLS1.3 will save the crypto cpu costs but not any
+ packet roundtrips.
+
+ Since a new hints DB is used, the hints DB maintenance should be updated
+ to additionally handle "tls".
+
+Security aspects:
+ The session ticket is encrypted, but is obviously an additional security
+ vulnarability surface. An attacker able to decrypt it would have access
+ all connections using the resumed session.
+ The session ticket encryption key is not committed to storage by the server
+ and is rotated regularly (OpenSSL: 1hr, and one previous key is used for
+ overlap; GnuTLS 6hr but does not specify any overlap).
+ Tickets have limited lifetime (2hr, and new ones issued after 1hr under
+ OpenSSL. GnuTLS 2hr, appears to not do overlap).
+
+ There is a question-mark over the security of the Diffie-Helman parameters
+ used for session negotiation. TBD. q-value; cf bug 1895
+
+Observability:
+ New log_selector "tls_resumption", appends an asterisk to the tls_cipher "X="
+ element.
+
+ Variables $tls_{in,out}_resumption have bits 0-4 indicating respectively
+ support built, client requested ticket, client offered session,
+ server issued ticket, resume used. A suitable decode list is provided
+ in the builtin macro _RESUME_DECODE for ${listextract {}{}}.
+
+Issues:
+ In a resumed session:
+ $tls_{in,out}_cipher will have values different to the original (under GnuTLS)
+ $tls_{in,out}_ocsp will be "not requested" or "no response", and
+ hosts_require_ocsp will fail
--------------------------------------------------------------