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 e170c392948a28e18e29156fbab51b93555fcba2
Author: Benoit TELLIER <[email protected]>
AuthorDate: Sun Nov 1 19:59:57 2026 +0000

    [FIX] Body canonicalizers: ignore the high-order bits of write(int)
    
    RelaxedBodyCanonicalizer and SimpleBodyCanonicalizer compared the
    whole int with CR, LF, SP and HTAB, whereas OutputStream#write(int)
    says its 24 high-order bits are ignored: writing b | 0x100 through the
    streaming API (newBodyHasher, getOutputStream, verify(BodyHasher))
    passed 0x120 on as data and kept trailing CRLFs, so the body hash
    differed from the one of verify(InputStream).
    
    write(int) now masks its argument with 0xFF first, in both
    canonicalizers and, for consistency, in LimitedOutputStream,
    CompoundOutputStream and DigestOutputStream.
---
 .../org/apache/james/jdkim/canon/CompoundOutputStream.java     |  2 ++
 .../java/org/apache/james/jdkim/canon/DigestOutputStream.java  |  2 ++
 .../java/org/apache/james/jdkim/canon/LimitedOutputStream.java |  2 ++
 .../org/apache/james/jdkim/canon/RelaxedBodyCanonicalizer.java |  2 ++
 .../org/apache/james/jdkim/canon/SimpleBodyCanonicalizer.java  |  2 ++
 .../apache/james/jdkim/canon/RelaxedBodyCanonicalizerTest.java | 10 ++++++++++
 .../apache/james/jdkim/canon/SimpleBodyCanonicalizerTest.java  | 10 ++++++++++
 7 files changed, 30 insertions(+)

diff --git 
a/main/src/main/java/org/apache/james/jdkim/canon/CompoundOutputStream.java 
b/main/src/main/java/org/apache/james/jdkim/canon/CompoundOutputStream.java
index 5c02384..8ae653a 100644
--- a/main/src/main/java/org/apache/james/jdkim/canon/CompoundOutputStream.java
+++ b/main/src/main/java/org/apache/james/jdkim/canon/CompoundOutputStream.java
@@ -48,6 +48,8 @@ public class CompoundOutputStream extends OutputStream {
     }
 
     public void write(int b) throws IOException {
+        // OutputStream#write(int): the 24 high-order bits are ignored
+        b &= 0xFF;
         for (OutputStream outputStream : outputStreams) outputStream.write(b);
     }
 
diff --git 
a/main/src/main/java/org/apache/james/jdkim/canon/DigestOutputStream.java 
b/main/src/main/java/org/apache/james/jdkim/canon/DigestOutputStream.java
index 3aec990..2c783b4 100644
--- a/main/src/main/java/org/apache/james/jdkim/canon/DigestOutputStream.java
+++ b/main/src/main/java/org/apache/james/jdkim/canon/DigestOutputStream.java
@@ -42,6 +42,8 @@ public class DigestOutputStream extends FilterOutputStream {
     }
 
     public void write(int arg0) throws IOException {
+        // OutputStream#write(int): the 24 high-order bits are ignored
+        arg0 &= 0xFF;
         md.update((byte) arg0);
         if (out != null)
             out.write(arg0);
diff --git 
a/main/src/main/java/org/apache/james/jdkim/canon/LimitedOutputStream.java 
b/main/src/main/java/org/apache/james/jdkim/canon/LimitedOutputStream.java
index 9e0a581..d6c8d44 100644
--- a/main/src/main/java/org/apache/james/jdkim/canon/LimitedOutputStream.java
+++ b/main/src/main/java/org/apache/james/jdkim/canon/LimitedOutputStream.java
@@ -55,6 +55,8 @@ public class LimitedOutputStream extends FilterOutputStream {
     }
 
     public void write(int b) throws IOException {
+        // OutputStream#write(int): the 24 high-order bits are ignored
+        b &= 0xFF;
         if (computedBytes < limit) {
             out.write(b);
             computedBytes++;
diff --git 
a/main/src/main/java/org/apache/james/jdkim/canon/RelaxedBodyCanonicalizer.java 
b/main/src/main/java/org/apache/james/jdkim/canon/RelaxedBodyCanonicalizer.java
index 86d8f95..2031d6b 100644
--- 
a/main/src/main/java/org/apache/james/jdkim/canon/RelaxedBodyCanonicalizer.java
+++ 
b/main/src/main/java/org/apache/james/jdkim/canon/RelaxedBodyCanonicalizer.java
@@ -63,6 +63,8 @@ public class RelaxedBodyCanonicalizer extends 
FilterOutputStream {
     }
 
     public void write(int b) throws IOException {
+        // OutputStream#write(int): the 24 high-order bits are ignored
+        b &= 0xFF;
         if (pendingCR) {
             pendingCR = false;
             if (b == '\n') {
diff --git 
a/main/src/main/java/org/apache/james/jdkim/canon/SimpleBodyCanonicalizer.java 
b/main/src/main/java/org/apache/james/jdkim/canon/SimpleBodyCanonicalizer.java
index 6e5f8d6..d2271e8 100644
--- 
a/main/src/main/java/org/apache/james/jdkim/canon/SimpleBodyCanonicalizer.java
+++ 
b/main/src/main/java/org/apache/james/jdkim/canon/SimpleBodyCanonicalizer.java
@@ -76,6 +76,8 @@ public class SimpleBodyCanonicalizer extends 
FilterOutputStream {
     }
 
     public void write(int b) throws IOException {
+        // OutputStream#write(int): the 24 high-order bits are ignored
+        b &= 0xFF;
         if (DEEP_DEBUG)
             System.out.println("B:(" + lastWasCR + "|" + countCRLF + ") [" + 
(char) b + "]");
         if (lastWasCR) {
diff --git 
a/main/src/test/java/org/apache/james/jdkim/canon/RelaxedBodyCanonicalizerTest.java
 
b/main/src/test/java/org/apache/james/jdkim/canon/RelaxedBodyCanonicalizerTest.java
index 4fb7658..41346f1 100644
--- 
a/main/src/test/java/org/apache/james/jdkim/canon/RelaxedBodyCanonicalizerTest.java
+++ 
b/main/src/test/java/org/apache/james/jdkim/canon/RelaxedBodyCanonicalizerTest.java
@@ -91,4 +91,14 @@ public class RelaxedBodyCanonicalizerTest extends 
AbstractOutputStreamTestCase {
         os.close();
         extensiveChunker(body, bytes.toByteArray());
     }
+
+    public void testWriteIntIgnoresHighBits() throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        RelaxedBodyCanonicalizer os = new RelaxedBodyCanonicalizer(bos);
+        for (byte b : "a  b\r\n".getBytes()) {
+            os.write(b | 0x100); // OutputStream#write(int): the 24 high-order 
bits are ignored
+        }
+        os.close();
+        assertArrayEquals("a b\r\n".getBytes(), bos.toByteArray());
+    }
 }
diff --git 
a/main/src/test/java/org/apache/james/jdkim/canon/SimpleBodyCanonicalizerTest.java
 
b/main/src/test/java/org/apache/james/jdkim/canon/SimpleBodyCanonicalizerTest.java
index 23bfed1..48f2ce3 100644
--- 
a/main/src/test/java/org/apache/james/jdkim/canon/SimpleBodyCanonicalizerTest.java
+++ 
b/main/src/test/java/org/apache/james/jdkim/canon/SimpleBodyCanonicalizerTest.java
@@ -155,4 +155,14 @@ public class SimpleBodyCanonicalizerTest extends 
AbstractOutputStreamTestCase {
         extensiveChunker("\r\n\r\r".getBytes(), "\r\n\r\r\r\n".getBytes());
         extensiveChunker("a\r\n\r\nb\r\r\n\r\n".getBytes(), 
"a\r\n\r\nb\r\r\n".getBytes());
     }
+
+    public void testWriteIntIgnoresHighBits() throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        SimpleBodyCanonicalizer os = new SimpleBodyCanonicalizer(bos);
+        for (byte b : "x\r\n\r\n\r\n".getBytes()) {
+            os.write(b | 0x100); // OutputStream#write(int): the 24 high-order 
bits are ignored
+        }
+        os.close();
+        assertArrayEquals("x\r\n".getBytes(), bos.toByteArray());
+    }
 }


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

Reply via email to