On 06/11/2020 11:53, Mark Elkins via Exim-users wrote:
I've got the following in exim.conf....

acl_check_dkim:
    deny dkim_status = fail
            message = DKIM validation failed: $dkim_verify_status
            log_message = DKIM validation failed: $dkim_verify_status \
                (address=$sender_address, domain=$dkim_cur_signer), \
                signature is bad
    defer dkim_status = invalid
            message = DKIM signature invalid: $dkim_verify_status
            log_message = DKIM signature invalid: $dkim_verify_status \
                (address=$sender_address, domain=$dkim_cur_signer), \
                invalid signature
    # NOTE: dkim_status = none should never happen in this ACL
    accept
            # Add an X-DKIM header to the message
            add_header = :at_start: X-DKIM: DKIM validation passed: \
                (address=$sender_address domain=$dkim_cur_signer), \
                signature is good
            logwrite = DKIM validation passed

This is breaking some of my customers...
How can I soften the blow? - so they can get their incorrectly signed emails from these broken servers (some of which live in my countries banking system and are otherwise completely valid)

I've got something similar for SPF....

# SPF Checks
acl_check_mail:

  # SPF validation
  deny spf = fail : softfail
          message = SPF validation failed: \
                  $sender_host_address is not allowed to send mail from \
                  ${if def:sender_address_domain \
                      {$sender_address_domain}{$sender_helo_name}}
          log_message = SPF validation failed\
                  ${if eq{$spf_result}{softfail} { (softfail)}{}}: \
                  $sender_host_address is not allowed to send mail from \
                  ${if def:sender_address_domain \
                      {$sender_address_domain}{$sender_helo_name}}
  deny spf = permerror
          message = SPF validation failed: \
                  syntax error in SPF record(s) for \
                  ${if def:sender_address_domain \
                      {$sender_address_domain}{$sender_helo_name}}
          log_message = SPF validation failed (permerror): \
                  syntax error in SPF record(s) for \
                  ${if def:sender_address_domain \
                      {$sender_address_domain}{$sender_helo_name}}
  defer spf = temperror
          message = temporary error during SPF validation; \
                  please try again later
          log_message = SPF validation failed temporary; deferred
  # Log SPF none/neutral result
  warn spf = none : neutral
          log_message = SPF validation none/neutral

  # Use the lack of reverse DNS to trigger greylisting. Some people
  # even reject for it but that would be a little excessive.

  warn condition = ${if eq{$sender_host_name}{} {1}}
       set acl_m_greylistreasons = Host $sender_host_address \
           lacks reverse DNS\n$acl_m_greylistreasons

  accept
          # Add an SPF-Received header to the message
          add_header = :at_start: $spf_received
          logwrite = SPF validation passed

I think I have to allow this sort of stuff through for now - but would love it to come through with readable error messages for now - give people a chance to fix their errors.




Many suggest that DKIM be used as part of wider DMARC and with layered policy and the equivalent of 'soft fail' etc. however I developed my DKIM support and processing very early on, i.e. early days of DKIM and before DMARC, hence I have an implementation with our company policy baked in.

We support several hundred domains and everything has a MySQL backend.  Mail processing is shared between three front-end relay boxes [relay1, relay2 and relay3] with two on one site and one on a different site which gives us server, site and power resilience. Relay1 is the primary and holds the master database rel2 and rely3 replicate from it.

We have the concept of 'known signers' - these are sites (domains) that we know correctly sign and therefor we can hard enforce, for example:

MariaDB [relay]> select * from dkim_known_signers limit 15;
+------+--------+------------------+
| id   | active | domain           |
+------+--------+------------------+
|    1 |      1 | ebay.com         |
|    3 |      1 | paypal.com       |
|    4 |      1 | paypal.co.uk     |
|    2 |      1 | ebay.co.uk       |
|    5 |      1 | yahoo.com        |
|    6 |      1 | yahoo.co.uk      |
|    7 |      1 | gmail.com        |
|    8 |      1 | googlemail.com   |
|    9 |      1 | google.com       |
|   10 |      1 | facebook.com     |
|   11 |      1 | facebookmail.com |
|   12 |      1 | fwd.facebook.com |
|   13 |      1 | spc.facebook.com |
|   14 |      1 | googlegroups.com |
|   15 |      1 | groups.io        |
+------+--------+------------------+

We have the concept of 'whitelisted domains' - ones we will allow in with broken DKIM (and potentially other broken stuff).


Our policy can be described:

    if you are known good signer - test for good signatures only - drop everything else

    if you are white listed, let you in with bad signatures

    if you are neither 'known signer' or 'whitelisted' and have a signature treat it at face value:
            pass => let you in
            invalid => can't get public key => defer
            fail => reject

    if you don't have a signature, let you in

To get a sample of what's going on out there, Relay1 writes back all the DKIM it sees to the database - this gives us an insight into what's failing and why.  We find house-hold names with misconfigured servers including Microsoft, Amazon, HSBC, Plenty-of-Fish, Capita and government departments.

In every case that I have investigated from our capture database there has been a genuine problem at the other end.

You might care to pick some bits out of my DKIM ACL (below).


Mike





DKIM_WHITELIST_DOMAINS = select domain from dkim_whitelist_domains
domainlist dkim_whitelist_domains = ${lookup mysql{DKIM_WHITELIST_DOMAINS}{${sg{$value}{\\n}{ : }} }}

DKIM_KNOWN_SIGNERS = select domain from dkim_known_signers where active=1;
domainlist dkim_known_signers = ${lookup mysql{DKIM_KNOWN_SIGNERS}{${sg{$value}{\\n}{ : }} }}




###
### acl_check_dkim: this ACL is used for checking DKIM
###

#
# acl_m2 set to zero on start for normal/full checks, set to 1 if white-listed domain
#

acl_check_dkim:

        #
        # start of DKIM debug message and clear macro
        #

        #
        # Only do MySQL INSERT on Relay1 !!!
        #
        warn    set acl_m_dummy = ${lookup mysql{INSERT INTO dkim_log (status,reason,host,domain,identity,selector,algo) VALUES ('${quote_mysql:$dkim_verify_status}', '${quote_mysql:$dkim_verify_reason}','${quote_mysql:$sender_fullhost}', '${quote_mysql:$dkim_domain}', '${quote_mysql:$dkim_identity}', '${quote_mysql:$dkim_selector}', '${quote_mysql:$dkim_algo}' )}}                 log_message = DKIM START: domain=$sender_address_domain possible_signer=$dkim_cur_signer status=$dkim_verify_status ${if def:dkim_verify_reason {(reason=$dkim_verify_reason)

        #
        # strict checking on known signers...
        #
        deny    sender_domains = +dkim_known_signers
                dkim_status = none:invalid:fail
                message = Message from $sender_address_domain (known signer) with invalid or missing signature                 log_message = DKIM DENY: Rejected $sender_address_domain is known signer (in database) but has invalid/missing signature

        accept  sender_domains = +dkim_known_signers
                dkim_status = pass
                log_message = DKIM PASS: Accepted $sender_address_domain is known signer and has good signature                 add_header = :after_received:X-DKIM-Result: Domain=$sender_address_domain Result=Good and Known Domain

        #
        # ignore noise where we have no signature
        #
        accept  dkim_status = none
#               log_message = DKIM SKIP: Skipping DKIM checks - no signature for: $dkim_cur_signer

        #
        # skip DKIM if domain whitelisted for DKIM, i.e. known good domain that has broken DKIM
        #
        accept  sender_domains = +dkim_whitelist_domains
                log_message = DKIM SKIP: Skipping DKIM checks for whitelisted domain: $sender_address_domain
                set acl_m2 = 1

        #
        # skip DKIM checks on hosts we relay for
        #
        accept  hosts = +relay_from_hosts
                log_message = DKIM SKIP: Skipping DKIM checks for relay host: $sender_fullhost

        #
        # skip DKIM checks on authenticated hosts (that we also relay for)
        #
        accept  authenticated = *
                log_message = DKIM SKIP: Skipping DKIM checks for authenticated host: $sender_fullhost

        #
        # defer when message not testable, e.g. can't get public key, etc.
        #
        defer   dkim_status = invalid
                message = Message from $sender_address_domain cannot be verified                 log_message = DKIM DEFER: domain=$sender_address_domain cannot obtain public key

        #
        # accept the message (correctly signed)
        #
        accept  dkim_status = pass
                sender_domains = $sender_address_domain
                dkim_signers = $sender_address_domain
                log_message = DKIM PASS: domain=$sender_address_domain signer=$dkim_cur_signer status=$dkim_verify_status                 add_header = :after_received:X-DKIM-Result: Domain=$sender_address_domain Result=Signature OK

        #
        # accept the message EVEN IF the signature FAILS! due to white listing
        #
        accept  condition = ${if eq {$acl_m2}{1}}
                dkim_status = fail
                sender_domains = $sender_address_domain
                dkim_signers = $sender_address_domain
                log_message = DKIM FAIL (BUT WHITELISTED): domain=$sender_address_domain status=$dkim_verify_status - DKIM failed but message accepted                 add_header = :after_received:X-DKIM-Result: Domain=$sender_address_domain Result=FAIL (but whitelisted)

        #
        # deny (strict) when message fails signature test *and* acl_m2 = 0 (not whitelisted)
        #
        deny    condition = ${if eq {$acl_m2}{0}}
                dkim_status = fail
                sender_domains = $sender_address_domain
                dkim_signers = $sender_address_domain
                message = Message from has invalid DKIM signature
                log_message = DKIM FAIL (DENY): domain=$sender_address_domain - message rejected!

        #
        # accept anything else (should never get here)
        #
        accept  log_message = DKIM DEFAULT: domain=$sender_address_domain - message accepted (at end of ACL)












--
## List details at https://lists.exim.org/mailman/listinfo/exim-users
## Exim details at http://www.exim.org/
## Please use the Wiki with this list - http://wiki.exim.org/

Reply via email to