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 b2ac4bdba5e0873b19aba94c5b1a8103eeca17f7
Author: Benoit TELLIER <[email protected]>
AuthorDate: Fri Oct 30 08:36:15 2026 +0100

    [FIX] PublicKeyRecordImpl: report an undecodable p= as IllegalStateException
    
    getPublicKey() let the IllegalArgumentException of the base64 decoder
    escape: the verifier then reported a misleading "Invalid signature
    record", and direct callers got an undeclared exception. A key folded
    inside its padding ("= =") was rejected as well.
    
    p= is now decoded with FWS removed and decoding errors are rethrown as
    IllegalStateException, like the other key errors.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java |  7 ++++---
 .../java/org/apache/james/jdkim/tagvalue/TagValue.java   | 11 +++++++++++
 .../java/org/apache/james/jdkim/PublicKeyRecordTest.java | 16 ++++++++++++++++
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git 
a/main/src/main/java/org/apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java 
b/main/src/main/java/org/apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java
index d482eab..8366fbc 100644
--- 
a/main/src/main/java/org/apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java
+++ 
b/main/src/main/java/org/apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java
@@ -28,7 +28,6 @@ import java.security.interfaces.RSAPublicKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
-import java.util.Base64;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -177,8 +176,7 @@ public class PublicKeyRecordImpl extends TagValue 
implements PublicKeyRecord {
      */
     public PublicKey getPublicKey() {
         try {
-            String p = getValue("p").toString();
-            byte[] key = Base64.getMimeDecoder().decode(p.getBytes());
+            byte[] key = decodeBase64(getValue("p"));
             KeyFactory keyFactory;
             keyFactory = KeyFactory.getInstance(getValue("k").toString());
             X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(key);
@@ -191,6 +189,9 @@ public class PublicKeyRecordImpl extends TagValue 
implements PublicKeyRecord {
         } catch (InvalidKeySpecException e) {
             throw new IllegalStateException("Invalid key spec: "
                     + e.getMessage());
+        } catch (IllegalArgumentException e) {
+            throw new IllegalStateException("Invalid key encoding: "
+                    + e.getMessage());
         }
     }
 
diff --git a/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java 
b/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java
index 68562a5..400a06b 100644
--- a/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java
+++ b/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java
@@ -46,6 +46,7 @@ public class TagValue {
     private static final Pattern valuePattern = Pattern.compile("^(?:" + tval
             + "(?:(?:(?:\r\n)?[\t ])++" + tval + ")*+)?$");
     private static final Pattern b64PadFixPattern = 
Pattern.compile("=(\r?\n\\s*)=$");
+    private static final Pattern fwsPattern = Pattern.compile("[ \t\r\n]");
 
     // we may use a TreeMap because we may need to know original order.
     private final Map<String, CharSequence> tagValues;
@@ -230,6 +231,16 @@ public class TagValue {
         );
     }
 
+    /**
+     * Decodes a base64string (RFC 6376 section 2.8): FWS may appear anywhere,
+     * every other character must belong to the base64 alphabet.
+     *
+     * @throws IllegalArgumentException if the value is not valid base64
+     */
+    protected static byte[] decodeBase64(CharSequence value) {
+        return 
Base64.getDecoder().decode(fwsPattern.matcher(value).replaceAll(""));
+    }
+
     protected void setValue(String tag, String value) {
         stringRepresentation = null;
         tagValues.put(tag, value);
diff --git a/main/src/test/java/org/apache/james/jdkim/PublicKeyRecordTest.java 
b/main/src/test/java/org/apache/james/jdkim/PublicKeyRecordTest.java
index 2059d4f..2ce3666 100644
--- a/main/src/test/java/org/apache/james/jdkim/PublicKeyRecordTest.java
+++ b/main/src/test/java/org/apache/james/jdkim/PublicKeyRecordTest.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.jdkim;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import java.util.Base64;
 import org.apache.james.jdkim.api.PublicKeyRecord;
 import org.apache.james.jdkim.tagvalue.PublicKeyRecordImpl;
 import org.junit.Assert;
@@ -260,4 +262,18 @@ public class PublicKeyRecordTest {
         assertFalse(pkr.isDenySubdomains());
     }
 
+    @Test
+    public void malformedKeyShouldThrowIllegalStateException() {
+        PublicKeyRecordImpl record = new PublicKeyRecordImpl("v=DKIM1; k=rsa; 
p=AAAAA");
+
+        
assertThatThrownBy(record::getPublicKey).isInstanceOf(IllegalStateException.class);
+    }
+
+    @Test
+    public void foldedKeyShouldDecode() throws Exception {
+        String key = 
Base64.getEncoder().encodeToString(TestKeys.publicKey.getEncoded());
+        String folded = key.substring(0, 10) + "\r\n " + key.substring(10, 
key.length() - 1) + " " + key.substring(key.length() - 1);
+
+        assertEquals(TestKeys.publicKey, new PublicKeyRecordImpl("v=DKIM1; 
k=rsa; p=" + folded).getPublicKey());
+    }
 }


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

Reply via email to