Re: [exim-dev] DKIM Signing and renewing DKIM certificates

Top Page
Delete this message
Reply to this message
Author: Ryan Castellucci
Date:  
To: Exim Dev
Subject: Re: [exim-dev] DKIM Signing and renewing DKIM certificates
FWIW, I have the script I use (runs from cron.daily) for daily DKIM
rotation
with AWS Route53 up as a gist here:

https://gist.github.com/ryancdotorg/a8f565b9e4f0902eb7b5cd4cdefeea0f

PLEASE NOTE: This script publishes the private keys after the selectors
are
no longer valid to avoid giving sent email any long-term non-repudiation
properties. If you don't understand what this means, please do not use
as-is.

I'm providing the script here as an example of automated key rotation
using
an API rather than advocating my specific key rotation strategy.

On 2020-11-01 10:20, Mark Elkins via Exim-dev wrote:
> Thank you for the comprehensive reply. OK - so this tells me that
> receiving MTA's will look for a DKIM record with correct selector
> (taken from the received email) and simply use that. There can
> therefore only ever be one record with that selector (I re-watched
> Highlander last night - There can only be One). If there are multiple,
> the MTA may not check that any one of the replies works (as opposed to
> DNSSEC - where any one chain that works means Success).
>
> Thus one should use a selector which must be unique in the DNS to
> specify the Key that the originating/signing MTA used.
>
> So the Keys should change once a month (as an example of good key
> management).
>
> Does Exim know the current month? Is there a Variable for the current
> month in Exim? (Can I run the unix 'date' command to get the month?)
>
> Could I then use something like...
>
> dkim_selector = $Month
>
> (I'd assume that EXIM works on UTC time, does it?)
>
> If so - then I simply create new DKIM Keys for the domain say on the
> 24th of every month for the following month (and put the necessary
> into the DNS) and then around the 8th of the month, do a clean-up of
> old information. Just need to check that any new domains that appear
> after the 24th are appropriately taken care of, such as, create this
> and next months DKIM keys.
>
> dkim_selector = $Month
> ... is simply way more readable than....
> dkim_selector = ${sg{${sg{${lookup
> {$dkim_domain}cdb{CDBMAILTABLES/dkim.selectors.hermes.cdb}
> {$value}{OOPS}}}{\N=\w+\N}{}}}{\N\s+\N}{:}}
>
> Having a selector of YYYYMM would also work for me - and provide a
> better History.
>
> ps - it was a cut'n'paste plus anticipation that put a double '_'
> into my previous email. I only really have one '_'.
>
> On 2020/11/01 01:10, Phil Pennock via Exim-dev wrote:
>> On 2020-10-31 at 18:34 +0200, Mark Elkins via Exim-dev wrote:
>>> [quoting:]
>>> Of course, when you change your DKIM key pair, the public key in the
>>> DKIM
>>> record needs to be changed as well.
>>
>> That is very poorly phrased.
>>
>> One selector corresponds to one DNS record. There is no way to safely
>> change the public key in a given selector's DNS record: there will
>> always be races.
>>
>> If you wish to change the public key, then you use a new selector.
>>
>> Anyone advocating for changing which key one selector corresponds to,
>> without a major downtime/rest-period between values, does not
>> understand
>> distributed caching or distributed coherency. If you read such
>> advice,
>> run away from it.
>>
>> You pre-publish the new selector and wait for at least the zone SOA's
>> TTL field to expire: this is because if you use a predictable naming
>> scheme, then someone could pre-populate caches with the NXDOMAIN for
>> your new record, so you need to wait for negative cache entries to
>> expire.
>>
>> Once your public key has been in DNS, in the new selector, for longer
>> than the previous update's SOA record's TTL, it's safe to start using.
>>
>> You then need to wait for long enough for all mails stuck in queues
>> elsewhere to make their way through, for the validation to happen.
>>
>>>     create the domain.pem & domain.pub parts, create and publish the
>>>     DKIM DNS record with the PUB data as "mail.__domainkey" (where
>>>     "mail" is my selector).

>>
>> No, single underscore for "_domainkey", not two.
>>
>> [snip system based upon poorly worded advice]
>>> Is this fine?
>>
>> No.
>>
>>> If I have to have a different selector for a new DKIM key pair - and
>>> I'm
>>> signing about 40 domains - is there a suggested way to manage the
>>> currently
>>> hard coded line in exim.conf of:-
>>
>> There are two fundamental approaches to rotating selectors:
>>
>> 1. Date-stamp
>> 2. Set of candidates (typically three)
>>
>>
>> ### Date-stamp
>>
>> I use the date-stamp approach: if this were coming with a From: of my
>> spodhuis.org domain, it would be dual-signed with the "d202008" and
>> "d202008e2" selectors (RSA, Ed25519). A week from today, as the first
>> Saturday of "every three months", I have a calendar reminder to go
>> ahead
>> and generate the d202011 family of keys for my domains, and publish
>> them
>> in DNS. Then on Monday, I should go ahead and switch the selector
>> used
>> by Exim for signing email.
>>
>> As a very complicated example, the SMTP Transport in Exim has:
>>
>>    dkim_domain   = ${domain:$acl_m_dkim_sender_address}
>>    # CDB has: domain.tld: dYYYYMM=rsa dYYYYMMe2=ed25519
>>    dkim_selector = ${sg{${sg{${lookup 
>> {$dkim_domain}cdb{CDBMAILTABLES/dkim.selectors.hermes.cdb} 
>> {$value}{OOPS}}}{\N=\w+\N}{}}}{\N\s+\N}{:}}
>>    dkim_private_key = ${if 
>> eq{$dkim_selector}{OOPS}{false}{DKKEYDIR/${extract{$dkim_selector}{${lookup 
>> {$dkim_domain}cdb{CDBMAILTABLES/dkim.selectors.hermes.cdb}}}}.private.$dkim_selector.$dkim_domain}}
>>    dkim_strict   = ${if eq{$dkim_selector}{OOPS}{0}{1}}
>>    dkim_sign_headers = SPODHUIS_DKIM_SIGNHEADERS
>> # timestamps are Exim 4.92+; seconds to add to current time; 2 weeks 
>> == 1209600 seconds
>>    dkim_timestamps = 1209600

>>
>> This is way overkill for you, but that's about as complicated as it
>> gets, and that's handling extracting two different selectors from the
>> value of a CDB lookup. Very _very_ few people dual-sign with two
>> algorithms. You can write something simpler.
>>
>>
>> ### Set of candidates
>>
>> I don't use this, but you see this used by mail service providers who
>> provide mail-sending for various companies, where they want to be able
>> to DKIM sign for their customers.
>>
>> The MSP declares that three selectors may exist; to avoid the risk of
>> collisions, the sensible ones use a prefix which varies by MSP. Thus
>> Fastmail have "fm1", "fm2", "fm3". Mailchimp uses "k1", "k2", "k3".
>> (Some providers willing to vary selector per-customer let the customer
>> choose the selectors).
>>
>> Assume "x1"/"x2"/"x3":
>>
>>   1. Your customer sets up CNAMEs for all three inside their domain, 
>> so
>>      that they have to touch DNS once, to set up the CNAMEs, then 
>> never
>>      have to change DNS again.  You can rotate freely without having 
>> to
>>      coordinate with different DNS zones.
>>   2. You start with x1.  You publish it.  You use s=x1 in the DKIM
>>      signatures.  Leave x1/x2 empty, perhaps a TXT record `""`.  As 
>> long
>>      as no mails are sent using those selectors, no validators will 
>> look
>>      them up in DNS, so you don't need to care.  Just have something 
>> so
>>      that DNS control panels which check for "something exists for 
>> this
>>      CNAME" won't make life hard for your customers.
>>   3. Later, you publish x2 in DNS.  After a TTL wait, you can start 
>> using
>>      s=x2 in signatures.
>>   4. You leave x1 in DNS.  Let older signatures continue to validate.
>>   5. Somewhere between "some time later" and "when you publish x3", 
>> you
>>      stop publishing x1 in DNS.  Signatures made with that will no 
>> longer
>>      validate.
>>   6. You publish x3.  You unpublish x1 if it's still published.  
>> Follow
>>      the usual dance.
>>   7. After x3, circle back around to x1.

>>
>> The three selectors form a ring, which conceptually have pointers:
>> "previous", "current", "next". Only "current" has to exist normally;
>> "previous" should be left existing for some time afterwards. (Maybe
>> two
>> weeks, maybe three months, it depends upon your rotation frequency).
>> "next" should exist for a DNS zone SOA TTL period, or longer, before
>> it
>> becomes the current.
>>
>>
>> You should not ever try to change the key which an actively used
>> selector is pointing to. The ring approach provides a compromise to
>> avoid the number of changes needed in DNS: there are static CNAMEs
>> from
>> the various zones to your published records. The date-stamped
>> approach
>> means that things never expire, and if someone years later tries to
>> figure out "wait, why doesn't this signature validate" on a leaked
>> email, they can see the datestamp and know that it was probably
>> withdrawn.
>>
>> -Phil
>>
>
> --
> Mark James ELKINS  -  Posix Systems - (South) Africa
> mje@???       Tel: +27.826010496 <tel:+27826010496>
> For fast, reliable, low cost Internet in ZA: https://ftth.posix.co.za
> <https://ftth.posix.co.za>