[exim] Exim 4.77 and understanding DKIM signature verificati…

Top Page
Delete this message
Reply to this message
Author: Michael J. Tubby B.Sc G8TIC
Date:  
To: exim-users
Subject: [exim] Exim 4.77 and understanding DKIM signature verification and DKIM ACL
All,

I haven't put in much of an appearance here for a couple of years, but a
long time ago Peter Bowyer and myself built a mail relay system, its
been running Exim 4.63 for years on Fedora 6 and I've just come to do a
major upgrade on it and replace it with Exim 4.77 and Ubuntu 12.4 LTS
server.

We had experimental DomainKeys on the old system and I've replaced it
with Exim's in-built DKIM and I'm having some trouble getting my head
around the way it works, or more precisely, the way it confuses me...

What I am trying to do:

     a) accept messages that are correctly signed
     b) reject (deny) messages that are incorrectly signed
     c) defer for messages that are signed but we can't verify them for 
a transient reason (eg. can't reach their DNS)
     d) accept all messages that have no signature
     e) maintain sufficient information in the logs so that I can 
understand what is going on



What I have:

     * Pentuim 4 2.8GHz server, 1Gb RAM, 250Gb HDD
     * Ubuntu 12.4 LTS Server (Beta2)
     * Exim-4.77 built from source with experimental SPF, SRS, DKIM, 
MySQL and a few other bits and pieces
     * latest ClamAV, SpamAssassin, etc.




Here is my current config pertaining to the DKIM parts:


# mysql table with things like paypal.com, ebay.com, google.com etc.
SELECT_DKIM_KNOWN_SIGNERS = select domain from dkim_known_signers where
active=1;
DKIM_KNOWN_SIGNERS = ${lookup
mysql{SELECT_DKIM_KNOWN_SIGNERS}{${sg{$value}{\\n}{ : }} }}

# list of signers we should attempt to verify
dkim_verify_signers = $dkim_signers : $sender_address_domain :
DKIM_KNOWN_SIGNERS


acl_check_dkim:

         #
         # debugging
         #
         warn    logwrite = DKIM TEST: domain=$sender_address_domain 
possible_signer=$dkim_cur_signer status=$dkim_verify_status 
reason=$dkim_verify_reason


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


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


         #
         # skip DKIM checks on authenticated hosts (that we also relay for)
         #
         accept  authenticated = *
                 logwrite = 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
                 logwrite = DKIM DEFER: domain=$sender_address_domain


         #
         # deny when message fails signature test
         #
         deny    dkim_status = fail
                 message = Message from $sender_address_domain has 
invalid DKIM signature
                 logwrite = DKIM DENY: domain=$sender_address_domain


         #
         # accept the message (correctly signed)
         #
         accept
                 sender_domains = $sender_address_domain
                 dkim_signers = $sender_address_domain
                 dkim_status = pass
                 logwrite = DKIM MATCH: 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 anything else
         #
         accept
                 # debugging
                 logwrite = DKIM DEFAULT: Accept at end of ACL: 
domain=$sender_address_domain




I see some discrepancies between documented and actual behaviour (and
what I expected or would like to see :-)

Exim's documentation (Chapter 54 section 2) states: "Verification of
DKIM signatures in incoming email is implemented via the acl_smtp_dkim
ACL. By default, this ACL is called once for each syntactically(!)
correct signature in the incoming message."

If I leave $dkim_verify_signers set to default ($dkim_signers) and I
receive a signed mail message then I see what I would expect:

2012-04-14 07:18:07 1SIwJD-0000k1-3k DKIM: d=mail.dealcloud.co.uk s=key1
c=relaxed/relaxed a=rsa-sha1 i=deals@??? [verification
succeeded]
2012-04-14 07:18:07 1SIwJD-0000k1-3k DKIM START:
domain=xpressus.emarsys.net signer=mail.dealcloud.co.uk status=pass reason=
2012-04-14 07:18:07 1SIwJD-0000k1-3k DKIM ACCEPT:
domain=xpressus.emarsys.net signer=mail.dealcloud.co.uk status=pass
2012-04-14 07:18:07 1SIwJD-0000k1-3k DKIM START:
domain=xpressus.emarsys.net signer=deals@???
status=pass reason=
2012-04-14 07:18:07 1SIwJD-0000k1-3k DKIM ACCEPT:
domain=xpressus.emarsys.net signer=deals@??? status=pass

the above example appears to have two signatures and the ACL is called
twice, both signers pass and on both occasions the ACL returns accept
before reaching the bottom.


However, if I set $dkim_verify_signers to the compound list
(dkim_verify_signers = $dkim_signers : $sender_address_domain :
DKIM_KNOWN_SIGNERS) then the DKIM ACL gets called even when Exim has not
generated its initial "DKIM: d= s= c= a= i= [status]" message (that
it generates when it detects a signature) - here it is doing it:

2012-04-14 21:08:51 CONNECT: New connection from 194.25.134.18:38422 -> 25
2012-04-14 21:08:53 CONNECT: Accepting connection from: 194.25.134.18 as
not blocked by any DNSRBL
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=t-online.de status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=ebay.com status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=paypal.com status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=paypal.co.uk status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=ebay.co.uk status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=yahoo.com status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=yahoo.co.uk status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=gmail.com status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=googlemail.com status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM TEST: domain=t-online.de
possible_signer=google.com status=none reason=
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ DKIM DEFAULT: Accecpt at end of
ACL: domain=t-online.de
2012-04-14 21:08:53 1SJ9HB-0003S3-CZ MIME: Checking status: 1

so, it iterates over all of the entries in $dkim_verify_signers and
*not* all of the signatures in the email (since there are none) - is
this not a bug - I can't see the point of the ACL being called for the
contents of $dkim_verify_signers ?

Next, for the testing that I think that I want to do I'm trying to find
the first definite 'accept' (good signature) or 'deny' (bad signature)
and bail out of the ACL checking for the message at that point. I can't
see the point in carrying on calling the ACL when we know we want to
bail out - I think what is needed is a bit like a "no_more" when
routing, for example:

         deny    dkim_status = fail
                 message = Message from $sender_address_domain has 
invalid DKIM signature
                 logwrite = DKIM DENY: domain=$sender_address_domain
                 no_more    // return 'deny' and exit the DKIM ACL 
altogether



One of the conditions that I'm not sure how we resolve (or even it it
ever happens) is what we do if there are two signatures on an incoming
message and one is good (pass) and one is bad (fail) - but I guess this
is down to the ACL creator ;-)



Mike