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

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

commit ec11c71459ab5649685544c8b1f4c06231b0bc07
Author: Benoit TELLIER <[email protected]>
AuthorDate: Thu Oct 29 12:27:48 2026 +0100

    [FIX] DKIMVerifier: query each distinct q= lookup method once
    
    A DKIM-Signature repeating dns/txt in q= triggered one key lookup per
    entry, so a domain answering SERVFAIL made a single signature issue
    thousands of sequential DNS queries. RFC 6376 section 6.1.2 expects one
    lookup per method: duplicate entries are now ignored.
---
 .../java/org/apache/james/jdkim/DKIMVerifier.java  | 11 +++++++++--
 .../org/apache/james/jdkim/DKIMVerifierTest.java   | 22 ++++++++++++++++++++++
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java 
b/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java
index 07c1ddc..d9c74c5 100644
--- a/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java
+++ b/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java
@@ -53,9 +53,11 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public class DKIMVerifier {
     private final List<Result> result = new ArrayList<>();
@@ -171,9 +173,14 @@ public class DKIMVerifier {
         PublicKeyRecord key = null;
         TempFailException lastTempFailure = null;
         PermFailException lastPermFailure = null;
-        for (Iterator<CharSequence> rlm = 
sign.getRecordLookupMethods().iterator(); key == null
+        // RFC 6376 section 6.1.2: each distinct q= method is queried at most 
once.
+        Set<String> methods = new LinkedHashSet<>();
+        for (CharSequence method : sign.getRecordLookupMethods()) {
+            methods.add(method.toString());
+        }
+        for (Iterator<String> rlm = methods.iterator(); key == null
                 && rlm.hasNext(); ) {
-            CharSequence method = rlm.next();
+            String method = rlm.next();
             try {
                 PublicKeyRecordRetriever pkrr = getPublicKeyRecordRetriever();
                 List<String> records = pkrr.getRecords(method, 
sign.getSelector()
diff --git a/main/src/test/java/org/apache/james/jdkim/DKIMVerifierTest.java 
b/main/src/test/java/org/apache/james/jdkim/DKIMVerifierTest.java
index 68d3de6..f884096 100644
--- a/main/src/test/java/org/apache/james/jdkim/DKIMVerifierTest.java
+++ b/main/src/test/java/org/apache/james/jdkim/DKIMVerifierTest.java
@@ -19,8 +19,16 @@
 
 package org.apache.james.jdkim;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
+
 import org.apache.james.jdkim.api.PublicKeyRecord;
+import org.apache.james.jdkim.api.SignatureRecord;
 import org.apache.james.jdkim.exceptions.PermFailException;
+import org.apache.james.jdkim.exceptions.TempFailException;
 import org.apache.james.jdkim.tagvalue.PublicKeyRecordImpl;
 import org.apache.james.jdkim.tagvalue.SignatureRecordImpl;
 import static org.junit.Assert.fail;
@@ -99,4 +107,18 @@ public class DKIMVerifierTest {
         }
     }
 
+    @Test
+    public void repeatedLookupMethodsShouldBeQueriedOnce() {
+        AtomicInteger calls = new AtomicInteger();
+        DKIMVerifier verifier = new DKIMVerifier((method, selector, token) -> {
+            calls.incrementAndGet();
+            throw new TempFailException("SERVFAIL");
+        });
+        SignatureRecord sign = verifier.newSignatureRecord(
+                "v=1; a=rsa-sha256; d=example.com; s=s0; h=from; bh=AAAA; 
b=AAAA; q=" + String.join(":", Collections.nCopies(100, "dns/txt")));
+
+        assertThatThrownBy(() -> 
verifier.publicRecordLookup(sign)).isInstanceOf(TempFailException.class);
+        assertThat(calls.get()).isEqualTo(1);
+    }
+
 }


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

Reply via email to