This is an automated email from the ASF dual-hosted git repository.

chibenwa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-jdkim.git

commit 913a41941a2f82e0a854361e4950f861432b124a
Author: Benoit TELLIER <[email protected]>
AuthorDate: Wed Nov 4 15:01:27 2026 +0100

    [FIX] Message: drop mime4j's per-field limits
    
    MimeConfig.PERMISSIVE still caps each header field at 64 KB and the
    header at 4096 fields. RFC 5322 sets no limit on a folded field, and a
    To: listing a few thousand recipients is longer than 64 KB: such
    messages could be neither signed nor verified (PermFailException
    "Maximum header length limit (65536) exceeded").
    
    Message now raises these two limits to the profile's limits on the
    whole header (16384 fields, 1 MB), which keep the memory the header
    takes bounded.
---
 docs/modules/ROOT/pages/usage.adoc                 |  9 +++--
 .../java/org/apache/james/jdkim/impl/Message.java  | 12 ++++--
 .../apache/james/jdkim/impl/MessageLimitsTest.java | 47 ++++++++++++++++++++++
 3 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/docs/modules/ROOT/pages/usage.adoc 
b/docs/modules/ROOT/pages/usage.adoc
index 2245155..9938d07 100644
--- a/docs/modules/ROOT/pages/usage.adoc
+++ b/docs/modules/ROOT/pages/usage.adoc
@@ -293,10 +293,11 @@ signature, an unsupported algorithm -- are always applied.
 === Message parsing limits
 
 `sign(InputStream)` and `verify(InputStream)` parse the message with mime4j's
-`MimeConfig.PERMISSIVE` profile, whose limits (4096 header fields, 64 KB per
-header field, no line limit, 100 MB of content) are well above what real mail
-uses. The next mime4j release makes them configurable with the
-`james.mime4j.permissive.*` system properties. A message exceeding them is a 
permanent error
+`MimeConfig.PERMISSIVE` profile, without its per-field limits: RFC 5322 sets no
+limit on the length of a folded field, and a `To:` listing a few thousand
+recipients is longer than 64 KB. What remains (16384 header fields and 1 MB for
+the whole header, no line limit, 100 MB of content) is well above what real
+mail uses. A message exceeding these limits is a permanent error
 (`PermFailException`), not an I/O error.
 
 == Applying several signatures
diff --git a/main/src/main/java/org/apache/james/jdkim/impl/Message.java 
b/main/src/main/java/org/apache/james/jdkim/impl/Message.java
index 3015562..687e669 100644
--- a/main/src/main/java/org/apache/james/jdkim/impl/Message.java
+++ b/main/src/main/java/org/apache/james/jdkim/impl/Message.java
@@ -78,10 +78,14 @@ public class Message implements Headers {
     }
 
     private MessageServiceFactory newMessageBuilder() throws MimeException {
-        // the limits of mime4j's permissive profile (4096 fields, 64 KB per 
field, no line limit) are well
-        // above what real mail uses; the next mime4j release makes them 
configurable with the
-        // james.mime4j.permissive.* system properties
-        MimeConfig mec = MimeConfig.PERMISSIVE;
+        // mime4j's permissive profile, without its per-field limits (4096 
fields, 64 KB per field): RFC 5322
+        // sets none, and a To: listing a few thousand recipients exceeds 64 
KB. The memory the header takes
+        // stays bounded by the limits on the whole header (16384 fields, 1 
MB), which a single field cannot
+        // exceed anyway.
+        MimeConfig mec = MimeConfig.copy(MimeConfig.PERMISSIVE)
+                
.setMaxHeaderCount(MimeConfig.PERMISSIVE.getMaxTotalHeaderCount())
+                .setMaxHeaderLen((int) Math.min(Integer.MAX_VALUE, 
MimeConfig.PERMISSIVE.getMaxTotalHeaderLen()))
+                .build();
 
         MessageServiceFactory mbf = MessageServiceFactory.newInstance();
         mbf.setAttribute("MimeEntityConfig", mec);
diff --git 
a/main/src/test/java/org/apache/james/jdkim/impl/MessageLimitsTest.java 
b/main/src/test/java/org/apache/james/jdkim/impl/MessageLimitsTest.java
index bfc4439..b2945f0 100644
--- a/main/src/test/java/org/apache/james/jdkim/impl/MessageLimitsTest.java
+++ b/main/src/test/java/org/apache/james/jdkim/impl/MessageLimitsTest.java
@@ -20,12 +20,14 @@
 package org.apache.james.jdkim.impl;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
 
 import org.apache.james.jdkim.DKIMSigner;
 import org.apache.james.jdkim.TestKeys;
+import org.apache.james.mime4j.MimeException;
 import org.junit.Test;
 
 public class MessageLimitsTest {
@@ -86,4 +88,49 @@ public class MessageLimitsTest {
 
         assertThat(field).startsWith("DKIM-Signature:");
     }
+
+    private static StringBuilder longTo(int recipients) {
+        StringBuilder sb = new StringBuilder("From: [email protected]\r\nTo: 
[email protected]");
+        for (int i = 1; i < recipients; i++) {
+            sb.append(",\r\n r").append(i).append("@example.com");
+        }
+        return sb.append("\r\n\r\nbody\r\n");
+    }
+
+    @Test
+    public void shouldParseFoldedFieldLongerThan64K() throws Exception {
+        // about 90 KB unfolded
+        Message message = new Message(stream(longTo(5000)));
+
+        assertThat(message.getFields("To")).hasSize(1);
+    }
+
+    @Test
+    public void signerShouldSignMessageWithFoldedFieldLongerThan64K() throws 
Exception {
+        String field = new DKIMSigner("v=1; a=rsa-sha256; c=simple; 
d=messiah.edu; h=from:to; s=selector2;", TestKeys.privateKey)
+                .sign(stream(longTo(5000)));
+
+        assertThat(field).startsWith("DKIM-Signature:");
+    }
+
+    @Test
+    public void shouldParseMoreThan4096HeaderFields() throws Exception {
+        StringBuilder sb = new StringBuilder("From: [email protected]\r\n");
+        for (int i = 0; i < 6000; i++) {
+            sb.append("Received: hop ").append(i).append("\r\n");
+        }
+        sb.append("\r\nbody\r\n");
+
+        Message message = new Message(stream(sb));
+
+        assertThat(message.getFields("Received")).hasSize(6000);
+    }
+
+    @Test
+    public void headerOverOneMegabyteShouldBeRejected() {
+        // about 1.6 MB unfolded
+        assertThatThrownBy(() -> new Message(stream(longTo(100000))))
+                .isInstanceOf(MimeException.class)
+                .hasMessageContaining("limit");
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to