Wednesday, June 9, 2010

HOWTO define DKIM/ADSP RRs

SkyHi @ Wednesday, June 09, 2010

DomainKeys Identified Mail (DKIM) has a similar goal to SPF in that it provides a way for mail recipients to verify that mail, purporting to come from domain X (and possibly user Y), did, indeed, come from domain X (and possibly user Y). DKIM works by having one, or more, sending or handling mail agent(s) (MUA/MTA) cryptographically sign the mail (by adding a DKIM-Signature header to each mail item). Any receiving (or intermediate mail handling) MTA/MUA can authenticate the source of the mail and optionally add an Authenticated-Results header (defined in RFC 5451). DKIM mail signing uses public-key (or asymmetric) cryptography to create digital signatures covering defined mail headers and/or the mail body. The public key(s) used in signature verification are stored in the DNS in DKIM TXT RRs (described below).

If, like most normal humans, you are cryptographically challenged then you might find our crypto primer useful. Then again you may not.

In addition to the DKIM TXT RR, the DKIM specifications allows the domain owner to define an Author Domain Signing Policies (ADSP) TXT RR which essentially provides advice to the validating mail receiver about what to do if a mail item is not signed.

DKIM is defined by a series of RFCs of which RFC 4871 and RFC 5672 define the DNS DKIM TXT RR format (as well as the added mail headers), RFC 5617 defines DNS Author Domain Signing Policies (ADSP) TXT RR formats for indicating signing practises and RFC 5585 describes how it all works. Serious stuff - if somewhat wordy.

Only that part of DKIM concerned with the DNS is described here. It is beyond the scope of this document to detail all the functionality offered by DKIM and readers are advised to consult the various listed RFCs for all the gory details. We make the following observations from the RFCs:

  1. DKIM uses "identifiers" (typically an email address or just a domain name) not IP addresses (unlike SPF) as its base for authentication. Mail content is verified not the path it takes.

  2. Clearly bad guys could equally use DKIM to sign their email. The various DKIM RFCs emphasize that DKIM only authenticates the mail source and needs to be used in conjunction with, say, a whitelist (or other reputation system) to allow decisions to be made about accepting or rejecting DKIM signed mail.

  3. DKIM does not provide mail confidentiality (encryption).

  4. DKIM digital signatures can, optionally, be used to provide mail integrity.

  5. DKIM does not require purchase of SSL certificates. The public keys are obtained directly from the DNS of the authenticating domain and may be generated using Open Source (or other) tools.

Whether the above points are positive or negative will depend entirely on the implementor's context and requirements.

Many of the values in the DKIM TXT RR will depend on those defined for the mail signer software. While creating this documentation we used OpenDKIM as a reference source which supports sendmail and postfix through the milter interface. Many other DKIM implementations exist and you are advised to carefully read your mail system's DKIM documentation.

A number of major email organization have already implemented DKIM, perhaps most notably google's gmail.

DKIM DNS RR Format

DKIM uses (at the present time) a TXT RR to contain all the DNS stored data. The generic format of the TXT RR is:

name  ttl  class   rr     text

DKIM TXT RR Format - Name

There may be one or more DKIM TXT RRs for any given domain. The generic name format for the DKIM TXT RR is:

name  ttl  class   rr     text
;DKIM TXT RR format is
selector._domainkey ttl class rr DKIM-specific-text

The content of the DKIM-specific-text field is defined below. The name of each TXT RR used to contain DKIM data must match that constructed by the validating email receiver which extracts values contained in the DKIM-Signature mail header field. Specifically, the validating email receiver will construct this name by extracting the selector (s= tag-value field, defined in RFC 4871 Section 3.5), appending the fixed subdomain name _domainkey and finally appending the extracted domain name (d= tag-value field, defined in RFC 4871 Section 3.5).

The selector is, in essence, a unique and relatively arbitrary tag whose purpose/format is defined in RFC 4871 Section 3.1.

DKIM Scope and Selectors

While it was noted above that description of the full functionality of DKIM is beyond the scope of this document an understanding of the delegation concept, its scope and relationship to the selector field is required to fully understand some of the fields that populate the DKIM DNS RR(s). What follows is our attempt to explain this concept insofar as it relates to the use of the DKIM TXT RR.

In part, the relative complexity of DKIM relates to the designers' objective to allow mail from any domain to be handled by various parties, for example, while user@example.com may normally send mail through a company mail service (MTA) the same user, using the same email address may also wish to send mail from home via an ISP's MTA. Equally, bulk mailing may be delegated to an external third party. Other such scenarios may be imagined. In all such scenarios DKIM allows for one, or more, third parties to be delegated the signing responsibility for some, or all, of the mail using a particular domain name.

Configuring DKIM could be done by the domain owner generating a DKIM public-private key pair for use with one or more mail addresses or subdomains, supplying the private key to the delegated signer and publishing the public key in a DKIM TXT RR in the domain's zone file under a suitable name. Conversely, the delegated signer could generate the DKIM public/private key pair and supply the public key to the domain name operator for inclusion in a DKIM TXT RR under a suitable name.

So just what is the suitable DKIM TXT RR name? This problem is solved using the selector field (s= in DKIM-Signature header) and the domain field (d= in the DKIM-Signature mail header). The suitable name is computed by the validating receiver as described above. Thus if the selector in the DKIM-Signature mail header (s=) is joe and the domain name (from the d= field of the DKIM-Signature mail header) is example.com then the constructed query name will be joe._domainkey.example.com This is a relatively trivial illustration and a number of additional examples are provided. By querying the originating domain's DNS using the constructed name a validating receiver can obtain information including, crucially, the public key to be used to authenticate the mail.

By default the signer will sign mail for the domain and all its subdomains - meaning that a single DKIM TXT RR can be created to cover the entire domain. Mail sent from user@example.com and user@sub.example.com will use the same selector and hence use the same key.

Where the domain owner wishes to use unique keys for subdomains (or where subdomains are known not to exist) the domain owner should set the 's' flag of the t= tag in the DKIM TXT RR for the domain. In this case separate DKIM TXT RRs (and ADSP RRs) will be required for each subdomain that can send mail (See Examples).

DKIM TXT RR Format - Text

The text part of the DKIM TXT RR can contain a number of semi-colon (;) separated tag=value fields (defined in RFC 4871 Section 3.6.1). The following section documents the allowed tags and values (a number of examples are provided to show scenario specific RR values).

Note: DKIM uses a tag=value notation to define fields in both the DKIM-Signature header and the DNS TXT RR text field. Somewhat confusingly, in a number of cases the tag name part, such as v= or s=, will take the same value for both the DKIM-Signature mail header and the DNS RR. In some case the meaning will be the same but the valid values may be different, in other cases the meaning of the tag is different for each entity. Readers are advised to ensure they consult the correct section of the specification. Specifically for DKIM-Signature mail header tag=value pairs use RFC 4871 Section 3.5 (updated by RFC 5672) and for DNS TXT RR tag=value pairs use RFC 4871 Section 3.6.1.

v= (version)
Optional. Defines the DKIM version number and may only (at this time) take the (defaulted) value DKIM1. While it may be safely omitted our advice is to include it.
v=DKIM1;
g= (granularity)
Optional. Granularity defines the range of user (local) part of the email (everything to the left hand side of the @) to which this DKIM TXT RR applies. A single wild card (*) value may be used anywhere in the field. Defaults to g=*(all user - local - part addresses match). This value (after any wild card processing) must exactly match the mail From: user (local) part. The only case we have seen where it could make some sense is if you have a single email address in the domain. Doubtless there are other cases. However, assuming you are not doing anything too fancy (good luck if you are) it may be safely omitted.
# single email address form
g=joe;
# partial wild card form
g=*-maillist;
# default form - everything
g=*;
h= (hash algorithm)
Optional. Defines one or more colon (:) separated hash (digest) algorithms that will be used for the purpose of creating digital signatures (in conjunction with k= below) covering either or both of the defined mail headers or the mail body (including, optionally, MIME attachments). Allowable values are from the set sha1 and sha256. Default is h=* (all). Since all implementations of DKIM are mandated to support both sha1 and sha256 hash (digest) algorithms it may be safely omitted.
h=sha1:sha256;
h=*;
k= (key type)
Optional. Defines the public key algorithm being used. Defaults to k=rsa. Since rsa is the only algorithm currently supported it may be safely omitted.
k=rsa;
n= (notes)
Optional. Defines human readable (text) than may be used by validating receiver administrators. Unless this imparts significant, perhaps world-stopping, knowledge it may be safely omitted.
n=Don't trust these guys;
p= (public key material)
Defines the public key (in base64 text format) for the algorithm defined by the k= tag whose private key was used to digitally sign user defined parts of the mail item. The data for the public key may be created by openssl using the following command sequence (taken from RFC 4871 Appendix C and reproduced here only for convenience):
# Create the RSA public private key pair
# in dkim.private with a key length of 1024 bits
openssl genrsa -out dkim.private 1024

openssl rsa -in dkim.private -out dkim.public -pubout -outform PEM
# extracts the public key (in base 64 format to file dkim.public
# in PEM (Privacy Enhanced Mail) format which looks like this:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkM
oGeLnQg1fWn7/zYtIxN2SnFCjxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/R
tdC2UzJ1lWT947qR+Rcac2gbto/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToI
MmPSPDdQPNUYckcQ2QIDAQAB
-----END PUBLIC KEY-----

Remove the lines beginning with "-" and edit the remaining text in any of the following formats (most key material replaces with ' ... ' for brevity):

; single line format
name._domainkey IN TXT "v=DKIM1;p=MIGfMA0G ... cQ2QIDAQAB"

; multi-line format
name._domainkey IN TXT ("v=DKIM1"
"p=MIGfMA0G ... "
"oGeLnQg ... "
"tdC2UzJ1lW ... "
"MmPSPDdQPNUYckcQ2QIDAQAB")

See TXT RR for additional information on layout and formatting of text.

If a key is to be revoked (declared invalid) then setting the p= tag to a null value will achieve this:

p=;
s= (service type)
Optional. Defines the service type to which DKIM is applied. At this time the only valid value is email but clearly the designers had their sights set on greater goals. The default is s=* (all). Since email is, currently, the only DKIM supported service it may be safely omitted.
s=email;
s=*;
t= (flags)
Optional. Defaults to no flags set. A colon (:) separated list of flags to be used by the validator. Two flags are currently defined:
y Indicates test mode. If set it may (hopefully does) generate additional diagnostic messages from the validating receiver, but still permits the validator to treat the mail normally, that is, a validation failure must still be treated as a failure - no validation leniency is implied by setting this flag.
s If defined this flag indicates that this key is not valid for subdomains of the domain name (defined in the d= tag of the DKIM-Signature). This probably makes no sense unless you understood this discussion. And, indeed, may make no sense afterwards either. To inhibit subdomain signing behavior in OpenDKIM you must set SubDomains No.
t=y:s;

A number of worked examples are provided.

ADSP TXT RR Format

The Author Domain Signing Practices (ADSP) TXT RR is designed to allow a domain to indicate its mail signing policies. The ADSP TXT RR is optional but the ADSP policies may be used to assist a validating receiving MTA in determining how to handle mail that is not signed. The format of the ADSP TXT RR is:

name  ttl  class   rr     text
;ADSP TXT RR format is
_adsp._domainkey ttl class rr ADSP-specific-text

Only one ADSP TXT RR per domain may be defined - however each subdomain may also have its own ADSP TXT RR. See examples for more detail.

ADSP TXT RR Format - Text

The ADSP TXT RR text field uses the same tag=value format used throughout DKIM. The allowed tags and their corresponding values are:

Tag Values
dkim= A single value from the following set of permissible values is allowed:
unknown The domain (defined by the d= tag of the DKIM-Signature mail header) does not sign all mail. This is the most common setting during testing, but if used in a production environment will essentially nullify the use of DKIM. Having a domain which, in a production environment, only signs some of its mail is about as useful as watching grass grow IOHO.
all The domain (defined by the d= tag of the DKIM-Signature mail header) signs all mail. This setting leaves the validating receiver free to carry out its own policies if it receives unsigned mail.
discardable The domain (defined by the d= tag of the DKIM-Signature mail header) signs all mail. This is the macho setting because it also advises the validating receiver that unsigned mail should be discarded. The sleepless-nights-for-mail-administrators setting.
dkim=discardable;

Note: There are a number of additional tag=value pairs mentioned in various RFC drafts (which have no official status) and also in OpenDKIM documentation. The most interesting is an r=error-address tag=value pair which defines the local part of an email address to which extended error information may be sent. Thus if r=ouch; is present for the domain example.com then mail regarding any validation failures will be sent to ouch@exmple.com. The precise status (that is, will it work) of this tag=value pair is unknown (Jan 2010).

Examples

All domains are assumed to use the ubiquitous domain example.com unless otherwise stated. The public key material is denoted by blah...blah for simplicity and brevity.

All Mail Signed - One MTA, No Subdomains

The tightest and simplest scenario assumes that all mail for the domain is sent using a single path - typically an in-house MTA. No subdomains are used in email addresses. All the mail is signed and users working from home or remotely will use, say, a webmail interface to the in-house MTA. Email from any other source is deemed to be invalid. A single selector may be used in this instance, which we will call mail since we entirely lack imagination:

; zone example.com fragment
...
mail._domainkey IN TXT "v=DKIM1;t=s;p=blah....blah;"
_adsp._domainkey IN TXT "dkim=discardable;"
; if you like typing you could have written
mail._domainkey.example.com. IN TXT "v=DKIM1;t=s;p=blah....blah;"
_adsp._domainkey.example.com. IN TXT "dkim=discardable;"
; OR you could use an $ORIGIN
$ORIGIN _domainkey
mail IN TXT "v=DKIM1;t=s;p=blah....blah;"
_adsp IN TXT "dkim=discardable;"
; if RRs appear below this $ORIGIN then it will have to be reset

Notes:

  1. The DKIM TXT RR name of mail is entirely arbitrary we could, just as easily, have called it gobbledegook (though that is longer and we can't always spell it correctly) and is the selector for the domain example.com. The selector is defined using either the Selector directive or a KeyTable for OpenDKIM.

  2. Since all mail is signed the _adsp RR uses the super macho discardable value, if you want to be weasely use all or even unknown.

  3. Since the domain does not send mail using any subdomains the t=s flag allows the validating receiver to be tighter in its handling by rejecting any mail from a subdomain. If subdomains are used remove the entire t= tag.

  4. The v=DKIM1; tag could be omitted and will default to the defined value. We believe it is always good practise to indicate which version of any specification you think you are supporting so we have included it. In 5 years no-one will remember. Or, if you are like us, in 2 weeks time no-one will remember.

  5. All other tags are left to their default values (and no notes are supplied!).

Loose DKIM Signing

For use during testing or for those not entirely sure what their mail users actually do - including whether they use subdomains in their mail addresses.

; zone example.com fragment
...
hope._domainkey IN TXT "v=DKIM1;t=y;p=blah....blah;"
_adsp._domainkey IN TXT "dkim=unknown;"
; if you like typing you could have written
hope._domainkey.example.com. IN TXT "v=DKIM1;t=y;p=blah....blah;"
_adsp._domainkey.example.com. IN TXT "dkim=unknown;"
; OR you could use an $ORIGIN
$ORIGIN _domainkey
hope IN TXT "v=DKIM1;t=y;p=blah....blah;"
_adsp IN TXT "dkim=unknown;"
; if RRs appear below, $ORIGIN may have to be reset

Notes:

  1. The DKIM TXT RR name hope is entirely arbitrary we could, just as easily, have called it pray (both names faithfully reflect usage at this stage) and is the selector for the domain example.com. The selector is defined using either the Selector directive or a KeyTable for OpenDKIM.

  2. Since mail may, or may not, be signed the _adsp RR must use the unknown value.

  3. The t=y flag indicates to the validating receiver that we would like as much help as possible (verbose, highly detailed, error messages hopefully) if anything goes wrong with any mail that we do, finally, get around to signing. Since we don't actually know if our users use subdomains it is not safe to use the s flag. If, however, we were positive about this one fact then we could use a flags field of t=y:s; and live dangerously.

Multiple Subdomain DKIM Signing

Assume we send mail from the domain example.com and two subdomains, maillist.example.com (signed by external third party) and secure.example.com (signed using in-house MTA). We always sign mail from the subdomains but not always the main domain.

; zone example.com fragment
...
; DKIM and ADSP TXT RR for main domain
$ORIGIN _domainkey
domain IN TXT "v=DKIM1;t=s;p=blah....blah;"
_adsp IN TXT "dkim=unknown;"
; if other RRs appear below, $ORIGIN may have to be reset

; DKIM and ADSP for maillist subdomain
$ORIGIN _domainkey.maillist
external IN TXT "v=DKIM1;t=s;p=blah....blah;"
_adsp IN TXT "dkim=discardable;"
; if other RRs appear below, $ORIGIN may have to be reset

; DKIM and ADSP for secure subdomain
$ORIGIN secure
internal IN TXT "v=DKIM1;t=s;p=blah....blah;"
_adsp IN TXT "dkim=discardable;"


REFERENCES
http://www.zytrax.com/books/dns/ch9/dkim.html

; if RRs appear below, $ORIGIN may have to be reset

Notes:

  1. The DKIM TXT RRs names domain, external and internal are entirely arbitrary we could, just as easily, have called them alice, bob and uncle-bert and are the selectors for each of the separately signed part of mail from the domain example.com. Note: use of these selector values is partly deliberate to re-enforce the point that there is no necessary relationship between subdomain names and selector names. A single selector is defined in the Selector directive of OpenDKIM or if multiple selectors are required they must be defined in an OpenDKIM KeyTable.

  2. We use $ORIGIN directives in this scenario because we like them and think they make the subsequent definitions much clearer (and shorter as well).

  3. We use the t=s flag in all the DKIM TXT RR definitions because we have explicitly defined a key for use with each used subdomain (only maillist and secure) so explicitly need to notify the validating receiver that each key has no subdomain scope.

  4. Since we have no idea about signing from the main example.com domain (as we defined in scenario description) we use the unknown value, whereas since we know that the maillist and secure domain will always be signed we have used discardable.

  5. When using OpenDKIM in this scenario the values example.com, maillist.example.com and secure.example.com must all appear in either a Domains directive or a SigningTable, in both cases a SubDomains No directive must be used.