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

coheigea pushed a commit to branch coheigea/jwsinputstream
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 5ea3d70c534916df97ea2bf4b2b57e036346d80d
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Thu Aug 27 10:08:47 2026 +0100

    Fix bug in JwsInputStream and add tests
---
 .../cxf/rs/security/jose/jws/JwsInputStream.java   |  3 +-
 .../rs/security/jose/jws/JwsInputStreamTest.java   | 82 ++++++++++++++++++++++
 2 files changed, 83 insertions(+), 2 deletions(-)

diff --git 
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsInputStream.java
 
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsInputStream.java
index 6225e35c834..53662ebba2b 100644
--- 
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsInputStream.java
+++ 
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jws/JwsInputStream.java
@@ -21,7 +21,6 @@ package org.apache.cxf.rs.security.jose.jws;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.ByteBuffer;
 
 public class JwsInputStream extends FilterInputStream {
     private final JwsVerificationSignature signature;
@@ -42,7 +41,7 @@ public class JwsInputStream extends FilterInputStream {
     public int read() throws IOException {
         int value = super.read();
         if (value != -1) {
-            byte[] bytes = ByteBuffer.allocate(Integer.SIZE / 
8).putInt(value).array();
+            byte[] bytes = new byte[] {(byte)value};
             signature.update(bytes, 0, bytes.length);
         } else {
             verify();
diff --git 
a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsInputStreamTest.java
 
b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsInputStreamTest.java
new file mode 100644
index 00000000000..53581dafdb4
--- /dev/null
+++ 
b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jws/JwsInputStreamTest.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.jose.jws;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
+
+import org.junit.Test;
+
+import static org.junit.Assert.fail;
+
+public class JwsInputStreamTest {
+
+    private static final byte[] KEY = 
"0123456789abcdef0123456789abcdef".getBytes(StandardCharsets.UTF_8);
+    private static final byte[] CONTENT = "signed multipart 
content".getBytes(StandardCharsets.UTF_8);
+
+    @Test
+    public void testSingleByteReadVerifiesValidSignature() throws Exception {
+        byte[] signatureBytes = sign(CONTENT);
+
+        JwsVerificationSignature vSig = createVerificationSignature();
+        try (JwsInputStream jwsStream =
+            new JwsInputStream(new ByteArrayInputStream(CONTENT), vSig, 
signatureBytes, true)) {
+            // Reading one byte at a time must feed the exact content bytes 
into the
+            // signature and thus accept a valid signature at the end of the 
stream
+            while (jwsStream.read() != -1) {
+                // consume
+            }
+        }
+    }
+
+    @Test
+    public void testTamperedContentIsRejected() throws Exception {
+        byte[] signatureBytes = sign(CONTENT);
+
+        byte[] tampered = CONTENT.clone();
+        tampered[0] ^= 0x01;
+        JwsVerificationSignature vSig = createVerificationSignature();
+        try (JwsInputStream jwsStream =
+            new JwsInputStream(new ByteArrayInputStream(tampered), vSig, 
signatureBytes, true)) {
+            byte[] buf = new byte[8];
+            try {
+                while (jwsStream.read(buf, 0, buf.length) != -1) {
+                    // consume
+                }
+                fail("Failure expected on tampered content");
+            } catch (JwsException ex) {
+                // expected
+            }
+        }
+    }
+
+    private byte[] sign(byte[] content) {
+        HmacJwsSignatureProvider provider = new HmacJwsSignatureProvider(KEY, 
SignatureAlgorithm.HS256);
+        JwsSignature sig = provider.createJwsSignature(new 
JwsHeaders(SignatureAlgorithm.HS256));
+        sig.update(content, 0, content.length);
+        return sig.sign();
+    }
+
+    private JwsVerificationSignature createVerificationSignature() {
+        HmacJwsSignatureVerifier verifier = new HmacJwsSignatureVerifier(KEY, 
SignatureAlgorithm.HS256);
+        return verifier.createJwsVerificationSignature(new 
JwsHeaders(SignatureAlgorithm.HS256));
+    }
+}

Reply via email to