RFC 4871
DomainKeys Identified Mail (DKIM) Signatures
RFC 4871: DomainKeys Identified Mail (DKIM) Signatures ๐ฆ (part 1 of 15, more to come!)
Okay bestie, this one's from the Network Working Group and it's dated May 2007 ๐ . Six authors wrote it: E. Allman (Sendmail, Inc.), J. Callas (PGP Corporation), M. Delany and M. Libbey (both Yahoo! Inc), and J. Fenton and M. Thomas (both Cisco Systems, Inc.) ๐. It's on the Standards Track, and it obsoletes RFC 4870 ๐ . The header doesn't list anything it updates.
Status of This Memo ๐
Bestie, this document is an Internet standards track protocol for the whole Internet community, and it's literally asking for discussion and suggestions for improvements ๐ฃ๏ธ. To see where this protocol stands in standardization, check the current edition of the "Internet Official Protocol Standards" (STD 1) ๐. Distribution of this memo is unlimited ๐.
Copyright Notice ยฉ๏ธ
Copyright (C) The IETF Trust (2007).
Abstract โจ
DomainKeys Identified Mail (DKIM) is a domain-level authentication framework for email ๐. It uses public-key cryptography and key server technology so that either Mail Transfer Agents (MTAs) or Mail User Agents (MUAs) can verify the source and contents of messages ๐. The big goal is to let a signing domain take responsibility for a message. That protects the identity of the signer and the integrity of the messages they send, all while keeping Internet email working the way it does today ๐ซถ. Protecting email identity may help with the global control of "spam" and "phishing" ๐ โโ๏ธ.
Table of Contents ๐๏ธ
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1. Signing Identity . . . . . . . . . . . . . . . . . . . . . 5
1.2. Scalability . . . . . . . . . . . . . . . . . . . . . . . 5
1.3. Simple Key Management . . . . . . . . . . . . . . . . . . 5
2. Terminology and Definitions . . . . . . . . . . . . . . . . . 5
2.1. Signers . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2. Verifiers . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3. Whitespace . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4. Common ABNF Tokens . . . . . . . . . . . . . . . . . . . . 6
2.5. Imported ABNF Tokens . . . . . . . . . . . . . . . . . . . 7
2.6. DKIM-Quoted-Printable . . . . . . . . . . . . . . . . . . 7
3. Protocol Elements . . . . . . . . . . . . . . . . . . . . . . 8
3.1. Selectors . . . . . . . . . . . . . . . . . . . . . . . . 8
3.2. Tag=Value Lists . . . . . . . . . . . . . . . . . . . . . 10
3.3. Signing and Verification Algorithms . . . . . . . . . . . 11
3.4. Canonicalization . . . . . . . . . . . . . . . . . . . . . 13
3.5. The DKIM-Signature Header Field . . . . . . . . . . . . . 17
3.6. Key Management and Representation . . . . . . . . . . . . 25
3.7. Computing the Message Hashes . . . . . . . . . . . . . . . 29
3.8. Signing by Parent Domains . . . . . . . . . . . . . . . . 31
4. Semantics of Multiple Signatures . . . . . . . . . . . . . . . 32
4.1. Example Scenarios . . . . . . . . . . . . . . . . . . . . 32
4.2. Interpretation . . . . . . . . . . . . . . . . . . . . . . 33
5. Signer Actions . . . . . . . . . . . . . . . . . . . . . . . . 34
5.1. Determine Whether the Email Should Be Signed and by
Whom . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.2. Select a Private Key and Corresponding Selector
Information . . . . . . . . . . . . . . . . . . . . . . . 35
5.3. Normalize the Message to Prevent Transport Conversions . . 35
5.4. Determine the Header Fields to Sign . . . . . . . . . . . 36
5.5. Recommended Signature Content . . . . . . . . . . . . . . 38
5.6. Compute the Message Hash and Signature . . . . . . . . . . 39
5.7. Insert the DKIM-Signature Header Field . . . . . . . . . . 40
6. Verifier Actions . . . . . . . . . . . . . . . . . . . . . . . 40
6.1. Extract Signatures from the Message . . . . . . . . . . . 41
6.2. Communicate Verification Results . . . . . . . . . . . . . 46
6.3. Interpret Results/Apply Local Policy . . . . . . . . . . . 47
7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 48
7.1. DKIM-Signature Tag Specifications . . . . . . . . . . . . 48
7.2. DKIM-Signature Query Method Registry . . . . . . . . . . . 49
7.3. DKIM-Signature Canonicalization Registry . . . . . . . . . 49
7.4. _domainkey DNS TXT Record Tag Specifications . . . . . . . 50
7.5. DKIM Key Type Registry . . . . . . . . . . . . . . . . . . 50
7.6. DKIM Hash Algorithms Registry . . . . . . . . . . . . . . 51
7.7. DKIM Service Types Registry . . . . . . . . . . . . . . . 51
7.8. DKIM Selector Flags Registry . . . . . . . . . . . . . . . 52
7.9. DKIM-Signature Header Field . . . . . . . . . . . . . . . 52
8. Security Considerations . . . . . . . . . . . . . . . . . . . 52
8.1. Misuse of Body Length Limits ("l=" Tag) . . . . . . . . . 52
8.2. Misappropriated Private Key . . . . . . . . . . . . . . . 53
8.3. Key Server Denial-of-Service Attacks . . . . . . . . . . . 54
8.4. Attacks Against the DNS . . . . . . . . . . . . . . . . . 54
8.5. Replay Attacks . . . . . . . . . . . . . . . . . . . . . . 55
8.6. Limits on Revoking Keys . . . . . . . . . . . . . . . . . 55
8.7. Intentionally Malformed Key Records . . . . . . . . . . . 56
8.8. Intentionally Malformed DKIM-Signature Header Fields . . . 56
8.9. Information Leakage . . . . . . . . . . . . . . . . . . . 56
8.10. Remote Timing Attacks . . . . . . . . . . . . . . . . . . 56
8.11. Reordered Header Fields . . . . . . . . . . . . . . . . . 56
8.12. RSA Attacks . . . . . . . . . . . . . . . . . . . . . . . 56
8.13. Inappropriate Signing by Parent Domains . . . . . . . . . 57
9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 57
9.1. Normative References . . . . . . . . . . . . . . . . . . . 57
9.2. Informative References . . . . . . . . . . . . . . . . . . 58
Appendix A. Example of Use (INFORMATIVE) . . . . . . . . . . . . 60
A.1. The user composes an email . . . . . . . . . . . . . . . . 60
A.2. The email is signed . . . . . . . . . . . . . . . . . . . 61
A.3. The email signature is verified . . . . . . . . . . . . . 61
Appendix B. Usage Examples (INFORMATIVE) . . . . . . . . . . . . 62
B.1. Alternate Submission Scenarios . . . . . . . . . . . . . . 63
B.2. Alternate Delivery Scenarios . . . . . . . . . . . . . . . 65
Appendix C. Creating a Public Key (INFORMATIVE) . . . . . . . . . 67
Appendix D. MUA Considerations . . . . . . . . . . . . . . . . . 68
Appendix E. Acknowledgements . . . . . . . . . . . . . . . . . . 69
1. Introduction โจ
DKIM defines a mechanism where email messages can be cryptographically signed ๐๏ธ. That lets a signing domain claim responsibility for putting a message into the mail stream ๐. Recipients can verify the signature by asking the signer's domain directly for the right public key, and that confirms the message was vouched for by someone holding the private key for the signing domain ๐.
The DKIM approach is different from earlier message signing systems, like Secure/Multipurpose Internet Mail Extensions (S/MIME) [RFC1847] and OpenPGP [RFC2440], and here's how ๐ :
- the signature lives in a message header field, so neither human readers nor existing MUA (Mail User Agent) software gets confused by signature stuff showing up in the body;
- it doesn't depend on public and private key pairs being issued by well-known, trusted certificate authorities;
- it doesn't depend on deploying any new Internet protocols or services for public key distribution or revocation;
- a failed signature verification doesn't force rejection of the message;
- encryption isn't part of the mechanism, no attempt is made there;
- archiving messages isn't a design goal.
And DKIM is also:
- compatible with the existing email infrastructure and as transparent as it possibly can be ๐ซง;
- needs minimal new infrastructure;
- can be implemented independently of clients, so deployment doesn't take forever โฉ;
- can be deployed bit by bit, incrementally;
- allows signing to be delegated to third parties ๐ค.
1.1. Signing Identity ๐ชช
DKIM keeps two questions apart: who the signer of the message is, and who the purported author of the message is. A signature includes the identity of the signer, and verifiers can use that signing info to decide how they want to process the message ๐ง. The signing identity goes in the signature header field.
INFORMATIVE RATIONALE: The signing identity in a DKIM signature isn't required to match an address in any particular header field, because recipient mail systems (MUAs included) interpret things in lots of broad ways.
1.2. Scalability ๐
DKIM is built for the extreme scalability needs of the email identification problem ๐. There are currently over 70 million domains, and a much larger number of individual addresses. DKIM wants to keep the good stuff about today's email infrastructure, like anyone being able to talk to anyone else without an introduction ๐.
1.3. Simple Key Management ๐๏ธ
DKIM is different from traditional hierarchical public-key systems, because no Certificate Authority infrastructure is needed. The verifier asks for the public key from a repository in the claimed signer's domain directly, not from some third party ๐ โโ๏ธ.
The DNS is proposed as the first mechanism for the public keys, so DKIM depends on DNS administration and the security of the DNS system ๐. It's designed to be extensible to other key fetching services as they show up ๐ง.
2. Terminology and Definitions ๐
This section defines the terms used in the rest of the document. Syntax descriptions use the form described in Augmented BNF for Syntax Specifications [RFC4234] ๐งฉ.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be read the way [RFC2119] describes ๐.
2.1. Signers โ๏ธ
Parts of the mail system that sign messages on behalf of a domain are called signers ๐. These can be MUAs (Mail User Agents), MSAs (Mail Submission Agents), MTAs (Mail Transfer Agents), or other agents like mailing list exploders. Generally, any signer gets involved in injecting a message into the message system somehow. The key issue is that a message must be signed before it leaves the administrative domain of the signer ๐ช.
2.2. Verifiers ๐
Parts of the mail system that verify signatures are called verifiers ๐ฆ. These can be MTAs, Mail Delivery Agents (MDAs), or MUAs. Usually, verifiers are expected to sit close to an end user (reader) of the message, or to some consuming agent like a mailing list exploder ๐ธ.
2.3. Whitespace ๐ซถ
okay so whitespace comes in three flavors, bestie ๐
- WSP is the simple one: a space or a tab character (formal definition in [RFC4234]).
- LWSP is linear whitespace, which is WSP plus CRLF (formal definition in [RFC4234]).
- FWS is folding whitespace. It lets multiple lines separated by CRLF, followed by at least one whitespace, get joined together โจ
the formal ABNF for these is below (WSP and LWSP are just for information, ngl):
WSP = SP / HTAB
LWSP = *(WSP / CRLF WSP)
FWS = [*WSP CRLF] 1*WSP
the definition of FWS is basically identical to the one in [RFC2822], except it leaves out obs-FWS. ๐
2.4. Common ABNF Tokens ๐ธ
these ABNF tokens get reused all over the doc, so they're the main characters here ๐
hyphenated-word = ALPHA [ *(ALPHA / DIGIT / "-") (ALPHA / DIGIT) ]
base64string = 1*(ALPHA / DIGIT / "+" / "/" / [FWS])
[ "=" [FWS] [ "=" [FWS] ] ]
2.5. Imported ABNF Tokens ๐ฆ
some tokens get borrowed from other RFCs. those RFCs are the source of truth, so they win if there's any drama ๐
the following tokens are imported from [RFC2821]:
- "Local-part" (implementation warning: this permits quoted strings)
- "sub-domain"
the following tokens are imported from [RFC2822]:
- "field-name" (name of a header field)
- "dot-atom-text" (in the Local-part of an email address)
the following tokens are imported from [RFC2045]:
- "qp-section" (a single line of quoted-printable-encoded text)
- "hex-octet" (a quoted-printable encoded octet)
INFORMATIVE NOTE: heads up, the ABNF in RFC 2045 doesn't follow the rules of RFC 4234, so you have to read it accordingly, especially when it comes to case folding. ๐
everything else that isn't defined here gets imported from [RFC4234]. those are the intuitive basics like SP, HTAB, WSP, ALPHA, DIGIT, CRLF, etc. ๐ง
2.6. DKIM-Quoted-Printable ๐
the DKIM-Quoted-Printable encoding is giving Quoted-Printable [RFC2045], Section 6.7 vibes, but with its own twist. any character MAY be encoded as an "=" followed by two hexadecimal digits from the alphabet "0123456789ABCDEF" (no lowercase characters permitted), representing the hexadecimal-encoded integer value of that character. all control characters (those with values < %x20), 8-bit characters (values > %x7F), and the characters DEL (%x7F), SPACE (%x20), and semicolon (";", %x3B) MUST be encoded. note that all whitespace, including SPACE, CR, and LF characters, MUST be encoded. after encoding, FWS MAY be added at arbitrary locations to avoid super long lines, but that whitespace is NOT part of the value, and it MUST be removed before decoding. ๐ซ
ABNF:
dkim-quoted-printable =
*(FWS / hex-octet / dkim-safe-char)
; hex-octet is from RFC 2045
dkim-safe-char = %x21-3A / %x3C / %x3E-7E
; '!' - ':', '<', '>' - '~'
; Characters not listed as "mail-safe" in
; RFC 2049 are also not recommended.
INFORMATIVE NOTE: DKIM-Quoted-Printable is its own thing and differs from the RFC 2045 Quoted-Printable in a few important ways ๐ 1. whitespace in the input text, including CR and LF, must be encoded. RFC 2045 doesn't require that, and it doesn't allow encoding CR or LF characters that are part of a CRLF line break. 2. whitespace in the encoded text gets ignored. this is so tags encoded with DKIM-Quoted-Printable can be wrapped wherever needed. RFC 2045 says line breaks in the input have to stay as physical line breaks, and that's not the case here. 3. the "soft line break" syntax ("=" as the last non-whitespace character on the line) doesn't apply. 4. DKIM-Quoted-Printable doesn't require encoded lines to be no more than 76 characters long (although other requirements may apply depending on the context the encoded text is used in).
3. Protocol Elements ๐
protocol elements are the conceptual bits of the protocol that aren't specific to signers or verifiers. the protocol descriptions for signers and verifiers live in later sections (Signer Actions (Section 5) and Verifier Actions (Section 6)). NOTE: this section must be read in the context of those sections. ๐
3.1. Selectors ๐
to support multiple concurrent public keys per signing domain, the key namespace gets split up using "selectors". for example, selectors might be the names of office locations (e.g., "sanfrancisco", "coolumbeach", and "reykjavik"), the signing date (e.g., "january2005", "february2005", etc.), or even the individual user. ๐บ๏ธ
selectors are needed for some important use cases, like:
- domains that want to delegate signing capability for a specific address, for a given duration, to a partner such as an advertising provider or other outsourced function.
- domains that want to let frequent travelers send messages locally without needing to connect to a particular MSA.
- "affinity" domains (e.g., college alumni associations) that forward incoming mail but don't operate a mail submission agent for outgoing mail.
periods are allowed in selectors and act as component separators. when keys get retrieved from the DNS, the periods in selectors define DNS label boundaries, similar to how they work in domain names. selector components might combine dates with locations, for example "march2005.reykjavik". in a DNS implementation, this can allow delegation of a portion of the selector namespace. ๐งฉ
ABNF:
selector = sub-domain *( "." sub-domain )
the number of public keys and corresponding selectors for each domain is decided by the domain owner. lots of owners will be happy with just one selector, while administratively distributed organizations may want to manage different selectors and key pairs in different regions or on different email servers. ๐
beyond admin convenience, selectors make it possible to seamlessly swap out public keys on a routine basis. if a domain wants to switch from the public key tied to selector "january2005" to the one tied to selector "february2005", it just makes sure both public keys are advertised in the public-key repository at the same time for the transition period, during which email may still be in transit before verification. at the start of the transition period, the outbound email servers get configured to sign with the "february2005" private key. at the end of the transition period, the "january2005" public key gets removed from the public-key repository. ๐
INFORMATIVE NOTE: a key may also be revoked, as described below. the difference between revoking a key selector record and removing it is subtle. when phasing out keys like described above, a signing domain would probably just remove the key record after the transition period. however, a signing domain could choose to revoke the key (but keep the key record) for a further period. there's no defined semantic difference between a revoked key and a removed key. ๐คทโโ๏ธ
some domains might want to make selector values well known, but others will want to be careful not to allocate selector names in a way that lets outside parties harvest data. for example, if per-user keys get issued, the domain owner has to decide whether to tie the selector directly to the user name, or make it some unassociated random value, like a fingerprint of the public key. ๐ต๏ธโโ๏ธ
INFORMATIVE OPERATIONS NOTE: reusing a selector with a new key (for example, changing the key associated with a user's name) makes it impossible to tell the difference between a message that didn't verify because the key is no longer valid and a message that's actually forged. for this reason, signers are ill-advised to reuse selectors for new keys. a better strategy is to assign new keys to new selectors. ๐ซ
3.2. Tag=Value Lists ๐ฆ
DKIM uses a simple "tag=value" syntax in several contexts, including messages and domain signature records. ๐
values are a series of strings containing plain text, "base64" text (as defined in [RFC2045], Section 6.8), "qp-section" (ibid, Section 6.7), or "dkim-quoted-printable" (as defined in Section 2.6). the name of the tag decides the encoding of each value. unencoded semicolon (";") characters MUST NOT occur in the tag value, since that separates tag-specs. ๐ช
INFORMATIVE IMPLEMENTATION NOTE: even though the "plain text" defined below (as "tag-value") only includes 7-bit characters, an implementation that wants to anticipate future standards would be advised not to rule out UTF8-encoded text in tag=value lists. ๐
formally, the syntax rules look like this:
tag-list = tag-spec 0*( ";" tag-spec ) [ ";" ]
tag-spec = [FWS] tag-name [FWS] "=" [FWS] tag-value [FWS]
tag-name = ALPHA 0*ALNUMPUNC
tag-value = [ tval 0*( 1*(WSP / FWS) tval ) ]
; WSP and FWS prohibited at beginning and end
tval = 1*VALCHAR
VALCHAR = %x21-3A / %x3C-7E
; EXCLAMATION to TILDE except SEMICOLON
ALNUMPUNC = ALPHA / DIGIT / "_"
note that WSP is allowed anywhere around tags. in particular, any WSP after the "=" and any WSP before the terminating ";" is not part of the value. WSP inside the value, though, is significant. ๐
tags MUST be interpreted in a case-sensitive manner. values MUST be processed as case sensitive, unless the specific tag description of semantics says they're case insensitive. โจ
tags with duplicate names MUST NOT occur within a single tag-list. if a tag name occurs more than once, the entire tag-list is invalid. ๐
whitespace within a value MUST be retained, unless the specific tag description explicitly excludes it. ๐ซง
tag=value pairs that represent the default value MAY be included to aid legibility. ๐ท
unrecognized tags MUST be ignored. ๐
tags that have an empty value are not the same as omitted tags. an omitted tag is treated as having the default value, while a tag with an empty value explicitly designates the empty string as the value. for example, "g=" does not mean "g=", even though "g=" is the default for that tag. ๐ง
3.3. Signing and Verification Algorithms ๐
DKIM supports multiple digital signature algorithms. two algorithms are defined by this specification right now: rsa-sha1 and rsa-sha256. rsa-sha256 is the default if no algorithm is specified. verifiers MUST implement both rsa-sha1 and rsa-sha256. signers MUST implement and SHOULD sign using rsa-sha256. ๐
INFORMATIVE NOTE: even though sha256 is strongly encouraged, some senders of low-security messages (such as routine newsletters) may prefer sha1 because it needs less CPU to compute a sha1 hash. in general, sha256 should always be used whenever possible. ๐ฐโจ
3.3.1. The rsa-sha1 Signing Algorithm โจ
okay so the rsa-sha1 signing algorithm first makes a message hash (see Section 3.7 below) using SHA-1 [FIPS.180-2.2002] as the hash-alg ๐. then the signer signs that hash with RSA (from PKCS#1 version 1.5 [RFC3447]) as the crypt-alg, using their private key ๐. the hash MUST NOT be truncated or converted into any form other than the native binary form before it gets signed, no cap ๐ . also the signing algorithm SHOULD use a public exponent of 65537 ๐ .
3.3.2. The rsa-sha256 Signing Algorithm ๐ธ
this one is basically the same vibe, except it uses SHA-256 [FIPS.180-2.2002] as the hash-alg ๐. the message hash gets signed by the signer with RSA (PKCS#1 version 1.5 [RFC3447]) as the crypt-alg and the signer's private key ๐๏ธ. same rule as before: the hash MUST NOT be truncated or converted into any form other than the native binary form before being signed ๐ซถ.
3.3.3. Key Sizes ๐
picking a key size is literally a balancing act between cost, performance, and risk ๐คน. short RSA keys are easier to crack with off-line attacks, so signers MUST use RSA keys of at least 1024 bits for long-lived keys ๐. verifiers MUST be able to validate signatures with keys from 512 bits up to 2048 bits, and they MAY be able to validate bigger ones too ๐ฆ. verifier policies may use the length of the signing key as one metric for deciding whether a signature is acceptable ๐.
factors that should influence the key size choice include:
- The practical constraint that large (e.g., 4096 bit) keys may not fit within a 512-byte DNS UDP response packet ๐
- The security constraint that keys smaller than 1024 bits are subject to off-line attacks ๐
- Larger keys impose higher CPU costs to verify and sign email
- Keys can be replaced on a regular basis, thus their lifetime can be relatively short ๐
- The security goals of this specification are modest compared to typical goals of other systems that employ digital signatures ๐
see [RFC3766] for more on picking key sizes โจ
3.3.4. Other Algorithms ๐ง
other algorithms MAY be defined in the future ๐ฎ. verifiers MUST ignore any signatures using algorithms they don't implement, so no drama ๐.
3.4. Canonicalization ๐งผ
okay this part is giving "who gets to decide what counts as a change" ๐ญ. empirical evidence shows that some mail servers and relay systems modify email in transit, and that can totally break a signature ๐. there are two competing perspectives here. for most signers, mild modification of email is immaterial to the authentication status of the email, so for them a canonicalization algorithm that survives modest in-transit modification is preferred ๐.
other signers are super strict. any modification of the email, however minor, should result in a signature verification failure, and these signers prefer a canonicalization algorithm that does not tolerate in-transit modification of the signed email ๐ โโ๏ธ.
some signers may be willing to accept modifications to header fields that are within the bounds of email standards such as [RFC2822], but are unwilling to accept any modification to the body of messages ๐ซ .
so to make everyone happy, two canonicalization algorithms are defined for each of the header and the body โจ. there's a "simple" algorithm that tolerates almost no modification, and a "relaxed" algorithm that tolerates common modifications such as whitespace replacement and header field line rewrapping ๐ฆ. a signer MAY specify either algorithm for header or body when signing an email. if no canonicalization algorithm is specified by the signer, the "simple" algorithm defaults for both header and body. verifiers MUST implement both canonicalization algorithms. the header and body may use different canonicalization algorithms, which is very on-brand for them ๐ . further canonicalization algorithms MAY be defined in the future, and verifiers MUST ignore any signatures that use unrecognized canonicalization algorithms ๐ซ.
canonicalization just preps the email for presentation to the signing or verification algorithm ๐. it MUST NOT change the transmitted data in any way ๐ซถ. the header and body canonicalization are described below.
NOTE: This section assumes that the message is already in "network normal" format (text is ASCII encoded, lines are separated with CRLF characters, etc.). See also Section 5.3 for information about normalizing the message.
3.4.1. The "simple" Header Canonicalization Algorithm ๐ค
the "simple" header canonicalization algorithm does not change header fields in any way, zero edits, full stop ๐ง. header fields MUST be presented to the signing or verification algorithm exactly as they are in the message being signed or verified. in particular, header field names MUST NOT be case folded and whitespace MUST NOT be changed ๐.
3.4.2. The "relaxed" Header Canonicalization Algorithm ๐ท
the "relaxed" header canonicalization algorithm is the glow-up version ๐. it MUST apply the following steps in order:
- Convert all header field names (not the header field values) to lowercase. For example, convert "SUBJect: AbC" to "subject: AbC".
- Unfold all header field continuation lines as described in [RFC2822]. in particular, lines with terminators embedded in continued header field values (that is, CRLF sequences followed by WSP) MUST be interpreted without the CRLF. Implementations MUST NOT remove the CRLF at the end of the header field value.
- Convert all sequences of one or more WSP characters to a single SP character. WSP characters here include those before and after a line folding boundary.
- Delete all WSP characters at the end of each unfolded header field value.
- Delete any WSP characters remaining before and after the colon separating the header field name from the header field value. The colon separator MUST be retained.
3.4.3. The "simple" Body Canonicalization Algorithm ๐ซง
the "simple" body canonicalization algorithm ignores all empty lines at the end of the message body. an empty line is a line of zero length after removing the line terminator ๐. if there's no body or no trailing CRLF on the message body, a CRLF gets added. it makes no other changes to the message body. in more formal terms, it converts 0*CRLF at the end of the body to a single CRLF ๐งฎ.
note that a completely empty or missing body gets canonicalized as a single CRLF, so the canonicalized length will be 2 octets ๐ผ.
3.4.4. The "relaxed" Body Canonicalization Algorithm ๐
the "relaxed" body canonicalization algorithm:
- Ignores all whitespace at the end of lines. Implementations MUST NOT remove the CRLF at the end of the line.
- Reduces all sequences of WSP within a line to a single SP character.
- Ignores all empty lines at the end of the message body. "Empty line" is defined in Section 3.4.3.
INFORMATIVE NOTE: It should be noted that the relaxed body canonicalization algorithm may enable certain types of extremely crude "ASCII Art" attacks where a message may be conveyed by adjusting the spacing between words. If this is a concern, the "simple" body canonicalization algorithm should be used instead. ๐จ
3.4.5. Body Length Limits ๐
a body length count MAY be specified to limit the signature calculation to an initial prefix of the body text, measured in octets. if the body length count isn't specified, the entire message body is signed ๐.
INFORMATIVE RATIONALE: This capability is provided because it is very common for mailing lists to add trailers to messages (e.g., instructions how to get off the list). Until those messages are also signed, the body length count is a useful tool for the verifier since it may as a matter of policy accept messages having valid signatures with extraneous data. ๐ฌ
INFORMATIVE IMPLEMENTATION NOTE: Using body length limits enables an attack in which an attacker modifies a message to include content that solely benefits the attacker. It is possible for the appended content to completely replace the original content in the end recipient's eyes and to defeat duplicate message detection algorithms. To avoid this attack, signers should be wary of using this tag, and verifiers might wish to ignore the tag or remove text that appears after the specified content length, perhaps based on other criteria. ๐จ
the body length count lets the signer of a message allow data to be appended to the end of the body of a signed message ๐ง. the body length count MUST be calculated following the canonicalization algorithm. for example, any whitespace ignored by a canonicalization algorithm is not included as part of the body length count. signers of MIME messages that include a body length count SHOULD be sure that the length extends to the closing MIME boundary string ๐งท.
INFORMATIVE IMPLEMENTATION NOTE: A signer wishing to ensure that the only acceptable modifications are to add to the MIME postlude would use a body length count encompassing the entire final MIME boundary string, including the final "--CRLF". A signer wishing to allow additional MIME parts but not modification of existing parts would use a body length count extending through the final MIME boundary string, omitting the final "--CRLF". Note that this only works for some MIME types, e.g., multipart/mixed but not multipart/signed. ๐ง
a body length count of zero means the body is completely unsigned ๐ซฅ.
signers who want to make sure no modification of any sort can happen should specify the "simple" canonicalization algorithm for both header and body, and omit the body length count ๐๐ .
3.4.6. Canonicalization Examples (INFORMATIVE) ๐ฐ
in the following examples, actual whitespace is only used for clarity. the actual input and output text is marked with bracketed descriptors: "<SP>" for a space character, "<HTAB>" for a tab character, and "<CRLF>" for a carriage-return/line-feed sequence. for example, "X <SP> Y" and "X<SP>Y" represent the same three characters ๐.
Example 1: A message reading:
A: <SP> X <CRLF>
B <SP> : <SP> Y <HTAB><CRLF>
<HTAB> Z <SP><SP><CRLF>
<CRLF>
<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>
<CRLF>
<CRLF>
when canonicalized using relaxed canonicalization for both header and body, the header reads:
a:X <CRLF>
b:Y <SP> Z <CRLF>
and the body reads:
<SP> C <CRLF>
D <SP> E <CRLF>
Example 2: The same message canonicalized using simple canonicalization for both header and body results in a header reading:
A: <SP> X <CRLF>
B <SP> : <SP> Y <HTAB><CRLF>
<HTAB> Z <SP><SP><CRLF>
and a body reading:
<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>
Example 3: When processed using relaxed header canonicalization and simple body canonicalization, the canonicalized version has a header of:
a:X <CRLF>
b:Y <SP> Z <CRLF>
and a body reading:
<SP> C <SP><CRLF>
D <SP><HTAB><SP> E <CRLF>
3.5. The DKIM-Signature Header Field ๐๏ธ
the signature of the email is stored in the DKIM-Signature header field ๐. this header field holds all of the signature and key-fetching data, and its value is a tag-list as described in Section 3.2 ๐.
the DKIM-Signature header field SHOULD be treated as though it were a trace header field as defined in Section 3.6 of [RFC2822]. that means it SHOULD NOT be reordered, and it SHOULD be prepended to the message ๐งโโ๏ธโจ.
The DKIM-Signature header field being made or checked is always part of the signature math ๐, and it goes after all the other header fields being signed โจ. But here's the twist ๐: while the math is happening, the value of the b= tag (the signature value) in that very DKIM-Signature field MUST be treated as though it were an empty string. Unknown tags in the DKIM-Signature header field MUST be included in the signature calculation but MUST be otherwise ignored by verifiers ๐ซถ. Other DKIM-Signature header fields that are included in the signature should be treated as normal header fields ๐, so the b= tag isn't treated specially over there ๐ฆ.
The encodings for each field type are listed below ๐ธ. Tags described as qp-section are encoded as described in Section 6.7 of MIME Part One [RFC2045], with the additional conversion of semicolon characters to "=3B". Intuitively, that's one line of quoted-printable encoded text ๐. The dkim-quoted-printable syntax is defined in Section 2.6.
Here are the tags on the DKIM-Signature header field, along with their type and requirement status ๐. Unrecognized tags MUST be ignored ๐ง.
v= Version (MUST be included) ๐. This tag defines the version of this specification that applies to the signature record. It MUST have the value "1". Verifiers must do a string comparison on this value, so "1" is not the same as "1.0" ๐.
sig-v-tag = %x76 [FWS] "=" [FWS] "1"
INFORMATIVE NOTE: DKIM-Signature version numbers are expected to increase arithmetically as new versions of this specification are released ๐.
a= The algorithm used to generate the signature (plain-text; REQUIRED) ๐ฅ. Verifiers MUST support "rsa-sha1" and "rsa-sha256". Signers SHOULD sign using "rsa-sha256" โจ. See Section 3.3 for a description of algorithms.
sig-a-tag = %x61 [FWS] "=" [FWS] sig-a-tag-alg
sig-a-tag-alg = sig-a-tag-k "-" sig-a-tag-h
sig-a-tag-k = "rsa" / x-sig-a-tag-k
sig-a-tag-h = "sha1" / "sha256" / x-sig-a-tag-h
x-sig-a-tag-k = ALPHA *(ALPHA / DIGIT) ; for later extension
x-sig-a-tag-h = ALPHA *(ALPHA / DIGIT) ; for later extension
b= The signature data (base64; REQUIRED) ๐ฆ. Whitespace is ignored in this value and MUST be ignored when reassembling the original signature. In particular, the signing process can safely insert FWS in this value in arbitrary places to conform to line-length limits. See Signer Actions (Section 5) for how the signature is computed ๐ .
sig-b-tag = %x62 [FWS] "=" [FWS] sig-b-tag-data
sig-b-tag-data = base64string
bh= The hash of the canonicalized body part of the message as limited by the "l=" tag (base64; REQUIRED) ๐ธ. Whitespace is ignored in this value and MUST be ignored when reassembling the original signature. In particular, the signing process can safely insert FWS in this value in arbitrary places to conform to line-length limits. See Section 3.7 for how the body hash is computed ๐ซถ.
sig-bh-tag = %x62 %x68 [FWS] "=" [FWS] sig-bh-tag-data
sig-bh-tag-data = base64string
c= Message canonicalization (plain-text; OPTIONAL, default is "simple/simple") ๐. This tag tells the verifier which type of canonicalization was used to prepare the message for signing. It's two names separated by a "slash" (%d47) character, matching the header and body canonicalization algorithms respectively. These algorithms are described in Section 3.4. If only one algorithm is named, that algorithm is used for the header and "simple" is used for the body. For example, "c=relaxed" is treated the same as "c=relaxed/simple" ๐.
sig-c-tag = %x63 [FWS] "=" [FWS] sig-c-tag-alg
["/" sig-c-tag-alg]
sig-c-tag-alg = "simple" / "relaxed" / x-sig-c-tag-alg
x-sig-c-tag-alg = hyphenated-word ; for later extension
d= The domain of the signing entity (plain-text; REQUIRED) ๐. This is the domain that will be queried for the public key. This domain MUST be the same as or a parent domain of the "i=" tag (the signing identity, as described below), or it MUST meet the requirements for parent domain signing described in Section 3.8. When presented with a signature that does not meet these requirement, verifiers MUST consider the signature invalid ๐ซ.
Internationalized domain names MUST be encoded as described in [RFC3490] ๐.
sig-d-tag = %x64 [FWS] "=" [FWS] domain-name
domain-name = sub-domain 1*("." sub-domain)
; from RFC 2821 Domain, but excluding address-literal
h= Signed header fields (plain-text, but see description; REQUIRED) ๐. This is a colon-separated list of header field names that identify the header fields presented to the signing algorithm. The field MUST contain the complete list of header fields in the order presented to the signing algorithm. The field MAY contain names of header fields that do not exist when signed. Nonexistent header fields do not contribute to the signature computation (that is, they are treated as the null input, including the header field name, the separating colon, the header field value, and any CRLF terminator) ๐. The field MUST NOT include the DKIM-Signature header field that is being created or verified, but may include others. Folding whitespace (FWS) MAY be included on either side of the colon separator. Header field names MUST be compared against actual header field names in a case-insensitive manner. This list MUST NOT be empty. See Section 5.4 for a discussion of choosing header fields to sign โจ.
sig-h-tag = %x68 [FWS] "=" [FWS] hdr-name
0*( *FWS ":" *FWS hdr-name )
hdr-name = field-name
INFORMATIVE EXPLANATION: By "signing" header fields that do not actually exist, a signer can prevent insertion of those header fields before verification. However, since a signer cannot possibly know what header fields might be created in the future, and since some MUAs might present header fields that are embedded inside a message (e.g., as a message/rfc822 content type), the security of this solution is not total ๐ญ.
INFORMATIVE EXPLANATION: The exclusion of the header field name and colon as well as the header field value for non-existent header fields prevents an attacker from inserting an actual header field with a null value ๐.
i= Identity of the user or agent (e.g., a mailing list manager) on behalf of which this message is signed (dkim-quoted-printable; OPTIONAL, default is an empty Local-part followed by an "@" followed by the domain from the "d=" tag) ๐ง. The syntax is a standard email address where the Local-part MAY be omitted. The domain part of the address MUST be the same as or a subdomain of the value of the "d=" tag.
Internationalized domain names MUST be converted using the steps listed in Section 4 of [RFC3490] using the "ToASCII" function ๐.
sig-i-tag = %x69 [FWS] "=" [FWS] [ Local-part ] "@" domain-name
INFORMATIVE NOTE: The Local-part of the "i=" tag is optional because, in some cases, a signer may not be able to establish a verified individual identity. In such cases, the signer may wish to assert that although it is willing to go as far as signing for the domain, it is unable or unwilling to commit to an individual user name within their domain. It can do so by including the domain part but not the Local-part of the identity ๐.
INFORMATIVE DISCUSSION: This document does not require the value of the "i=" tag to match the identity in any message header fields. This is considered to be a verifier policy issue. Constraints between the value of the "i=" tag and other identities in other header fields seek to apply basic authentication into the semantics of trust associated with a role such as content author. Trust is a broad and complex topic, and trust mechanisms are subject to highly creative attacks. The real-world efficacy of any but the most basic bindings between the "i=" value and other identities is not well established, nor is its vulnerability to subversion by an attacker. Hence, reliance on the use of these options should be strictly limited. In particular, it is not at all clear to what extent a typical end-user recipient can rely on any assurances that might be made by successful use of the "i=" options ๐ค.
l= Body length count (plain-text unsigned decimal integer; OPTIONAL, default is entire body) ๐. This tag tells the verifier the number of octets in the body of the email after canonicalization that were included in the cryptographic hash, starting from 0 immediately following the CRLF preceding the body. This value MUST NOT be larger than the actual number of octets in the canonicalized message body.
INFORMATIVE IMPLEMENTATION WARNING: Use of the "l=" tag might allow display of fraudulent content without appropriate warning to end users ๐จ. The "l=" tag is intended for increasing signature robustness when sending to mailing lists that both modify their content and do not sign their messages. However, using the "l=" tag enables attacks in which an intermediary with malicious intent modifies a message to include content that solely benefits the attacker. It is possible for the appended content to completely replace the original content in the end recipient's eyes, and to defeat duplicate message detection algorithms. Examples are described in Security Considerations (Section 8). To avoid this attack, signers should be extremely wary of using this tag, and verifiers might wish to ignore the tag or remove text that appears after the specified content length ๐.
INFORMATIVE NOTE: The value of the "l=" tag is constrained to 76 decimal digits. This constraint is not intended to predict the size of future messages or to require implementations to use an integer representation large enough to represent the maximum possible value. It's intended to remind the implementer to check the length of this and all other tags during verification, and to test for integer overflow when decoding the value. Implementers may need to limit the actual value expressed to a value smaller than 10^76, e.g., to allow a message to fit within the available storage space ๐งฎ.
sig-l-tag = %x6c [FWS] "=" [FWS] 1*76DIGIT
okay bestie, we're picking up right in the middle of the DKIM-Signature tag list ๐ so q= is up first ๐
q= is a colon-separated list of query methods used to fetch the public key ๐ It's plain-text and OPTIONAL, and if you don't set it the default is "dns/txt" ๐ Each method looks like "type[/options]", and what the options mean depends on the type and the options you pick โจ If you list more than one query mechanism, the choice of mechanism MUST NOT change how the signature is interpreted ๐ซถ And implementations MUST try the recognized query mechanisms in the order they're listed ๐ง
Right now "dns/txt" is the only valid value, and it's the DNS TXT record lookup algorithm described elsewhere in this document ๐ธ The only option defined for the "dns" query type is "txt", and that one MUST be included ๐ Verifiers and signers MUST support "dns/txt" ๐ญ
sig-q-tag = %x71 [FWS] "=" [FWS] sig-q-tag-method
*([FWS] ":" [FWS] sig-q-tag-method)
sig-q-tag-method = "dns/txt" / x-sig-q-tag-type
["/" x-sig-q-tag-args]
x-sig-q-tag-type = hyphenated-word ; for future extension
x-sig-q-tag-args = qp-hdr-value
s= is the selector, and it's how the namespace for the "d=" (domain) tag gets subdivided ๐ฆ It's plain-text and REQUIRED, so you can't skip it ๐
sig-s-tag = %x73 [FWS] "=" [FWS] selector
t= is the Signature Timestamp ๐ฐ๏ธ It's a plain-text unsigned decimal integer and RECOMMENDED, and if it's missing the default is an unknown creation time โญ It records when the signature was created, counted as seconds since 00:00:00 on January 1, 1970 in the UTC time zone ๐ The value is an unsigned integer in decimal ASCII, and it is NOT limited to fit into a 31- or 32-bit integer, so it can get really big ๐ Implementations SHOULD be ready to handle values up to at least 10^12, which is around AD 200,000 and fits into 40 bits ๐ฅ To dodge denial-of-service attacks, implementations MAY treat any value longer than 12 digits as infinite ๐ก๏ธ Leap seconds are not counted ๐ And implementations MAY ignore signatures whose timestamp is in the future ๐
sig-t-tag = %x74 [FWS] "=" [FWS] 1*12DIGIT
x= is the Signature Expiration ๐ It's a plain-text unsigned decimal integer and RECOMMENDED, and the default is no expiration at all โจ It uses the same format as "t=", but it's an absolute date and not a time delta from the signing timestamp ๐ The value is an unsigned decimal ASCII integer that follows the same constraints as the "t=" tag ๐ Signatures MAY be considered invalid if the verification time at the verifier is past the expiration date ๐ญ The verification time SHOULD be the time the message first arrived in the verifier's administrative domain, as long as that time is reliably available ๐ซถ If it isn't, the current time SHOULD be used instead ๐ง And if both "t=" and "x=" are present, the value of "x=" MUST be greater than the value of "t=" ๐
INFORMATIVE NOTE: The "x=" tag is not intended as an anti-replay defense. Please don't rely on it for that ๐ โโ๏ธ
sig-x-tag = %x78 [FWS] "=" [FWS] 1*12DIGIT
z= is for copied header fields ๐ท The text there is dkim-quoted-printable, but check the description, it's a bit of a twist ๐ฆ It's OPTIONAL, and the default is null ๐ It's a vertical-bar-separated list of selected header fields that were present when the message got signed, and each one includes both the field name and the value ๐ You don't have to copy every header that existed at signing time, and the fields in "z=" don't have to match the ones listed in "h=" either ๐ธ Any vertical bar ("|", %x7C) inside a copied header has to be encoded, because bars in the "z=" text are metacharacters ๐ All whitespace has to be encoded too, including whitespace between the colon and the header value ๐ After encoding, FWS MAY be added at arbitrary spots to keep lines from getting super long, but that whitespace is NOT part of the header value and MUST be removed before decoding ๐ญ
The header fields referenced by the "h=" tag point at the fields in the RFC 2822 header of the message, not at any copied fields in "z=" ๐ง Copied header values are only for diagnostic use ๐
Header fields with characters that need conversion (maybe from legacy MTAs that aren't [RFC2822] compliant) SHOULD be converted as described in MIME Part Three [RFC2047] ๐
sig-z-tag = %x7A [FWS] "=" [FWS] sig-z-tag-copy
*( [FWS] "|" sig-z-tag-copy )
sig-z-tag-copy = hdr-name ":" qp-hdr-value
qp-hdr-value = dkim-quoted-printable ; with "|" encoded
Here's an INFORMATIVE EXAMPLE of a signature header spread across a few continuation lines ๐
DKIM-Signature: a=rsa-sha256; d=example.net; s=brisbane;
c=simple; q=dns/txt; i=@eng.example.net;
t=1117574938; x=1118006938;
h=from:to:subject:date;
z=From:foo@eng.example.net|To:joe@example.com|
Subject:demo=20run|Date:July=205,=202005=203:44:08=20PM=20-0700;
bh=MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=;
b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZ
VoG4ZHRNiYzR
3.6. Key Management and Representation ๐
okay this part is giving trust ๐ฅน Signature applications need some level of assurance that the verification public key really belongs to the signer who's claimed ๐ Lots of apps get that by using public key certificates from a trusted third party ๐ But DKIM can reach a solid level of security with way better scalability, just by having the verifier query the purported signer's DNS entry (or some security-equivalent) to get the public key โจ That's the move ๐
DKIM keys can be stored in several kinds of key servers and in several formats ๐ How keys are stored and formatted doesn't matter to the rest of the DKIM algorithm ๐ซถ
The inputs to the key lookup algorithm are the lookup type (the "q=" tag), the signer's domain (the "d=" tag of the DKIM-Signature header field), and the selector (the "s=" tag) ๐ง
public_key = dkim_find_key(q_val, d_val, s_val)
This document defines one binding, which uses DNS TXT records to distribute the keys ๐ธ Other bindings may be defined in the future ๐ฎ
3.6.1. Textual Representation โจ
okay so bestie, a lot of key servers are gonna store keys as plain, unstructured text ๐ (an XML form doesn't count as unstructured text for this, fyi ๐). Whenever a DKIM key shows up in that kind of text, this exact definition MUST be used ๐ . The overall syntax is a tag-list, same as in Section 3.2 ๐ฆ. Here are the tags that are valid right now. Other tags MAY be present, and any implementation that doesn't understand them MUST ignore them ๐ซถ
v= ๐ This is the version of the DKIM key record (plain-text, RECOMMENDED, and it defaults to "DKIM1"). If it's there, the tag MUST be set to "DKIM1" (no quotes). It also MUST be the very first tag in the record, and any record starting with a v= tag set to something else MUST be discarded ๐ญ. Verifiers have to do a string comparison on this value, so "DKIM1" is NOT the same as "DKIM1.0" ๐
โโ๏ธ
ABNF:
key-v-tag = %x76 [FWS] "=" [FWS] "DKIM1"
g= ๐ง This is the granularity of the key (plain-text, OPTIONAL, default is ""). The value MUST match the Local-part of the i= tag in the DKIM-Signature header field (or the default empty string if i= isn't specified). There's a single optional "" that matches zero or more arbitrary characters, which is called wildcarding โจ. If the signing address doesn't match this value, that's a failed verification ๐. The whole point is to limit which signing address can use this selector, like when you hand a key to a third party that should only be used for special purposes ๐. Wildcarding lets you match things like "user+" or "-offer" ๐. An empty g= value never matches any addresses ๐
ABNF:
key-g-tag = %x67 [FWS] "=" [FWS] key-g-tag-lpart
key-g-tag-lpart = [dot-atom-text] ["*" [dot-atom-text] ]
h= ๐ธ These are the acceptable hash algorithms (plain-text, OPTIONAL, and it defaults to allowing all algorithms). It's a colon-separated list of hash algorithms that might get used. Signers and Verifiers MUST support the "sha256" hash algorithm, and Verifiers MUST also support the "sha1" hash algorithm ๐ฅ
ABNF:
key-h-tag = %x68 [FWS] "=" [FWS] key-h-tag-alg
0*( [FWS] ":" [FWS] key-h-tag-alg )
key-h-tag-alg = "sha1" / "sha256" / x-key-h-tag-alg
x-key-h-tag-alg = hyphenated-word ; for future extension
k= ๐ฆ This is the key type (plain-text, OPTIONAL, default is "rsa"). Signers and verifiers MUST support the "rsa" key type โจ. "rsa" means an ASN.1 DER-encoded [ITU.X660.1997] RSAPublicKey [RFC3447] (see Sections 3.1 and A.1.1) is being used in the p= tag. (Side note: the p= tag also encodes the value using base64 ๐
)
ABNF:
key-k-tag = %x76 [FWS] "=" [FWS] key-k-tag-type
key-k-tag-type = "rsa" / x-key-k-tag-type
x-key-k-tag-type = hyphenated-word ; for future extension
n= ๐ These are notes that might be of interest to a human (qp-section, OPTIONAL, default is empty). No program interprets them. Use this one sparingly in any key server mechanism with space limits (DNS, I'm looking at you ๐). It's meant for administrators, not end users ๐
ABNF:
key-n-tag = %x6e [FWS] "=" [FWS] qp-section
p= ๐ This is the public-key data (base64, REQUIRED). An empty value means the public key has been revoked ๐. The syntax and semantics of this tag's value before base64 encoding are defined by the k= tag.
INFORMATIVE RATIONALE: If a private key has been compromised or otherwise disabled (e.g., an outsourcing contract has been terminated), a signer might want to explicitly state that it knows about the selector, but all messages using that selector should fail verification. Verifiers should ignore any DKIM-Signature header fields with a selector referencing a revoked key.
ABNF:
key-p-tag = %x70 [FWS] "=" [ [FWS] base64string ]
INFORMATIVE NOTE: A base64string is permitted to include white space (FWS) at arbitrary places; however, any CRLFs must be followed by at least one WSP character. Implementors and administrators are cautioned to ensure that selector TXT records conform to this specification. ๐
s= ๐ This is the service type (plain-text, OPTIONAL, default is "*"). It's a colon-separated list of service types this record applies to. Verifiers for a given service type MUST ignore this record if that type isn't listed. The currently defined service types are:
*matches all service typesemailis electronic mail (not necessarily limited to SMTP)
This tag exists to constrain key use for other purposes, in case DKIM gets defined for other services down the road ๐ฎ
ABNF:
key-s-tag = %x73 [FWS] "=" [FWS] key-s-tag-type
0*( [FWS] ":" [FWS] key-s-tag-type )
key-s-tag-type = "email" / "*" / x-key-s-tag-type
x-key-s-tag-type = hyphenated-word ; for future extension
t= โญ These are flags, a colon-separated list of names (plain-text, OPTIONAL, default is no flags set). The defined flags are:
ymeans this domain is testing DKIM. Verifiers MUST NOT treat messages from signers in testing mode differently from unsigned email, even if the signature fails to verify ๐ญ. Verifiers MAY wish to track testing mode results to help the signer ๐งsmeans any DKIM-Signature header fields using thei=tag MUST have the same domain value on the right-hand side of the "@" in thei=tag and the value of thed=tag. Basically, thei=domain MUST NOT be a subdomain ofd=๐ โโ๏ธ. Use of this flag is RECOMMENDED unless subdomaining is required โจ
ABNF:
key-t-tag = %x74 [FWS] "=" [FWS] key-t-tag-flag
0*( [FWS] ":" [FWS] key-t-tag-flag )
key-t-tag-flag = "y" / "s" / x-key-t-tag-flag
x-key-t-tag-flag = hyphenated-word ; for future extension
Unrecognized flags MUST be ignored ๐ซถ
3.6.2. DNS Binding ๐
A binding using DNS TXT records as a key service is hereby defined, and every implementation MUST support it. No exceptions, bestie ๐
3.6.2.1. Namespace ๐ง
All DKIM keys live in a subdomain called "_domainkey" ๐ก. Say you've got a DKIM-Signature field with a d= tag of "example.com" and an s= tag of "foo.bar". The DNS query will be for "foo.bar._domainkey.example.com" ๐
INFORMATIVE OPERATIONAL NOTE: Wildcard DNS records (e.g.,*.bar._domainkey.example.com) do not make sense in this context and should not be used. Note also that wildcards within domains (e.g.,s._domainkey.*.example.com) are not supported by the DNS. ๐
3.6.2.2. Resource Record Types for Key Storage ๐พ
The DNS Resource Record type gets picked by an option to the query-type (q=) tag. The only option defined in this base specification is "txt", which means a TXT Resource Record (RR) ๐. A later extension of this standard might define another RR type, so keep an eye out ๐
Strings in a TXT RR MUST be concatenated together before use, with no whitespace in between ๐งต. TXT RRs MUST be unique for a particular selector name. If there are multiple records in an RRset, the results are undefined, and that's a whole mess nobody wants ๐
TXT RRs are encoded as described in Section 3.6.1 ๐
3.7. Computing the Message Hashes โจ
okay so before anything gets signed or checked, you have to compute two hashes over the message ๐ง Signers pick the signature parameters (see Signer Actions (Section 5)), and verifiers use the parameters in the DKIM-Signature header field they're verifying. We're talking about the tag names in the DKIM-Signature header field that either exists (when verifying) or will be created (when signing). Also, canonicalization (Section 3.4) is only there to prep the email for signing or verifying. It does NOT change the transmitted email in any way ๐
The signer/verifier MUST compute two hashes, one over the body of the message and one over the selected header fields of the message. ๐ธ
Signers MUST compute them in the order shown. Verifiers MAY compute them in any order convenient to the verifier, as long as the result is semantically identical to what you'd get if they'd been computed in this order ๐ฆ
In hash step 1, the signer/verifier MUST hash the message body, canonicalized with the body canonicalization algorithm named in the c= tag, and then truncated to the length in the l= tag. Then that hash gets converted to base64 and either inserted into (signers) or compared to (verifiers) the bh= tag of the DKIM-Signature header field ๐
In hash step 2, the signer/verifier MUST pass the following to the hash algorithm, in this exact order:
- The header fields named in the
h=tag, in the order that tag lists them, canonicalized with the header canonicalization algorithm from thec=tag. Each header field MUST be terminated with a single CRLF. - The DKIM-Signature header field that exists (verifying) or will be inserted (signing) in the message, with the value of the
b=tag deleted (i.e., treated as the empty string), canonicalized with the header canonicalization algorithm from thec=tag, and without a trailing CRLF.
Okay this part is kinda the main event ๐ฅ All the tags and their values in the DKIM-Signature header field get included in the cryptographic hash, with ONE exception: the value part of the b= (signature) tag, which MUST be treated as the null string. All tags MUST be included even if the verifier doesn't understand them ๐ The DKIM-Signature header field MUST be presented to the hash algorithm after the body of the message, not with the rest of the header fields, and it MUST be canonicalized as specified in the c= (canonicalization) tag. The DKIM-Signature header field MUST NOT be included in its own h= tag, although other DKIM-Signature header fields MAY be signed (see Section 4) โจ
When you're hashing messages that will be sent using base64 or quoted-printable encoding, signers MUST compute the hash AFTER the encoding. Likewise, the verifier MUST incorporate the values into the hash before decoding the base64 or quoted-printable text. BUT the hash MUST be computed before transport level encodings like SMTP "dot-stuffing" (the thing where lines starting with a "." get modified so they don't get confused with the SMTP end-of-message marker, as specified in [RFC2821]) ๐
Except for the canonicalization procedure in Section 3.4, the DKIM signing process treats the body of messages as just a string of octets. DKIM messages MAY be either plain-text or MIME format, and no special treatment is afforded to MIME content. Message attachments in MIME format MUST be included in the content that is signed ๐
Here's the more formal version of the algorithm:
body-hash = hash-alg(canon_body)
header-hash = hash-alg(canon_header || DKIM-SIG)
signature = sig-alg(header-hash, key)
where "sig-alg" is the signature algorithm named by the "a=" tag, "hash-alg" is the hash algorithm named by the "a=" tag, "canon_header" and "canon_body" are the canonicalized message header and body (respectively) as defined in Section 3.4 (excluding the DKIM-Signature header field), and "DKIM-SIG" is the canonicalized DKIM-Signature header field sans the signature value itself, but with "body-hash" included as the "bh=" tag.
INFORMATIVE IMPLEMENTERS' NOTE: Many digital signature APIs give you both hashing and application of the RSA private key in one single "sign()" primitive. If you're using one of those, the last two steps in the algorithm would probably get combined into one call that does both the "hash-alg" and the "sig-alg" ๐ง
3.8. Signing by Parent Domains ๐ณ
Sometimes a domain wants to sign on behalf of any of its subdomains WITHOUT having to maintain separate selectors (key records) in each subdomain. By default, private keys tied to key records can be used to sign messages for any subdomain of the domain they live in. For example, a key record for the domain example.com can verify messages where the signing identity (the i= tag of the signature) is sub.example.com, or even sub1.sub2.example.com ๐
To limit what these keys can do when that's not intended, the "s" flag may be set in the t= tag of the key record. That constrains the validity of the record to exactly the domain of the signing identity. If the referenced key record has the "s" flag as part of its t= tag, the domain of the signing identity (the "i=" flag) MUST be the same as the d= domain. If that flag is absent, the domain of the signing identity MUST be the same as, or a subdomain of, the d= domain. Key records that are NOT meant for use with subdomains SHOULD specify the "s" flag in the t= tag ๐
4. Semantics of Multiple Signatures ๐ฆ
4.1. Example Scenarios ๐
There are lots of reasons a message might end up with multiple signatures. For example, a signer might sign multiple times, maybe with different hashing or signing algorithms during a transition phase ๐
INFORMATIVE EXAMPLE: Say SHA-256 is someday found to be insufficiently strong, and DKIM usage transitions to SHA-1024. A signer might immediately sign using the newer algorithm, but keep signing with the older algorithm for interoperability with verifiers that haven't upgraded yet. The signer would do this by adding two DKIM-Signature header fields, one using each algorithm. Older verifiers that didn't recognize SHA-1024 as an acceptable algorithm would skip that signature and use the older algorithm. Newer verifiers could use either signature at their option, and all other things being equal might not even bother trying to verify the other signature ๐
Similarly, a signer might sign a message including all headers and no l= tag (to satisfy strict verifiers), AND a second time with a limited set of headers and an l= tag (in anticipation of possible message modifications on the way to other verifiers). Verifiers could then choose which signature they prefer ๐
INFORMATIVE EXAMPLE: A verifier might receive a message with two signatures, one covering more of the message than the other. If the signature covering more of the message verifies, the verifier could make one set of policy decisions. If that signature fails but the signature covering less of the message verifies, the verifier might make a different set of policy decisions ๐ง
Of course, a message might also have multiple signatures because it went through multiple signers. A common case is expected to be a signed message that passes through a mailing list that also signs every message. Assuming both of those signatures verify, a recipient might choose to accept the message if either signature is known to come from a trusted source ๐ฌ
INFORMATIVE EXAMPLE: Recipients might choose to whitelist mailing lists they've subscribed to and that have acceptable anti-abuse policies, so they accept messages sent to that list even from unknown authors. They might also subscribe to less trusted mailing lists (e.g., ones without anti-abuse protection) and be willing to accept all messages from specific authors, but insist on doing additional abuse scanning for other messages ๐ก๏ธ
Another related example of multiple signers is forwarding services, like the ones commonly associated with academic alumni sites ๐
INFORMATIVE EXAMPLE: A recipient might have an address at members.example.org, a site with anti-abuse protection that's somewhat less effective than the recipient would prefer. That recipient might have specific authors whose messages would be trusted absolutely, but messages from unknown authors that had passed the forwarder's scrutiny would have only medium trust ๐
4.2. Interpretation โจ
Okay so bestie, when a signer is just adding a signature to a message, it literally makes a brand new DKIM-Signature header, using the usual h= option semantics ๐
. A signer MAY sign previously existing DKIM-Signature header fields too, using the method from Section 5.4 to sign trace header fields ๐ฆ.
Informative note: Signers should be cognizant that signing DKIM-Signature header fields may result in signature failures with intermediaries that don't recognize DKIM-Signature header fields as trace header fields. Those intermediaries might unwittingly reorder them, which breaks the signatures ๐ญ. So signing existing DKIM-Signature header fields is unadvised, albeit legal ๐.
Informative note: If a header field with multiple instances is signed, those instances are always signed from the bottom up ๐. That means you can't sign only specific DKIM-Signature header fields. For example, if the message already has three DKIM-Signature header fields A, B, and C, you can sign all of them, B and C only, or C only. You can't do A only, B only, A and B only, or A and C only. Not me being picky ๐.
A signer MAY add more than one DKIM-Signature header field using different parameters. Like, during a transition period a signer might want to produce signatures with two different hash algorithms ๐.
Signers SHOULD NOT remove any DKIM-Signature header fields from messages they're signing, even if they know those signatures can't be verified ๐ซถ.
When a verifier evaluates a message with multiple signatures, it SHOULD evaluate each signature independently and on its own merits โจ. For example, a verifier whose policy chooses not to accept signatures made with deprecated cryptographic algorithms would consider those signatures invalid ๐ฅ. Verifiers MAY process signatures in any order they like. Some verifiers might choose to process signatures corresponding to the From field first, before the others ๐. See Section 6.1 for more info about signature choices ๐ง.
Informative implementation note: Verifier attempts to correlate valid signatures with invalid signatures, trying to guess why a signature failed, are ill-advised ๐ โโ๏ธ. Especially because there's no general way for a verifier to determine that an invalid signature was ever valid ๐ .
Verifiers SHOULD ignore failed signatures as though they weren't present in the message. Verifiers SHOULD continue checking signatures until one successfully verifies to the satisfaction of the verifier ๐. To limit potential denial-of-service attacks, verifiers MAY limit the total number of signatures they'll attempt to verify ๐ก๏ธ.
5. Signer Actions ๐
The following steps are performed in order by signers ๐.
5.1. Determine Whether the Email Should Be Signed and by Whom ๐ค
A signer can obviously only sign email for domains it has a private key for, plus the necessary knowledge of the corresponding public key and selector information ๐. But there are a bunch of other reasons, beyond not having a private key, why a signer could choose not to sign an email ๐.
Informative note: Signing modules can be built into any part of the mail system, including an MUA, a SUBMISSION server, or an MTA ๐ง. Wherever it's implemented, signers should be careful about signing (and thereby asserting responsibility for) messages that might be problematic ๐ฌ. For example, inside a trusted enclave the signing address might be derived from the header according to local policy. SUBMISSION servers might only sign messages from users who are properly authenticated and authorized ๐.
Informative implementer advice: SUBMISSION servers should not sign Received header fields if the outgoing gateway MTA obfuscates Received header fields, for example to hide the details of internal topology ๐ต๏ธโโ๏ธ.
If an email can't be signed for some reason, what happens to it is a local policy decision ๐.
5.2. Select a Private Key and Corresponding Selector Information ๐๏ธ
This specification doesn't define how a signer should choose which private key and selector information to use ๐คทโโ๏ธ. Right now, all selectors are equal as far as this spec is concerned, so the decision is mostly about administrative convenience ๐ . Distribution and management of private keys is also outside the scope of this document ๐ธ.
Informative operations advice: A signer should not sign with a private key when the selector containing the corresponding public key is expected to be revoked or removed before the verifier has a chance to validate the signature โณ. The signer should expect that verifiers might defer validation, maybe until the message is actually read by the final recipient ๐ฌ. Especially when rotating to a new key pair, signing should immediately start with the new private key, and the old public key should be kept for a reasonable validation interval before it's removed from the key server ๐.
5.3. Normalize the Message to Prevent Transport Conversions ๐งผ
Some messages, especially ones using 8-bit characters, get modified in transit, most notably converted to 7-bit form ๐ฑ. Those conversions will break DKIM signatures. To minimize the chances of breakage, signers SHOULD convert the message to a suitable MIME content transfer encoding, like quoted-printable or base64, as described in MIME Part One [RFC2045], before signing ๐. That conversion is outside the scope of DKIM. The actual message SHOULD be converted to 7-bit MIME by an MUA or MSA before it's presented to the DKIM algorithm โจ.
If the message is submitted to the signer with any local encoding that will be modified before transmission, that modification to canonical [RFC2822] form MUST be done before signing ๐. Specifically, bare CR or LF characters (some systems use these as a local line separator convention) MUST be converted to the SMTP-standard CRLF sequence before the message is signed ๐. Any conversion like this SHOULD be applied to the message actually sent to the recipient(s), not just to the version presented to the signing algorithm ๐ฆ.
More generally, the signer MUST sign the message as it's expected to be received by the verifier, rather than in some local or internal form ๐.
5.4. Determine the Header Fields to Sign ๐
The From header field MUST be signed (that is, included in the h= tag of the resulting DKIM-Signature header field) ๐. Signers SHOULD NOT sign an existing header field that's likely to be legitimately modified or removed in transit ๐
โโ๏ธ. Specifically, [RFC2821] explicitly permits modification or removal of the Return-Path header field in transit ๐ค๏ธ. Signers MAY include any other header fields present at the time of signing, at the signer's discretion ๐ท.
Informative operations note: Choosing which header fields to sign is kinda non-obvious ๐คฏ. One strategy is to sign all existing, non-repeatable header fields. Another is to sign only header fields that are likely to be displayed to, or otherwise likely to affect how the message is processed by, the receiver. A third strategy is to sign only "well known" headers ๐ญ. Note that verifiers may treat unsigned header fields with extreme skepticism, including refusing to display them to the end user, or even ignoring the signature if it doesn't cover certain header fields ๐. For this reason, signing fields present in the message such as Date, Subject, Reply-To, Sender, and all MIME header fields is highly advised ๐ซถ.
The DKIM-Signature header field is always implicitly signed, and it MUST NOT be included in the h= tag except to indicate that other preexisting signatures are also signed ๐.
Signers MAY claim to have signed header fields that don't exist. That is, signers MAY include the header field name in the h= tag even if that header field isn't in the message ๐ซฅ. When computing the signature, the non-existing header field MUST be treated as the null string, including the header field name, header field value, all punctuation, and the trailing CRLF ๐.
Informative rationale: This lets signers explicitly assert the absence of a header field. If that header field gets added later, the signature will fail ๐จ.
Informative note: A header field name only needs to be listed once more than the actual number of that header field in a message at the time of signing, in order to prevent any further additions ๐งฎ. For example, if there's a single Comments header field at signing time, listing Comments twice in theh=tag is enough to prevent any number of Comments header fields from being appended. It's not necessary (but it's legal) to list Comments three or more times in theh=tag ๐.
Signers who choose to sign an existing header field that occurs more than once in the message (such as Received) MUST sign the physically last instance of that header field in the header block ๐ซก. Signers who want to sign multiple instances of such a header field MUST include the header field name multiple times in the h= tag of the DKIM-Signature header field, and MUST sign those header fields in order from the bottom of the header field block to the top โฌ๏ธ. The signer MAY include more instances of a header field name in h= than there are actual corresponding header fields, to indicate that additional header fields of that name SHOULD NOT be added ๐ซ.
Informative example:
If the signer wants to sign two existing Received header fields, and the existing header contains:
Received: <A>
Received: <B>
Received: <C>
then the resulting DKIM-Signature header field should read:
DKIM-Signature: ... h=Received : Received : ...
and Received header fields <C> and <B> will be signed in that order ๐ฆ.
Signers should be careful about signing header fields that might get additional instances added later in the delivery process ๐ฌ. Those header fields might be inserted after the signed instance, or otherwise reordered. Trace header fields (such as Received) and Resent-* blocks are the only fields [RFC2822] prohibits from being reordered ๐ค๏ธ. Since DKIM-Signature header fields may be reordered by some intermediate MTAs, signing existing DKIM-Signature header fields is error-prone ๐ .
Informative admonition: Even though [RFC2822] permits header fields to be reordered (except Received header fields), reordering of signed header fields with multiple instances by intermediate MTAs will break DKIM signatures ๐. Such anti-social behavior should be avoided ๐ โโ๏ธ.
Informative implementer's note: Although this specification doesn't require it, all end-user visible header fields should be signed to avoid possible "indirect spamming" ๐ซ๐ง. For example, if the Subject header field isn't signed, a spammer can resend a previously signed mail and replace the legitimate subject with a one-line spam ๐คก. Not okay!! ๐ค
5.5. Recommended Signature Content ๐
Okay bestie, so to play nicely with the widest range of verifiers ๐ฆ, it is recommended that signers follow the practices in this section when signing a message. These are generic recommendations for the general case, though, so specific senders may wish to tweak them for their own situations โจ. Verifiers MUST be capable of verifying signatures even if one or more of the recommended header fields is not signed (with the exception of From, which must always be signed), or if one or more of the disrecommended header fields is signed ๐ซถ. Verifiers do have the option of ignoring signatures that don't cover a sufficient portion of the header or body, just as they may ignore signatures from an identity they don't trust ๐.
The following header fields SHOULD be included in the signature, if they are present in the message being signed:
From(REQUIRED in all signatures)Sender,Reply-ToSubjectDate,Message-IDTo,CcMIME-VersionContent-Type,Content-Transfer-Encoding,Content-ID,Content-DescriptionResent-Date,Resent-From,Resent-Sender,Resent-To,Resent-Cc,Resent-Message-IDIn-Reply-To,ReferencesList-Id,List-Help,List-Unsubscribe,List-Subscribe,List-Post,List-Owner,List-Archive
The following header fields SHOULD NOT be included in the signature:
Return-PathReceivedComments,KeywordsBcc,Resent-BccDKIM-Signature
Optional header fields (the ones not mentioned above) normally SHOULD NOT be included in the signature ๐, because additional header fields of the same name might get legitimately added or reordered before verification. There are likely to be legitimate exceptions to this rule, though, because there's a huge variety of application-specific header fields that can be applied to a message, and some of them are unlikely to be duplicated, modified, or reordered ๐.
Signers SHOULD choose canonicalization algorithms based on the types of messages they process and how much risk they're willing to take. For example, e-commerce sites sending mostly purchase receipts, which aren't expected to go through mailing lists or other software likely to modify messages, will generally prefer "simple" canonicalization. Sites sending mostly person-to-person email will likely prefer to be more resilient to modification during transport, so they'll use "relaxed" canonicalization ๐.
Signers SHOULD NOT use l= unless they intend to accommodate intermediate mail processors that append text to a message. For example, lots of mailing list processors append "unsubscribe" info to message bodies. If signers do use l=, they SHOULD include the entire message body that exists at the time of signing when computing the count. In particular, signers SHOULD NOT specify a body length of 0, since some verifiers may interpret that as a meaningless signature ๐.
5.6. Compute the Message Hash and Signature ๐ฅ
The signer MUST compute the message hash as described in Section 3.7 and then sign it using the selected public-key algorithm. This results in a DKIM-Signature header field that includes the body hash and a signature of the header hash, where that header includes the DKIM-Signature header field itself ๐ง.
Entities such as mailing list managers that implement DKIM, and that modify the message or a header field (for example, inserting unsubscribe information) before retransmitting the message, SHOULD check any existing signature on input and MUST make such modifications before re-signing the message ๐.
The signer MAY elect to limit the number of bytes of the body that will be included in the hash, and hence signed. The length actually hashed should be inserted in the l= tag of the DKIM-Signature header field โจ.
5.7. Insert the DKIM-Signature Header Field ๐
Finally, the signer MUST insert the DKIM-Signature header field created in the previous step before transmitting the email. The DKIM-Signature header field MUST be the same as the one used to compute the hash as described above, except that the value of the b= tag MUST be the appropriately signed hash computed in the previous step. That hash gets signed using the algorithm specified in the a= tag of the DKIM-Signature header field, and using the private key corresponding to the selector given in the s= tag of the DKIM-Signature header field, as chosen above in Section 5.2 ๐ฆ
The DKIM-Signature header field MUST be inserted before any other DKIM-Signature fields in the header block.
INFORMATIVE IMPLEMENTATION NOTE: The easiest way to achieve this is to insert theDKIM-Signatureheader field at the beginning of the header block. In particular, it may be placed before any existingReceivedheader fields. This is consistent with treatingDKIM-Signatureas a trace header field ๐ธ.
6. Verifier Actions ๐ซง
Since a signer MAY remove or revoke a public key at any time, it is recommended that verification happen in a timely manner. In many configurations, the most timely place is during acceptance by the border MTA or shortly after. In particular, deferring verification until the end user accesses the message is discouraged ๐ญ.
A border or intermediate MTA MAY verify the message signature(s). An MTA that has performed verification MAY communicate the result by adding a verification header field to incoming messages. This considerably simplifies things for the user, who can now use an existing mail user agent ๐. Most MUAs can filter messages based on header fields or content, and those filters would be used to implement whatever policy the user wants regarding unsigned mail โจ.
A verifying MTA MAY implement a policy regarding unverifiable mail, regardless of whether it applies the verification header field to signed messages ๐ .
Verifiers MUST produce a result that is semantically equivalent to applying the following steps in the order listed. In practice, several of these steps can be performed in parallel to improve performance ๐.
6.1. Extract Signatures from the Message ๐
The order in which verifiers try DKIM-Signature header fields is not defined; verifiers MAY try signatures in any order they like. For example, one implementation might try the signatures in textual order, whereas another might try signatures by identities that match the contents of the From header field before trying other signatures. Verifiers MUST NOT attribute ultimate meaning to the order of multiple DKIM-Signature header fields. In particular, there's reason to believe some relays will reorder the header fields in potentially arbitrary ways ๐.
INFORMATIVE IMPLEMENTATION NOTE: Verifiers might use the order as a clue to signing order in the absence of any other information. However, other clues as to the semantics of multiple signatures (such as correlating the signing host with Received header fields) may also be considered.
A verifier SHOULD NOT treat a message that has one or more bad signatures and no good signatures differently from a message with no signature at all. That kind of treatment is a matter of local policy and is beyond the scope of this document ๐ซถ.
When a signature successfully verifies, a verifier will either stop processing or attempt to verify any other signatures, at the discretion of the implementation. A verifier MAY limit the number of signatures it tries, to avoid denial-of-service attacks ๐ก๏ธ.
INFORMATIVE NOTE: An attacker could send messages with large numbers of faulty signatures, each of which would require a DNS lookup and corresponding CPU time to verify the message. This could be an attack on the domain that receives the message, slowing the verifier down by requiring it to do a huge number of DNS lookups and/or signature verifications. It could also be an attack against the domains listed in the signatures, essentially by enlisting innocent verifiers to launch an attack against the DNS servers of the actual victim ๐ฑ.
In the following description, text reading "return status (explanation)" (where "status" is one of PERMFAIL or TEMPFAIL) means that the verifier MUST immediately cease processing that signature. The verifier SHOULD proceed to the next signature, if any is present, and completely ignore the bad signature. If the status is PERMFAIL, the signature failed and should not be reconsidered. If the status is TEMPFAIL, the signature couldn't be verified at this time but may be tried again later. A verifier MAY either defer the message for later processing, perhaps by queueing it locally or issuing a 451/4.7.5 SMTP reply, or try another signature. If no good signature is found and any of the signatures resulted in a TEMPFAIL status, the verifier MAY save the message for later processing. The "(explanation)" is not normative text; it's provided solely for clarification ๐.
Verifiers SHOULD ignore any DKIM-Signature header fields where the signature does not validate. Verifiers that are prepared to validate multiple signature header fields SHOULD proceed to the next signature header field, should one exist. However, verifiers MAY make note of the fact that an invalid signature was present, for consideration at a later step ๐.
INFORMATIVE NOTE: The rationale for this requirement is to permit messages that have invalid signatures but also a valid signature to work. For example, a mailing list exploder might opt to leave the original submitter's signature in place even though the exploder knows it's modifying the message in a way that will break that signature, and the exploder inserts its own signature. In this case, the message should succeed even in the presence of the known-broken signature ๐.
For each signature to be validated, the following steps should be performed in such a manner as to produce a result that is semantically equivalent to performing them in the indicated order ๐ง
6.1.1. Validate the Signature Header Field โจ
Okay bestie, this is the bouncer step ๐ง๐
Implementers MUST meticulously validate the format and values in the DKIM-Signature header field. If there's any inconsistency or unexpected value, the header field MUST be completely ignored and the verifier MUST return PERMFAIL (signature syntax error). Being "liberal in what you accept" is definitely a bad strategy in this security context. ๐ซ Quick catch though: unknown tags in a DKIM-Signature header field are totally allowed, so they don't count as an inconsistency. ๐ฆ
Verifiers MUST ignore DKIM-Signature header fields with a v= tag that is inconsistent with this specification, and they MUST return PERMFAIL (incompatible version). ๐
โโ๏ธ
INFORMATIVE IMPLEMENTATION NOTE: An implementation may, of course, choose to also verify signatures generated by older versions of this specification. ๐ธ
If any tag listed as "required" in Section 3.5 is missing from the DKIM-Signature header field, the verifier MUST ignore the DKIM-Signature header field and MUST return PERMFAIL (signature missing required tag). ๐ฅบ
INFORMATIONAL NOTE: The tags listed as required in Section 3.5 arev=,a=,b=,bh=,d=,h=, ands=. Should there be a conflict between this note and Section 3.5, Section 3.5 is normative. ๐
If the DKIM-Signature header field doesn't have an i= tag, the verifier MUST behave as though that tag's value were @d, where d is the value from the d= tag. ๐ง
Verifiers MUST confirm that the domain in the d= tag is the same as, or a parent domain of, the domain part of the i= tag. If it isn't, the DKIM-Signature header field MUST be ignored and the verifier SHOULD return PERMFAIL (domain mismatch). ๐
If the h= tag doesn't include the From header field, the verifier MUST ignore the DKIM-Signature header field and MUST return PERMFAIL (From field not signed). Not it! ๐
โโ๏ธ
Verifiers MAY ignore the DKIM-Signature header field and return PERMFAIL (signature expired) if it has an x= tag and the signature has expired. โฐ
Verifiers MAY ignore the DKIM-Signature header field if the domain the signer used in the d= tag isn't associated with a valid signing entity. For example, signatures with d= values such as com and co.uk may be ignored. The list of unacceptable domains SHOULD be configurable. ๐
Verifiers MAY ignore the DKIM-Signature header field and return PERMFAIL (unacceptable signature header) for any other reason. For example, if the signature doesn't sign header fields the verifier considers essential. As a case in point, if MIME header fields aren't signed, certain attacks may be possible, and the verifier would prefer to avoid them. ๐ก๏ธ๐ฅ
6.1.2. Get the Public Key ๐
The public key for a signature is needed to finish the verification process. How you fetch it depends on the query type set by the q= tag in the DKIM-Signature header field. Obviously, you only need to retrieve a public key if extracting the signature information went completely smoothly. ๐ง Details of key management and representation are in Section 3.6. The verifier MUST validate the key record and MUST ignore any public key records that are malformed. ๐
When validating a message, a verifier MUST perform the following steps in a way that's semantically the same as doing them in the order listed. (Some implementations may parallelize or reorder these steps, as long as the semantics stay unchanged. Smart. ๐ง โจ)
- Retrieve the public key as described in Section 3.6, using the algorithm in the
q=tag, the domain from thed=tag, and the selector from thes=tag. ๐ - If the query for the public key doesn't respond, the verifier MAY defer accepting this email and return
TEMPFAIL(key unavailable). If verification happens during the incoming SMTP session, this MAY be done with a451/4.7.5SMTP reply code. Alternatively, the verifier MAY store the message in the local queue for a later try, or ignore the signature. Heads up, though: storing messages in a local queue is subject to denial-of-service attacks. ๐ฌ - If the query for the public key fails because the corresponding key record doesn't exist, the verifier MUST immediately return
PERMFAIL(no key for signature). ๐ซ - If the query for the public key returns multiple key records, the verifier may choose one of them, or may cycle through them and perform the remaining steps on each record at the implementer's discretion. The order of the key records is unspecified. ๐ฒ If the verifier cycles through the key records, then the "return ..." wording in the rest of this section means "try the next key record, if any; if none, return to try another signature in the usual way." ๐
- If the result from the query doesn't follow the format this specification defines, the verifier MUST ignore the key record and MUST return
PERMFAIL(key syntax error). Verifiers are urged to validate the syntax of key records carefully to avoid attempted attacks. ๐ In particular, the verifier MUST ignore keys with a version code (v=tag) that they don't implement. ๐ - If the
g=tag in the public key doesn't match the Local-part of thei=tag in the message signature header field, the verifier MUST ignore the key record and MUST returnPERMFAIL(inapplicable key). If the Local-part of thei=tag on the message signature isn't present, theg=tag must be*(valid for all addresses in the domain), or the entireg=tag must be omitted (which defaults tog=*). Otherwise, the verifier MUST ignore the key record and MUST returnPERMFAIL(inapplicable key). Apart from this test, verifiers SHOULD NOT treat a message signed with a key record that has ag=tag any differently than one without. In particular, verifiers SHOULD NOT prefer messages that seem to have an individual signature because of ag=tag versus a domain signature. ๐ - If the
h=tag exists in the public key record, and the hash algorithm implied by thea=tag in theDKIM-Signatureheader field isn't in the contents of theh=tag, the verifier MUST ignore the key record and MUST returnPERMFAIL(inappropriate hash algorithm). ๐ โโ๏ธ - If the public key data (the
p=tag) is empty, then this key has been revoked. The verifier MUST treat this as a failed signature check and MUST returnPERMFAIL(key revoked). There's no defined semantic difference between a revoked key and a key record that's been removed. ๐ชฆ - If the public key data isn't suitable for the algorithm and key types defined by the
a=andk=tags in theDKIM-Signatureheader field, the verifier MUST immediately returnPERMFAIL(inappropriate key algorithm). ๐
6.1.3. Compute the Verification ๐งฎ
Given a signer and a public key, verifying a signature means doing actions that are semantically equivalent to these steps. ๐
- Based on the algorithm defined in the
c=tag, the body length in thel=tag, and the header field names in theh=tag, prepare a canonicalized version of the message as described in Section 3.7. (This version doesn't actually need to be instantiated, babe. ๐) When matching header field names in theh=tag against the actual message header fields, comparisons MUST be case-insensitive. ๐ - Based on the algorithm indicated in the
a=tag, compute the message hashes from the canonical copy as described in Section 3.7. ๐งพ - Verify that the hash of the canonicalized message body computed in the previous step matches the hash value in the
bh=tag. If the hash doesn't match, the verifier SHOULD ignore the signature and returnPERMFAIL(body hash did not verify). ๐ - Using the signature in the
b=tag, verify the signature against the header hash, using the mechanism for the public key algorithm described in thea=tag. If the signature doesn't validate, the verifier SHOULD ignore the signature and returnPERMFAIL(signature did not verify). ๐ - Otherwise, the signature has verified correctly. ๐๐
INFORMATIVE IMPLEMENTER'S NOTE: Implementations might wish to start the public-key query in parallel with calculating the hash, since the public key isn't needed until the final decryption is calculated. Implementations may also verify the signature on the message header before checking that the message hash listed in the bh= tag matches the actual message body. However, if the body hash doesn't match, the entire signature must be considered to have failed. ๐งฉ
A body length in the l= tag of the signature limits how many bytes of the body get passed to the verification algorithm. All data beyond that limit is not validated by DKIM. ๐ Hence, verifiers might treat a message containing bytes beyond the indicated body length with suspicion. For example, they could truncate the message at the indicated body length, declare the signature invalid (e.g., by returning PERMFAIL (unsigned content)), or pass the partial verification along to the policy module. ๐ต๏ธโโ๏ธ
INFORMATIVE IMPLEMENTATION NOTE: Verifiers that truncate the body at the indicated body length might pass along a malformed MIME message if the signer used the "N-4" trick (omitting the final "--CRLF") described in the informative note in Section 3.4.5. Such verifiers may wish to check for this case and include a trailing "--CRLF" to avoid breaking the MIME structure. A simple way to do that might be to append "--CRLF" to any "multipart" message with a body length. If the MIME structure is already correctly formed, this will appear in the postlude and won't be displayed to the end user. ๐โจ
6.2. Communicate Verification Results ๐ฃ
Verifiers that want to share the results of verification with other parts of the mail system may do so however they like. ๐
For example, implementations might choose to add an email header field to the message before passing it on. Any such header field SHOULD be inserted before any existing DKIM-Signature or preexisting authentication status header fields in the header field block. ๐งฑ
INFORMATIVE ADVICE to MUA filter writers: Patterns that search for results header fields to visibly mark authenticated mail for end users should verify that the header field was added by the appropriate verifying domain, and that the verified identity matches the author identity the MUA will display. In particular, MUA filters should not be influenced by bogus results header fields added by attackers. To get around this attack, verifiers may wish to delete existing results header fields after verification and before adding a new one. ๐ก๏ธ๐
6.3. Interpret Results/Apply Local Policy โจ
Okay so, what a verifier actually does with the result is literally out of scope for this spec ๐ But here's the tea: a signed email gives the receiving system something an unsigned one just can't. An authenticated email creates a predictable identifier, so other decisions like trust and reputation can be managed reliably ๐ฆ Unsigned email has no reliable identifier to hang trust and reputation on, so it's reasonable to treat it as having zero trust and no positive reputation ๐
In general, verifiers SHOULD NOT reject messages just because they have no signature or an unverifiable one ๐ Doing that would cause severe interoperability problems, and nobody wants that drama. Still, if a verifier does decide to reject these messages (say, it's talking to a peer who agreed beforehand to only send signed messages ๐ค), and the verifier runs synchronously with the SMTP session and the signature is missing or doesn't verify, the MTA SHOULD use a 550/5.7.x reply code.
If the public key can't be fetched, maybe because the key server is down, a temporary failure message MAY be generated with a 451/4.7.5 reply code, like this:
451 4.7.5 Unable to verify signature - key server unavailable
Real talk: temporary failures like being unable to reach the key server or some other external service are the ONLY conditions that SHOULD use a 4xx SMTP reply code ๐ซถ Cryptographic signature verification failures MUST NOT return 4xx SMTP replies. Not ever, not even a little.
Once the signature has been verified, that info MUST be passed along to higher-level systems (like explicit allow/whitelists and reputation systems) and/or to the end user ๐ If the message is signed on behalf of any address other than the one in the From: header field, the mail system SHOULD take pains to make sure the actual signing identity is clear to the reader ๐
The verifier MAY treat unsigned header fields with extreme skepticism, including marking them as untrusted or even deleting them before the end user sees them ๐ง
Okay but here's the part that's lowkey tricky ๐ญ When verification fails, the symptom is obvious (the signature doesn't verify), but figuring out the exact cause can be way harder. If a selector can't be found, did the selector get removed, or did the value get changed somehow in transit? If the signature line is missing, was it never there, or did an overzealous filter nuke it? For diagnostic purposes, the exact reason the verification failed SHOULD be made available to the policy module and possibly recorded in the system logs ๐ And if the email can't be verified, it SHOULD be rendered the same as all unverified email, regardless of whether or not it looks like it was signed ๐
7. IANA Considerations ๐ธ
DKIM introduces some new namespaces that have been registered with IANA. In all cases, new values are assigned only for values that have been documented in a published RFC that has IETF Consensus [RFC2434]. Iykyk, it's a whole vibe ๐
7.1. DKIM-Signature Tag Specifications ๐ท๏ธ
A DKIM-Signature provides for a list of tag specifications. IANA has established the DKIM-Signature Tag Specification Registry for tag specifications that can be used in DKIM-Signature fields.
The initial entries in the registry comprise:
+------+-----------------+
| TYPE | REFERENCE |
+------+-----------------+
| v | (this document) |
| a | (this document) |
| b | (this document) |
| bh | (this document) |
| c | (this document) |
| d | (this document) |
| h | (this document) |
| i | (this document) |
| l | (this document) |
| q | (this document) |
| s | (this document) |
| t | (this document) |
| x | (this document) |
| z | (this document) |
+------+-----------------+
DKIM-Signature Tag Specification Registry Initial Values
7.2. DKIM-Signature Query Method Registry ๐
The "q=" tag-spec (specified in Section 3.5) provides for a list of query methods.
IANA has established the DKIM-Signature Query Method Registry for mechanisms that can be used to retrieve the key that will permit validation processing of a message signed using DKIM.
The initial entry in the registry comprises:
+------+--------+-----------------+
| TYPE | OPTION | REFERENCE |
+------+--------+-----------------+
| dns | txt | (this document) |
+------+--------+-----------------+
DKIM-Signature Query Method Registry Initial Values
7.3. DKIM-Signature Canonicalization Registry ๐งผ
The "c=" tag-spec (specified in Section 3.5) provides for a specifier for canonicalization algorithms for the header and body of the message.
IANA has established the DKIM-Signature Canonicalization Algorithm Registry for algorithms for converting a message into a canonical form before signing or verifying using DKIM.
The initial entries in the header registry comprise:
+---------+-----------------+
| TYPE | REFERENCE |
+---------+-----------------+
| simple | (this document) |
| relaxed | (this document) |
+---------+-----------------+
DKIM-Signature Header Canonicalization Algorithm Registry
Initial Values
The initial entries in the body registry comprise:
+---------+-----------------+
| TYPE | REFERENCE |
+---------+-----------------+
| simple | (this document) |
| relaxed | (this document) |
+---------+-----------------+
DKIM-Signature Body Canonicalization Algorithm Registry
Initial Values
7.4. _domainkey DNS TXT Record Tag Specifications ๐
A _domainkey DNS TXT record provides for a list of tag specifications. IANA has established the DKIM _domainkey DNS TXT Tag Specification Registry for tag specifications that can be used in DNS TXT Records.
The initial entries in the registry comprise:
+------+-----------------+
| TYPE | REFERENCE |
+------+-----------------+
| v | (this document) |
| g | (this document) |
| h | (this document) |
| k | (this document) |
| n | (this document) |
| p | (this document) |
| s | (this document) |
| t | (this document) |
+------+-----------------+
DKIM _domainkey DNS TXT Record Tag Specification Registry
Initial Values
7.5. DKIM Key Type Registry ๐
The "k=" <key-k-tag> (specified in Section 3.6.1) and the "a=" <sig-a-tag-k> (specified in Section 3.5) tags provide for a list of mechanisms that can be used to decode a DKIM signature.
IANA has established the DKIM Key Type Registry for such mechanisms.
The initial entry in the registry comprises:
+------+-----------+
| TYPE | REFERENCE |
+------+-----------+
| rsa | [RFC3447] |
+------+-----------+
DKIM Key Type Initial Values
7.6. DKIM Hash Algorithms Registry ๐งฎ
The "h=" <key-h-tag> (specified in Section 3.6.1) and the "a=" <sig-a-tag-h> (specified in Section 3.5) tags provide for a list of mechanisms that can be used to produce a digest of message data.
IANA has established the DKIM Hash Algorithms Registry for such mechanisms.
The initial entries in the registry comprise:
+--------+-------------------+
| TYPE | REFERENCE |
+--------+-------------------+
| sha1 | [FIPS.180-2.2002] |
| sha256 | [FIPS.180-2.2002] |
+--------+-------------------+
DKIM Hash Algorithms Initial Values
7.7. DKIM Service Types Registry ๐๏ธ
The "s=" <key-s-tag> tag (specified in Section 3.6.1) provides for a list of service types to which this selector may apply.
IANA has established the DKIM Service Types Registry for service types.
The initial entries in the registry comprise:
+-------+-----------------+
| TYPE | REFERENCE |
+-------+-----------------+
| email | (this document) |
| * | (this document) |
+-------+-----------------+
DKIM Service Types Registry Initial Values
7.8. DKIM Selector Flags Registry ๐ฉ
The "t=" <key-t-tag> tag (specified in Section 3.6.1) provides for a list of flags to modify interpretation of the selector.
IANA has established the DKIM Selector Flags Registry for additional flags.
The initial entries in the registry comprise:
+------+-----------------+
| TYPE | REFERENCE |
+------+-----------------+
| y | (this document) |
| s | (this document) |
+------+-----------------+
DKIM Selector Flags Registry Initial Values
7.9. DKIM-Signature Header Field ๐จ
IANA has added DKIM-Signature to the "Permanent Message Header Fields" registry (see [RFC3864]) for the "mail" protocol, using this document as the reference.
8. Security Considerations ๐
It has been observed that any mechanism that is introduced that attempts to stem the flow of spam is subject to intensive attack. Bestie, this is serious โจ DKIM needs to be carefully scrutinized to identify potential attack vectors and the vulnerability to each. See also [RFC4686].
8.1. Misuse of Body Length Limits ("l=" Tag) ๐จ
Body length limits (in the form of the "l=" tag) are subject to several potential attacks.
8.1.1. Addition of New MIME Parts to Multipart/*
Okay bestie, this one is spicy ๐. If the body length limit doesn't cover the closing MIME multipart section (including the trailing --CRLF bit), an attacker can intercept a properly signed multipart message and tack on a brand-new body part ๐ญ. Whether that actually does damage depends on the MIME type, the verifying MTA, and the receiving MUA, but it could let the attacker swap what the end user sees for something that looks like it came from a trusted source ๐.
For example, if attackers can append stuff to a text/html body part, they might exploit a bug in some MUAs that keep reading after a </html> marker. Then they could display HTML text on top of text that's already on screen ๐ซฃ. If a message has a multipart/alternative body part, they might be able to add a new body part that the displaying MUA prefers, which is giving sneaky energy ๐ฆ.
8.1.2. Addition of new HTML content to existing content
Several receiving MUA implementations don't stop rendering after a ""</html>"" tag ๐. Literally, this lets attackers do things like overlay images on top of existing text, and it's not cute ๐ค.
INFORMATIVE EXAMPLE: Appending the following text to an existing, properly closed message will in many MUAs result in inappropriate data being rendered on top of existing, correct data:
<div style="position: relative; bottom: 350px; z-index: 2;">
<img src="http://www.ietf.org/images/ietflogo2e.gif"
width=578 height=370>
</div>
8.2. Misappropriated Private Key
Okay so, if a user's private key lives on their computer and isn't protected by an appropriately secure mechanism, malware can send mail as that user and as any other user sharing the same private key ๐. The malware wouldn't be able to generate signed spoofs of other signers' addresses though, which would actually help identify the infected user and limit the sketchy social-engineering attacks ๐ต๏ธโโ๏ธ. This threat mainly applies to MUA-based implementations. Protecting private keys on servers can be easily achieved with specialized cryptographic hardware ๐.
A bigger problem happens if malware on lots of users' computers grabs their private keys and sends them over a covert channel to a site where they can be shared ๐ฑ. The compromised users would likely not know about it until they get "bounce" messages from mail they supposedly sent. Plenty of users might not understand what those bounces mean, so they wouldn't do anything about it ๐ฅฒ.
One countermeasure is to use a user-entered passphrase to encrypt the private key. BUT users tend to pick weak passphrases and reuse them for other stuff, which could let an attack against DKIM spill over into other domains ๐. The decoded private key might also be briefly exposed to malware when it's entered, or get captured by keystroke logging. Also, the added hassle of typing a passphrase every time someone sends a message would tend to discourage using a secure one ๐ฉ.
A somewhat more effective countermeasure is to send messages through an outgoing MTA that can authenticate the submitter with existing techniques (for example, SMTP Authentication). It can also validate the message itself (for example, checking that the header is legit and that the content passes a spam content check), and then sign the message with a key that matches the submitter's address โจ. Such an MTA can also cap how much outgoing mail each user is allowed to send, which further limits malware's ability to blast out bulk email ๐.
8.3. Key Server Denial-of-Service Attacks
Since the key servers are distributed (potentially separate for each domain), the number of servers you'd need to attack to defeat this mechanism Internet-wide is huge ๐. Still, key servers for individual domains could be attacked, which would stop verification of messages from that domain ๐ฌ. This isn't that different from an attacker denying service to the mail exchangers for a given domain, although it affects outgoing mail rather than incoming mail ๐ค.
A variation on this is that if a very large amount of mail were sent using spoofed addresses from a given domain, the key servers for that domain could get overwhelmed with requests ๐. However, verification has low overhead compared with handling the email message itself, so an attack like that would be hard to pull off ๐ .
8.4. Attacks Against the DNS
Since the DNS is a required binding for key services, specific attacks against the DNS must be considered ๐ง.
While the DNS is currently insecure [RFC3833], these security problems are the motivation behind DNS Security (DNSSEC) [RFC4033], and all users of the DNS will reap the benefit of that work ๐.
DKIM is only intended as a "sufficient" method of proving authenticity. It is NOT meant to give strong cryptographic proof about authorship or contents. Other technologies like OpenPGP [RFC2440] and S/MIME [RFC3851] handle those requirements ๐.
A second DNS security issue is the increased DNS traffic that comes from fetching selector-based data as well as fetching signing domain policy ๐. Widespread DKIM deployment will cause a significant increase in DNS queries to the claimed signing domain. In the case of forgeries on a large scale, DNS servers could see a substantial spike in queries ๐ญ.
A specific DNS security issue that DKIM verifiers should consider is the name chaining attack described in Section 2.3 of the DNS Threat Analysis [RFC3833]. While verifying a DKIM-Signature header field, a DKIM verifier could be prompted to retrieve a key record of an attacker's choosing ๐. This threat can be minimized by making sure that the name servers the verifier uses, including recursive name servers, strictly check "glue" and other additional information in DNS responses. That way they aren't vulnerable to this attack ๐ก๏ธ.
8.5. Replay Attacks
In this attack, a spammer sends a message to be spammed to an accomplice, which gets the message signed by the originating MTA ๐ญ. The accomplice then resends the message, original signature and all, to a large number of recipients. They might do this by sending it to many compromised machines acting as MTAs ๐คก. Since the messages weren't modified by the accomplice, they still have valid signatures. Chef's kiss, but make it villain ๐.
Partial solutions involve using reputation services to share the fact that a specific email address is being used for spam, and that messages from that signer are likely to be spam too ๐ฉ. This needs a real-time detection mechanism to react quickly enough. Still, these measures might be prone to abuse. For example, an attacker could resend a large number of messages received from a victim to make them look like a spammer ๐ต.
Large verifiers might be able to detect unusually large volumes of mail with the same signature in a short time period ๐. Smaller verifiers can get substantially the same volume of information through existing collaborative systems ๐ซถ.
8.6. Limits on Revoking Keys
When a large domain detects undesirable behavior from one of its users, it might want to revoke the key used to sign that user's messages. That way it can disavow responsibility for messages that haven't been verified yet or that are the subject of a replay attack ๐ โโ๏ธ. BUT the domain's ability to do that can be limited if the same key, for scalability reasons, is used to sign messages for many other users ๐ค. Mechanisms for explicitly revoking keys on a per-address basis have been proposed, but they still need further study regarding their utility and the DNS load they'd represent ๐ง .
8.7. Intentionally Malformed Key Records
It's possible for an attacker to publish key records in DNS that are intentionally malformed, aiming to cause a denial-of-service attack on a non-robust verifier implementation ๐. The attacker could then make a verifier read the malformed key record by sending a message to one of its users that references the malformed record in a (not necessarily valid) signature ๐ชค. Verifiers MUST thoroughly verify all key records retrieved from the DNS, and they MUST be robust against intentionally as well as unintentionally malformed key records ๐ ๏ธ. No cap, this one is non-negotiable ๐ .
8.8. Intentionally Malformed DKIM-Signature Header Fields
Verifiers MUST be prepared to receive messages with malformed DKIM-Signature header fields, and they MUST thoroughly verify the header field before depending on any of its contents ๐ซก. Trust nothing until you've checked it, periodt ๐.
8.9. Information Leakage
An attacker could figure out when a particular signature was verified by using a per-message selector and then monitoring their DNS traffic for the key lookup ๐๏ธ. This would act as the equivalent of a "web bug" for verification time, rather than for when the message was read ๐ฐ๏ธ. Sneaky, right? ๐
8.10. Remote Timing Attacks
In some cases, it may be possible to extract private keys using a remote timing attack [BONEH03] ๐ฑ. Implementations should consider obfuscating the timing to prevent such attacks ๐ญ.
8.11. Reordered Header Fields
Existing standards allow intermediate MTAs to reorder header fields ๐. If a signer signs two or more header fields of the same name, this can cause spurious verification errors on otherwise legit messages ๐. In particular, signers that sign any existing DKIM-Signature fields run the risk of having messages incorrectly fail to verify ๐ญ.
8.12. RSA Attacks
An attacker could create a large RSA signing key with a small exponent, which would force the verification key to have a large exponent instead. This makes verifiers burn considerable computing resources to verify the signature ๐ฅ. Verifiers might avoid this attack by refusing to verify signatures that reference selectors whose public keys have unreasonable exponents ๐ โโ๏ธ.
In general, an attacker might try to overwhelm a verifier by flooding it with messages that need verification ๐. This is similar to other MTA denial-of-service attacks and should be dealt with in a similar fashion ๐ช.
8.13. Inappropriate Signing by Parent Domains
The trust relationship described in Section 3.8 could conceivably be used by a parent domain to sign messages with identities in a subdomain that isn't administratively related to the parent ๐. For example, the ".com" registry could create messages with signatures using an i= value in the example.com domain ๐ณ. There's no general solution to this problem, since the administrative cut could occur anywhere in the domain name. For example, in the domain "example.podunk.ca.us" there are three administrative cuts (podunk.ca.us, ca.us, and us), and any of them could create messages with an identity in the full domain ๐บ๏ธ.
INFORMATIVE NOTE: This is considered an acceptable risk for the same reason that it is acceptable for domain delegation. For example, in the example above any of the domains could potentially simply delegate"example.podunk.ca.us"to a server of their choice and completely replace all DNS-served information. Note that a verifier MAY ignore signatures that come from an unlikely domain such as".com", as discussed in Section 6.1.1 โจ.
9. References
9.1. Normative References
These are the must-read docs, the ones the spec builds on, so you need them to really get it ๐โจ
[FIPS.180-2.2002]U.S. Department of Commerce, "Secure Hash Standard", FIPS PUB 180-2, August 2002.[ITU.X660.1997]"Information Technology - ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)", ITU-T Recommendation X.660, 1997.[RFC2045]Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996.[RFC2047]Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part Three: Message header field Extensions for Non-ASCII Text", RFC 2047, November 1996.[RFC2119]Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.[RFC2821]Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.[RFC2822]Resnick, P., "Internet Message Format", RFC 2822, April 2001.[RFC3447]Jonsson, J. and B. Kaliski, "Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1", RFC 3447, February 2003.[RFC3490]Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.[RFC4234]Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 4234, October 2005.
9.2. Informative References
These are the extra reading vibes ๐ง ๐ . Not required, but so worth a peek if you're curious about the deep stuff.
[BONEH03]Proc. 12th USENIX Security Symposium, "Remote Timing Attacks are Practical", 2003.[RFC1847]Galvin, J., Murphy, S., Crocker, S., and N. Freed, "Security Multiparts for MIME: Multipart/Signed and Multipart/Encrypted", RFC 1847, October 1995.[RFC2434]Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 2434, October 1998.[RFC2440]Callas, J., Donnerhacke, L., Finney, H., and R. Thayer, "OpenPGP Message Format", RFC 2440, November 1998.[RFC3766]Orman, H. and P. Hoffman, "Determining Strengths for Public Keys Used For Exchanging Symmetric Keys", RFC 3766, April 2004.[RFC3833]Atkins, D. and R. Austein, "Threat Analysis of the Domain Name System (DNS)", RFC 3833, August 2004.[RFC3851]Ramsdell, B., "S/MIME Version 3 Message Specification", RFC 3851, June 1999.[RFC3864]Klyne, G., Nottingham, M., and J. Mogul, "Registration Procedures for Message Header Fields", BCP 90, September 2004.[RFC4033]Arends, R., Austein, R., Larson, M., Massey, D., and S. Rose, "DNS Security Introduction and Requirements", RFC 4033, March 2005.[RFC4686]Fenton, J., "Analysis of Threats Motivating DomainKeys Identified Mail (DKIM)", RFC 4686, September 2006.[RFC4870]Delany, M., "Domain-Based Email Authentication Using Public Keys Advertised in the DNS (DomainKeys)", RFC 4870, May 2007.
Appendix A. Example of Use (INFORMATIVE) โจ
Okay, this part is my favourite ๐ฅน. It walks through a whole email's journey, from the moment it's sent to the moment it lands, and shows how all the pieces click together. The key used in this example is in Appendix C.
A.1. The User Composes an Email
Joe is writing to Suzie about dinner. Iconic, honestly ๐.
From: Joe SixPack <joe@football.example.com>
To: Suzie Q <suzie@shopping.example.net>
Subject: Is dinner ready?
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
Message-ID: <20030712040037.46341.5F8J@football.example.com>
Hi.
We lost the game. Are you hungry yet?
Joe.
A.2. The Email Is Signed
Now the example.com outbound email server signs it, and the email gets its signature glow-up โจ๐. It now looks like this:
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
c=simple/simple; q=dns/txt; i=joe@football.example.com;
h=Received : From : To : Subject : Date : Message-ID;
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
4bmp/YzhwvcubU4=;
Received: from client1.football.example.com [192.0.2.1]
by submitserver.example.com with SUBMISSION;
Fri, 11 Jul 2003 21:01:54 -0700 (PDT)
From: Joe SixPack <joe@football.example.com>
To: Suzie Q <suzie@shopping.example.net>
Subject: Is dinner ready?
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
Message-ID: <20030712040037.46341.5F8J@football.example.com>
Hi.
We lost the game. Are you hungry yet?
Joe.
The signing email server needs the private key tied to the "brisbane" selector to make this signature. No private key, no signature, no cap ๐.
A.3. The Email Signature Is Verified
Usually an inbound SMTP server or possibly the final delivery agent does the checking ๐ต๏ธโโ๏ธ. Intervening MTAs can also verify it if they choose to, which is lowkey a power move. The verification takes the domain "example.com" from the "d=" tag and the selector "brisbane" from the "s=" tag in the DKIM-Signature header field, and builds the DNS DKIM query for:
brisbane._domainkey.example.com
Verification starts with the physically last Received header field, then the From header field, and so on, in the order listed in the "h=" tag. After that comes a single CRLF, then the body (starting with "Hi."). The email gets canonically prepared for verifying with the "simple" method. The result of the query and the signature check gets stored (in this example) in the X-Authentication-Results header field line. Once it passes, the email looks like this:
X-Authentication-Results: shopping.example.net
header.from=joe@football.example.com; dkim=pass
Received: from mout23.football.example.com (192.168.1.1)
by shopping.example.net with SMTP;
Fri, 11 Jul 2003 21:01:59 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
c=simple/simple; q=dns/txt; i=joe@football.example.com;
h=Received : From : To : Subject : Date : Message-ID;
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
4bmp/YzhwvcubU4=;
Received: from client1.football.example.com [192.0.2.1]
by submitserver.example.com with SUBMISSION;
Fri, 11 Jul 2003 21:01:54 -0700 (PDT)
From: Joe SixPack <joe@football.example.com>
To: Suzie Q <suzie@shopping.example.net>
Subject: Is dinner ready?
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
Message-ID: <20030712040037.46341.5F8J@football.example.com>
Hi.
We lost the game. Are you hungry yet?
Joe.
Appendix B. Usage Examples (INFORMATIVE) ๐
DKIM signing and validating can be used in lots of different ways for lots of different operational scenarios ๐. This appendix talks through some of the common ones.
NOTE: Everything in this appendix is for information only ๐ซถ. It describes various ways DKIM can be used, given particular constraints and needs. None of these examples are meant as explanation or guidance on DKIM spec details when you're building an implementation, so don't take them as that!
B.1. Alternate Submission Scenarios
In the simplest setup, a user's MUA, MSA, and Internet (boundary) MTA all live in the same administrative environment and use the same domain name. So every part involved in submission and the first transfer is related, very neat โจ. But it's pretty common for two or more of those parts to be run by different admins, and that makes it tricky to pick and manage the domain name for signing, and to line it up with the common email identity header fields ๐ค.
B.1.1. Delegated Business Functions
Some organizations hand specific business jobs to separate groups, whether they're inside the org or outside it ๐ผ. The goal is to let that group sign some mail, but to limit which signatures they can make. DKIM selectors (the "s=" signature tag) and granularity (the "g=" key tag) make this kind of restricted permission possible ๐. Outsourced jobs like legit email marketing providers and corporate benefits providers are classic examples.
Here, the delegated group needs to send signed messages using the email domain of the client company ๐จ. At the same time, the client is usually hesitant to register a key for the provider that lets them send for any address in the domain. Understandable, bestie ๐.
There are a few ways to run this. In one, the client org handles all of the public query service (like DNS) admin. In another, it uses DNS delegation so the delegated group can manage the DKIM key record going forward ๐ง.
If the client org keeps all of the DNS admin, the outsourcing company can generate a key pair and give the public key to the client. The client then registers it in the query service under a unique selector that only authorizes a specific From header field Local-part. For example, a client with the domain "example.com" could set the selector record to "g=winter-promotions", so the signature only counts for mail with a From address of "winter-promotions@example.com". The provider can send with that specific address and it'll verify properly ๐
. The client keeps control of that address too, because they can revoke the key at any time ๐ฅ.
If the client wants the delegated group to handle the DNS admin, the domain name tied to the selector can point to the provider's DNS server. The provider then creates and maintains all of the DKIM signature info for that selector ๐ธ. In this setup the client can't put constraints on the Local-part of the addresses that get signed. But they can still pull the provider's signing rights by removing the DNS delegation record ๐.
B.1.2. PDAs and Similar Devices
okay so PDAs are literally the reason we need multiple keys per domain ๐ say John Doe wants to send mail from his work address, jdoe@example.com ๐ผ, but his tiny device can't set up a Virtual Private Network (VPN) connection to the corporate network. maybe the device is limited, or maybe his Internet access provider has restrictions ๐. if the device has a private key registered for jdoe@example.com by the administrator of the example.com domain, plus software that can sign messages, John can sign the message right on the device before it goes out through the access provider's outgoing network โจ slay.
B.1.3. Roaming Users
roaming users end up in situations where it's handy or necessary to use an SMTP server that isn't their home server ๐งณ think conferences, lots of hotels, that kind of thing. in those cases, a signature added by the submission service uses an identity that's different from the user's home system, which is kind of a plot twist ๐ญ
ideally, roaming users would connect back to their home server through either a VPN or a SUBMISSION server running with SMTP AUTHentication on port 587 ๐. if signing can happen on the roaming user's laptop, they can sign before submitting, although the risk of further modification is high ๐. if neither of those is possible, these roaming users won't be able to send mail signed with their own domain key ๐ฅฒ
B.1.4. Independent (Kiosk) Message Submission
standalone services like walk-up kiosks and web-based info services don't have any lasting email relationship with the user, but users sometimes ask for mail to be sent on their behalf ๐ฌ. like, a news website often lets you forward an article to a friend. this is usually done with the reader's own email address so it shows who the author is ๐. people call this the "Evite problem", named after the website of the same name that lets you send invites to friends ๐
a common fix is to keep the reader's address in the From header field, but put an address owned by the posting site in the Sender header field. the posting site can then sign the message using the domain in the Sender field. this gives the receiving email site useful info, since it can connect the signing domain with the initial submission role โจ
receiving sites often want to show end users info about mail handled this way ๐. honestly, the real efficacy of different approaches is something for human factors usability research ๐ง , but one technique is for the verifying system to rewrite the From header field so it shows the address that was verified. for example:
From: John Doe via news@news-site.com <jdoe@example.com>
(Note that such rewriting will break a signature, unless it is done after the verification pass is complete.) โ ๏ธ
B.2. Alternate Delivery Scenarios
email often lands in a mailbox with a different address from the one used at submission ๐ญ. in those cases, an intermediary works at the address originally used and then passes the message on to the final destination. this mediation creates some challenges for DKIM signatures ๐ฆ
B.2.1. Affinity Addresses
"Affinity addresses" let a user keep a stable email address even while they hop between email providers ๐ง. they're usually tied to college alumni groups, professional orgs, and rec clubs the user expects a long-term relationship with ๐ซ. these domains usually forward incoming mail, and they often have a web app that logs the user in and lets them change the forwarding address ๐ป. but these services usually rely on users sending outgoing mail through their own providers' MTAs. so mail signed with the affinity address's domain isn't signed by an entity administered by the organization that owns that domain ๐ค
with DKIM, affinity domains could use the web app to let users register per-user keys for signing messages on behalf of their affinity address ๐. the user takes away the secret half of the key pair for signing, and the affinity domain publishes the public half in DNS so verifiers can access it ๐ซถ
this is another use of user-level keying, and affinity domains would typically have a huge number of user-level keys ๐. alternatively, the affinity domain could handle outgoing mail itself, running a mail submission agent that authenticates users before accepting and signing messages for them ๐ก๏ธ. of course, this depends on the user's service provider not blocking the TCP ports used for mail submission ๐ซ
B.2.2. Simple Address Aliasing (.forward)
sometimes a recipient can set up an email address to automatically redirect messages from the original address to another, like with a Unix .forward file ๐ช. here, the recipient's domain's mail handling service usually redirects the message without changing it, except it adds a Received header field and changes the envelope recipient address ๐จ. so the person at the final mailbox will probably be able to verify the original signature, since the signed content hasn't changed, and DKIM can validate the message signature ๐
B.2.3. Mailing Lists and Re-Posters
services that take delivery of a message and then resubmit it behave all over the place ๐. the big example is mailing lists (collectively called "forwarders" below) ๐. some change nothing except adding a Received header field and changing the envelope info. others add header fields, change the Subject header field, add content to the body (usually at the end), or reformat the body somehow โ๏ธ. the simple ones produce messages pretty similar to the automated alias services, and the more elaborate ones basically create a new message ๐ญ
a Forwarder that doesn't modify the body or signed header fields is likely to keep the existing signature valid โ . it also could choose to add its own signature.
Forwarders that modify a message in a way that could break an existing signature are especially good candidates for adding their own signatures (e.g., mailing-list-name@example.net) ๐. since (re-)signing means taking responsibility for the message content, these signing forwarders are likely to be picky ๐ง. they forward or re-sign a message only if it was received with a valid signature, or if they have some other basis for knowing it isn't spoofed ๐ต๏ธ
a common habit among systems that are mostly mail redistributors is adding a Sender header field to identify the address used to sign the message ๐ฃ. this practice removes any preexisting Sender header field, as required by [RFC2822] ๐. the forwarder applies a new DKIM-Signature header field carrying the signature, public key, and related info of the forwarder ๐
Appendix C. Creating a Public Key (INFORMATIVE)
the default signature is an RSA signed SHA256 digest of the complete email ๐. to keep things easy to follow, we use the openssl command to show how keys and signatures get managed ๐ป. one way to generate a 1024-bit, unencrypted private key suitable for DKIM is to use openssl like this:
$ openssl genrsa -out rsa.private 1024
for increased security, the "-passin" parameter can also be added to encrypt the private key ๐. using this parameter will require entering a password for several of the following steps. servers may prefer to use hardware cryptographic support ๐ฅ๏ธ
the genrsa step results in the file rsa.private containing key information similar to this:
-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYtIxN2SnFC
jxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/RtdC2UzJ1lWT947qR+Rcac2gb
to/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB
AoGBALmn+XwWk7akvkUlqb+dOxyLB9i5VBVfje89Teolwc9YJT36BGN/l4e0l6QX
/1//6DWUTB3KI6wFcm7TWJcxbS0tcKZX7FsJvUz1SbQnkS54DJck1EZO/BLa5ckJ
gAYIaqlA9C0ZwM6i58lLlPadX/rtHb7pWzeNcZHjKrjM461ZAkEA+itss2nRlmyO
n1/5yDyCluST4dQfO8kAB3toSEVc7DeFeDhnC1mZdjASZNvdHS4gbLIA1hUGEF9m
3hKsGUMMPwJBAPW5v/U+AWTADFCS22t72NUurgzeAbzb1HWMqO4y4+9Hpjk5wvL/
eVYizyuce3/fGke7aRYw/ADKygMJdW8H/OcCQQDz5OQb4j2QDpPZc0Nc4QlbvMsj
7p7otWRO5xRa6SzXqqV3+F0VpqvDmshEBkoCydaYwc2o6WQ5EBmExeV8124XAkEA
qZzGsIxVP+sEVRWZmW6KNFSdVUpk3qzK0Tz/WjQMe5z0UunY9Ax9/4PVhp/j61bf
eAYXunajbBSOLlx4D+TunwJBANkPI5S9iylsbLs6NkaMHV6k5ioHBBmgCak95JGX
GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
-----END RSA PRIVATE KEY-----
to pull the public-key component out of the private key, use openssl like this:
$ openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM
this results in the file rsa.public containing key information similar to this:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkM
oGeLnQg1fWn7/zYtIxN2SnFCjxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/R
tdC2UzJ1lWT947qR+Rcac2gbto/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToI
MmPSPDdQPNUYckcQ2QIDAQAB
-----END PUBLIC KEY-----
this public-key data (without the BEGIN and END tags) is placed in the DNS ๐:
brisbane IN TXT ("v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ"
"KBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYt"
"IxN2SnFCjxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v"
"/RtdC2UzJ1lWT947qR+Rcac2gbto/NMqJ0fzfVjH4OuKhi"
"tdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB")
Appendix D. MUA Considerations ๐
Okay bestie, so when a DKIM signature gets verified, the processing system sometimes passes the result along to the recipient's MUA (that's the mail app, basically ๐ฌ). How to show this to users in a way that actually helps them is still being figured out through ongoing human factors usability research ๐ง . The usual move is to have the MUA highlight the address tied to the signing identity, so the user can see where the mail really came from โจ. An MUA could do that with visual cues like graphics, put the address in an alternate view, or even rewrite the original From address using the verified info. It's giving clarity ๐ฆ.
Some MUAs might show which header fields were protected by the validated DKIM signature. That could be a positive mark on the signed header fields, a negative mark on the unsigned ones, hiding the unsigned ones completely, or some mix of all of these ๐. If an MUA uses visual signals for signed header fields, it probably needs to be careful not to display unsigned header fields in a way the end user might think were signed ๐. That's a big "not me" moment waiting to happen. And if the message has an l= tag whose value doesn't reach the end of the message, the MUA might also hide or mark the part of the message body that wasn't signed ๐.
The info above is not meant to be exhaustive, so the MUA can highlight, accentuate, hide, or otherwise display any other information the MUA author thinks is important to the end user ๐. Main character energy for the MUA, honestly.
Appendix E. Acknowledgements ๐ซถ
The authors wanted to thank a whole squad of people for their valuable suggestions and constructive criticism ๐: Russ Allbery, Edwin Aoki, Claus Assmann, Steve Atkins, Rob Austein, Fred Baker, Mark Baugher, Steve Bellovin, Nathaniel Borenstein, Dave Crocker, Michael Cudahy, Dennis Dayman, Jutta Degener, Frank Ellermann, Patrik Faeltstroem, Mark Fanto, Stephen Farrell, Duncan Findlay, Elliot Gillum, Olafur Gu[eth]mundsson, Phillip Hallam-Baker, Tony Hansen, Sam Hartman, Arvel Hathcock, Amir Herzberg, Paul Hoffman, Russ Housley, Craig Hughes, Cullen Jennings, Don Johnsen, Harry Katz, Murray S. Kucherawy, Barry Leiba, John Levine, Charles Lindsey, Simon Longsdale, David Margrave, Justin Mason, David Mayne, Thierry Moreau, Steve Murphy, Russell Nelson, Dave Oran, Doug Otis, Shamim Pirzada, Juan Altmayer Pizzorno, Sanjay Pol, Blake Ramsdell, Christian Renaud, Scott Renfro, Neil Rerup, Eric Rescorla, Dave Rossetti, Hector Santos, Jim Schaad, the Spamhaus.org team, Malte S. Stretz, Robert Sanders, Rand Wacker, Sam Weiler, and Dan Wing ๐ธ. Iconic list, no notes.
The DomainKeys specification was a primary source for this spec, so it gets a big thank you too ๐. More info about DomainKeys is in [RFC4870] โจ.
Authors' Addresses ๐
Eric Allman
Sendmail, Inc.
6425 Christie Ave, Suite 400
Emeryville, CA 94608
USA
Phone: +1 510 594 5501
EMail: eric+dkim@sendmail.org
URI:
Jon Callas
PGP Corporation
3460 West Bayshore
Palo Alto, CA 94303
USA
Phone: +1 650 319 9016
EMail: jon@pgp.com
Mark Delany
Yahoo! Inc
701 First Avenue
Sunnyvale, CA 95087
USA
Phone: +1 408 349 6831
EMail: markd+dkim@yahoo-inc.com
URI:
Miles Libbey
Yahoo! Inc
701 First Avenue
Sunnyvale, CA 95087
USA
EMail: mlibbeymail-mailsig@yahoo.com
URI:
Jim Fenton
Cisco Systems, Inc.
MS SJ-9/2
170 W. Tasman Drive
San Jose, CA 95134-1706
USA
Phone: +1 408 526 5914
EMail: fenton@cisco.com
URI:
Michael Thomas
Cisco Systems, Inc.
MS SJ-9/2
170 W. Tasman Drive
San Jose, CA 95134-1706
Phone: +1 408 525 5386
EMail: mat@cisco.com
Full Copyright Statement ๐
Copyright (C) The IETF Trust (2007). Yes, that's the official vibe ๐๏ธ.
This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights ๐.
This document and the information in it are provided on an "AS IS" basis, and the legal disclaimer is serious business, so here it is word for word:
THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Intellectual Property ๐ฅ
The IETF doesn't take a position on whether any Intellectual Property Rights (or other rights) someone claims over the tech in this document are valid or how far they reach. It also doesn't say whether licenses are available, and it hasn't checked for any rights on its own ๐ . For how RFC documents handle rights, check BCP 78 and BCP 79 ๐.
You can get copies of IPR disclosures sent to the IETF Secretariat, plus any assurances of licenses, or the results of attempts to get a general license or permission for implementers or users, from the IETF online IPR repository at http://www.ietf.org/ipr ๐.
The IETF also invites anyone to point out any copyrights, patents, patent applications, or other proprietary rights that might cover technology needed to implement this standard. Send that info to the IETF at ietf-ipr@ietf.org ๐.
Acknowledgement ๐
Funding for the RFC Editor function is currently provided by the Internet Society ๐.
๐ฆ where this page comes from
- ietf: rfc4871 2007-05
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms