Hi all, I went through spec-06, bcp-01 and dns-00 looking for anything about header size limits in bytes and found nothing. BCP 7.5 covers the number of Message-Instance and DKIM2-Signature fields; I'm not trying to reopen the discussion about a ceiling on that number, but the size of those fields is the other half of the same problem and fits naturally in that section. Spec section 16 is still TBA. The only place the topic shows up is section 4.3.1 of draft-moccia-dkim2-deployment-profile, which the WG decided not to adopt, so I'm not building on it, and I'm not proposing anything about the recipe or JSON design either. This is a small operator note for the BCP, with proposed text further down.
I think this deserves a few paragraphs because receivers fail in three different ways when the header section gets too big. Some reject during the SMTP transaction, which is fine because the sender finds out. Some drop the connection. Others truncate silently, and for us that is the bad case. Every DKIM2-Signature covers all Message-Instance and DKIM2-Signature fields, so a single truncated field breaks every signature on the message, and the verifier reports "Message-Instance m=x contains invalid JSON" against a Reviser whose message was well formed when it left. I asked Claude to research what are the header limits defaults on different MTAs, message stores and cloud providers, details are below. "Total" is the whole header section, "per header" is one logical field. - Sendmail 8.18: MaxHeadersLength 32768 total, 552 5.6.0 [1] - Courier: BOFHHEADERLIMIT 100000 total (plus 500 headers and 5000 bytes per line), 534 [2] - Exchange Server: MaxHeaderSize 256 KB total, connection closed [3] - Exchange Online: 256 KB total and 32 KB per header, 552 5.3.4 [4] - Gmail: 512000 bytes total, 5000 fields, 32 KB per value (To, Cc and References exempt from the per-value cap but counted in the total), 552 5.3.4 [5] - Cisco ESA: 1000 header lines per listener, 552 #5.3.4 [6] - Exim: header_maxsize 1 MiB total, 552 [7] - Maddy: max_header_size 1 MiB total, 552 5.3.4 [8] - Postfix: header_size_limit 102400 per header, excess silently discarded, and capped at 60000 when milters are in use [9] - Dovecot 2.4: 10 MiB per MIME part header block and 50 MiB per message, silently truncated [10] - Cyrus and Haraka: 1000 header lines, the rest skipped without rejecting [11][12] The smallest total, Sendmail's 32 KiB, sits right next to the 32 KB per-field limit at Gmail and Exchange Online. Postfix's cut happens on receipt, before any DKIM2 verifier sees the message. For size, I asked Claude to do an estimation: a DKIM2-Signature with RSA-2048 plus Ed25519 and one rt= recipient is about 620 bytes folded at 78 columns (about 510 with RSA only), and a Message-Instance with a sha256 pair and no recipe is about 125 bytes (about 310 with sha512 too). A 10 hop path that only forwards is 6 to 8 KB. The 31 and 63 hop ceilings floated in the 7.5 thread come to roughly 19 KB and 39 KB of signatures alone, so 63 hops of dual signatures already passes Sendmail's default before any other header is counted. The worst case for recipes is a "d" step that has to carry a removed base64 attachment: after the JSON and base64 layers the header is about 1.85 times the decoded attachment size (1.92 after folding), which puts a single Message-Instance over 32 KiB at about 17 KB of attachment, over 102400 bytes at about 53 KB, over 256 KB at about 136 KB and over 500000 bytes at about 260 KB. These are Claude’s estimations for a literal copy, but I could do some real measurements if needed. Here is the text I'd propose. Rather than adding a section, I'd retitle 7.5 and append to it: 7.5. Discussion re: Maximum Number and Size of Message-Instance and DKIM2-Signature Header Fields [existing text of 7.5 unchanged, then:] Many MTAs, mailbox servers and hosted providers limit the size of the header section of a message, the size of individual header fields, or the number of header lines. Defaults vary widely: total header section limits of 32 KiB (Sendmail), 100 KB (Courier), 256 KB (Exchange) and about 500 KB (Gmail) are all in use, and some implementations limit a single header field to 32 KB (Gmail, Exchange Online) or 100 KiB (Postfix). Some of these limits are enforced by rejecting the message during the SMTP transaction; others close the connection, or truncate or discard the excess without any indication. A Message-Instance or DKIM2-Signature header field that is truncated in transit invalidates every DKIM2-Signature on the message, because each signature covers all of those header fields (Section 9.6 of [DKIM2]), and the failure is likely to be attributed to the wrong party. Before adding its header fields, a Reviser SHOULD check that the Message-Instance header field it adds, measured as transmitted (field name and folding included), does not exceed 30000 octets, and that the header section as a whole, once its Message-Instance and DKIM2-Signature header fields are added, does not exceed 100000 octets. If a content-bearing Body Recipe would break either bound, the Reviser SHOULD use a null Body Recipe (Section 5.2 of [DKIM2]) instead: a null Recipe is a visible, predictable outcome, whereas a truncated one is not. Header Recipes cannot be null (Section 5.1 of [DKIM2]); a Reviser whose header field changes would need a Header Recipe that breaks either bound SHOULD NOT make those changes. Operators who choose a ceiling on the number of Message-Instance and DKIM2-Signature header fields SHOULD take the size of those fields into account: a ceiling of N hops implies roughly N times the size of one DKIM2-Signature header field in the header section. That size is 0.5 to 0.7 KB with two signatures and a single rt= value, and grows with each additional recipient listed in rt=. Operators who enforce header size limits on inbound mail SHOULD reject messages that exceed them during the SMTP transaction (for example with 552 5.3.4) instead of accepting and truncating. A total header section limit below 100000 octets, such as the Sendmail default of 32768, can reject legitimate DKIM2 mail with a long forwarding path even when no Recipes are present, and operators of such systems SHOULD raise it to at least that value. Beyond that, operators SHOULD NOT raise header limits merely to accommodate DKIM2 header fields: unbounded header parsing has been a repeated source of denial of service vulnerabilities in mail software. One sentence at the end of 5.7: The size of a content-bearing Recipe is also a practical concern; see Section 7.5. And one sentence at the end of the "Resource exhaustion via unbounded chains" item in section 8, since the DoS angle is real (Dovecot has shipped several fixes for header floods, for example CVE-2024-23185 for one very large header and CVE-2026-27852 for headers with huge numbers of addresses or parameters [13]): The size of those header fields is a related concern; Section 7.5 recommends bounds on the header fields a Reviser adds and asks receivers to reject oversized header sections rather than truncate them. The two numbers come from different limits. 30000 octets sits under the 32 KB per-field limit at Gmail and Exchange Online with room for folding; a bigger Message-Instance will be rejected by the two largest receivers whatever the BCP says, so there is little point in allowing more. 100000 octets is the smallest total among the common defaults once Sendmail is set aside. Sendmail's 32 KiB is too small for a long DKIM2 chain even without recipes, which is why the text asks those operators to raise it rather than asking Revisers to fit under it. Using the same figure on both sides means a Reviser that follows the text produces messages that a receiver following it will accept. I'm happy to change either number, or to soften the SHOULDs, if people would rather not have figures in the BCP. Best, Mauro [1] https://github.com/freebsd/freebsd-src/blob/d39bd2c1388b520fcba9abed1932acacead60fba/contrib/sendmail/src/conf.h#L117-L118 and https://github.com/freebsd/freebsd-src/blob/d39bd2c1388b520fcba9abed1932acacead60fba/contrib/sendmail/src/collect.c#L686-L702 [2] https://www.courier-mta.org/courier.html and https://github.com/svarshavchik/courier/blob/749aee4a79da5e100843a34968c841bd055141a9/courier/courier/submit.C#L1709-L1710 [3] https://learn.microsoft.com/en-us/exchange/mail-flow/message-size-limits [4] https://learn.microsoft.com/en-us/office365/servicedescriptions/exchange-online-service-description/exchange-online-limits [5] https://knowledge.workspace.google.com/admin/gmail/gmail-message-header-limits [6] https://www.cisco.com/c/en/us/support/docs/security/email-security-appliance/118495-technote-esa-00.html [7] https://www.exim.org/exim-html-current/doc/html/spec_html/ch-main_configuration.html and https://github.com/Exim/exim/blob/exim-4.99.1/src/src/config.h.defaults#L89 [8] https://maddy.email/reference/endpoints/smtp/ and https://github.com/foxcpp/maddy/blob/v0.9.5/internal/endpoint/smtp/session.go#L421-L424 [9] https://www.postfix.org/postconf.5.html#header_size_limit and https://github.com/vdukhovni/postfix/blob/v3.11.0/postfix/src/cleanup/cleanup_message.c#L1183-L1190 [10] https://github.com/dovecot/core/blob/2.4.5/src/lib-mail/message-header-parser.h#L5 and https://github.com/dovecot/core/blob/2.4.5/src/lib-mail/message-parser.h#L22 [11] https://www.cyrusimap.org/imap/reference/manpages/configs/imapd.conf.html [12] https://github.com/haraka/Haraka/blob/39846c5e4dd1f9da0a5f4ad050cfe21b9895ab72/config/connection.ini#L42 [13] https://documentation.open-xchange.com/dovecot/security/advisories/html/2024/oxdc-adv-2024-0003.html and https://documentation.open-xchange.com/dovecot/security/advisories/html/2026/oxdc-adv-2026-0003.html _______________________________________________ Ietf-dkim mailing list -- [email protected] To unsubscribe send an email to [email protected]
