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

    [FIX] SignatureRecord: reject an x= tag that is not 1*12DIGIT
    
    validate() parsed x= with Long.parseLong, so an empty or non-numeric
    expiration leaked a NumberFormatException out of the constructor
    instead of the IllegalStateException the verifier reports as an invalid
    record. Both record classes now check the RFC 6376 grammar first.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java |  4 ++++
 .../apache/james/jdkim/tagvalue/SignatureRecordTemplate.java |  4 ++++
 .../java/org/apache/james/jdkim/SignatureRecordImplTest.java | 12 ++++++++++++
 .../org/apache/james/jdkim/SignatureRecordTemplateTest.java  |  6 ++++++
 4 files changed, 26 insertions(+)

diff --git 
a/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java 
b/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java
index 2e2a9f1..bd10540 100644
--- 
a/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java
+++ 
b/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java
@@ -33,6 +33,7 @@ public class SignatureRecordImpl extends TagValue implements 
SignatureRecord {
     // TODO ftext is defined as a sequence of at least one in %d33-57 or
     // %d59-126
     private static final Pattern hdrNamePattern = Pattern.compile("^[^: 
\r\n\t]+$");
+    private static final Pattern timestampPattern = 
Pattern.compile("^[0-9]{1,12}$");
 
     public SignatureRecordImpl(String data) {
         super(data);
@@ -83,6 +84,9 @@ public class SignatureRecordImpl extends TagValue implements 
SignatureRecord {
         // when "x=" exists and signature expired then return PERMFAIL
         // (signature expired)
         if (getValue("x") != null) {
+            // RFC 6376 section 3.5: sig-x-tag = %x78 [FWS] "=" [FWS] 1*12DIGIT
+            if (!timestampPattern.matcher(getValue("x")).matches())
+                throw new IllegalStateException("Invalid expiration (x=): " + 
getValue("x"));
             long expiration = Long.parseLong(getValue("x").toString());
             long lifetime = (expiration - System.currentTimeMillis() / 1000);
             if (lifetime < 0) {
diff --git 
a/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordTemplate.java
 
b/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordTemplate.java
index d33bab4..b18fd29 100644
--- 
a/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordTemplate.java
+++ 
b/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordTemplate.java
@@ -35,6 +35,7 @@ public class SignatureRecordTemplate extends TagValue 
implements SignatureRecord
     // TODO ftext is defined as a sequence of at least one in %d33-57 or
     // %d59-126
     private static final Pattern hdrNamePattern = Pattern.compile("^[^: 
\r\n\t]+$");
+    private static final Pattern timestampPattern = 
Pattern.compile("^[0-9]{1,12}$");
 
     public SignatureRecordTemplate(String data) {
         super(data);
@@ -91,6 +92,9 @@ public class SignatureRecordTemplate extends TagValue 
implements SignatureRecord
         // when "x=" exists and signature expired then return PERMFAIL
         // (signature expired)
         if (getValue("x") != null) {
+            // RFC 6376 section 3.5: sig-x-tag = %x78 [FWS] "=" [FWS] 1*12DIGIT
+            if (!timestampPattern.matcher(getValue("x")).matches())
+                throw new IllegalStateException("Invalid expiration (x=): " + 
getValue("x"));
             long expiration = Long.parseLong(getValue("x").toString());
             long lifetime = (expiration - System.currentTimeMillis() / 1000);
             if (lifetime < 0) {
diff --git 
a/main/src/test/java/org/apache/james/jdkim/SignatureRecordImplTest.java 
b/main/src/test/java/org/apache/james/jdkim/SignatureRecordImplTest.java
index 2f44f6e..c6f0e9f 100644
--- a/main/src/test/java/org/apache/james/jdkim/SignatureRecordImplTest.java
+++ b/main/src/test/java/org/apache/james/jdkim/SignatureRecordImplTest.java
@@ -166,4 +166,16 @@ public class SignatureRecordImplTest {
         assertThat(record.getSignature()).isEqualTo(signature);
         assertThat(new 
SignatureRecordImpl(record.toString()).getSignature()).isEqualTo(signature);
     }
+
+    @Test
+    public void nonNumericExpirationShouldBeASyntaxError() {
+        String base = "v=1; a=rsa-sha256; d=example.com; s=s; h=from; bh=AA==; 
b=AA==; ";
+
+        assertThatThrownBy(() -> new SignatureRecordImpl(base + "x="))
+                .isInstanceOf(IllegalStateException.class);
+        assertThatThrownBy(() -> new SignatureRecordImpl(base + "x=abc"))
+                .isInstanceOf(IllegalStateException.class);
+        assertThatThrownBy(() -> new SignatureRecordImpl(base + 
"x=9999999999999"))
+                .isInstanceOf(IllegalStateException.class);
+    }
 }
diff --git 
a/main/src/test/java/org/apache/james/jdkim/SignatureRecordTemplateTest.java 
b/main/src/test/java/org/apache/james/jdkim/SignatureRecordTemplateTest.java
index 18ba729..266154e 100644
--- a/main/src/test/java/org/apache/james/jdkim/SignatureRecordTemplateTest.java
+++ b/main/src/test/java/org/apache/james/jdkim/SignatureRecordTemplateTest.java
@@ -159,4 +159,10 @@ public class SignatureRecordTemplateTest {
         assertThat(signatureRecord.getBodyHash()).isEqualTo(bodyHash);
         assertThat(signatureRecord.getSignature()).isEqualTo(signature);
     }
+
+    @Test
+    public void nonNumericExpirationShouldBeASyntaxError() {
+        assertThatThrownBy(() -> new SignatureRecordTemplate("v=1; 
a=rsa-sha256; d=example.com; s=s; h=from; x=abc"))
+                .isInstanceOf(IllegalStateException.class);
+    }
 }


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

Reply via email to