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]
