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

Top Page
Delete this message
Reply to this message
Author: Phil Pennock
Date:  
To: mje
CC: Exim Dev
Subject: Re: [exim-dev] DKIM Signing and renewing DKIM certificates
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