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

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

commit 75d3ee09dc7109f463d4e0ee31d29932eabd9d6b
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Fri Apr 5 14:16:09 2024 +0100

    Put a max default configurable limit on the Jose P2C parameter
---
 .../cxf/rs/security/jose/common/JoseConstants.java |  5 ++++
 .../apache/cxf/rs/security/jose/jwe/JweUtils.java  |  5 +++-
 .../jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java | 15 ++++++++++
 .../security/jose/jwe/JwePbeHmacAesWrapTest.java   | 34 ++++++++++++++++++++++
 4 files changed, 58 insertions(+), 1 deletion(-)

diff --git 
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
 
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
index 48d5cbc8b0..092581d3fd 100644
--- 
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
+++ 
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/common/JoseConstants.java
@@ -192,6 +192,11 @@ public final class JoseConstants extends 
RSSecurityConstants {
      */
     public static final String RSSEC_ENCRYPTION_PBES2_COUNT = 
"rs.security.encryption.pbes2.count";
 
+    /**
+     * The max value for the "p2c" (PBES2 count) Header Parameter used for 
decryption. The default is 1_000_000.
+     */
+    public static final String RSSEC_DECRYPTION_MAX_PBES2_COUNT = 
"rs.security.decryption.max.pbes2.count";
+
     //
     // JWT specific configuration
     //
diff --git 
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
 
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
index cefad52f5a..67d6cb6af3 100644
--- 
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
+++ 
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
@@ -568,7 +568,10 @@ public final class JweUtils {
                 if (password == null) {
                     throw new 
JweException(JweException.Error.KEY_DECRYPTION_FAILURE);
                 }
-                keyDecryptionProvider = new 
PbesHmacAesWrapKeyDecryptionAlgorithm(new String(password));
+                int pbes2Count = MessageUtils.getContextualInteger(m, 
+                    JoseConstants.RSSEC_DECRYPTION_MAX_PBES2_COUNT, 1_000_000);
+
+                keyDecryptionProvider = new 
PbesHmacAesWrapKeyDecryptionAlgorithm(new String(password), pbes2Count);
             } else {
                 PrivateKey privateKey = KeyManagementUtils.loadPrivateKey(m, 
props, KeyOperation.DECRYPT);
                 if (keyAlgo == null) {
diff --git 
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java
 
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java
index 505049bba7..fcf00beeb8 100644
--- 
a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java
+++ 
b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/PbesHmacAesWrapKeyDecryptionAlgorithm.java
@@ -26,10 +26,15 @@ import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
 public class PbesHmacAesWrapKeyDecryptionAlgorithm implements 
KeyDecryptionProvider {
     private final byte[] password;
     private final KeyAlgorithm algo;
+    private final int maxPbesCount;
 
     public PbesHmacAesWrapKeyDecryptionAlgorithm(String password) {
         this(password, KeyAlgorithm.PBES2_HS256_A128KW, false);
     }
+    public PbesHmacAesWrapKeyDecryptionAlgorithm(String password, int 
maxPbesCount) {
+        this(PbesHmacAesWrapKeyEncryptionAlgorithm.stringToBytes(password), 
KeyAlgorithm.PBES2_HS256_A128KW, 
+            false, maxPbesCount);
+    }
     public PbesHmacAesWrapKeyDecryptionAlgorithm(String password, KeyAlgorithm 
algo, boolean hashLargePasswords) {
         this(PbesHmacAesWrapKeyEncryptionAlgorithm.stringToBytes(password), 
algo, hashLargePasswords);
     }
@@ -43,15 +48,25 @@ public class PbesHmacAesWrapKeyDecryptionAlgorithm 
implements KeyDecryptionProvi
         this(password, KeyAlgorithm.PBES2_HS256_A128KW, false);
     }
     public PbesHmacAesWrapKeyDecryptionAlgorithm(byte[] password, KeyAlgorithm 
algo, boolean hashLargePasswords) {
+        this(password, algo, hashLargePasswords, 1_000_000);
+    }
+
+    public PbesHmacAesWrapKeyDecryptionAlgorithm(byte[] password, KeyAlgorithm 
algo, boolean hashLargePasswords,
+        int maxPbesCount) {
         this.password =
             PbesHmacAesWrapKeyEncryptionAlgorithm.validatePassword(password, 
algo.getJwaName(), hashLargePasswords);
         this.algo = algo;
+        this.maxPbesCount = maxPbesCount;
     }
+
     @Override
     public byte[] getDecryptedContentEncryptionKey(JweDecryptionInput 
jweDecryptionInput) {
         JweHeaders jweHeaders = jweDecryptionInput.getJweHeaders();
         byte[] saltInput = getDecodedBytes(jweHeaders.getHeader("p2s"));
         int pbesCount = jweHeaders.getIntegerHeader("p2c");
+        if (pbesCount > maxPbesCount) {
+            throw new JoseException("Too many PBES2 iterations");
+        }
         String keyAlgoJwt = 
jweHeaders.getKeyEncryptionAlgorithm().getJwaName();
         int keySize = 
PbesHmacAesWrapKeyEncryptionAlgorithm.getKeySize(keyAlgoJwt);
         byte[] derivedKey = PbesHmacAesWrapKeyEncryptionAlgorithm
diff --git 
a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
 
b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
index 1ad835001e..aa37cce9f6 100644
--- 
a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
+++ 
b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JwePbeHmacAesWrapTest.java
@@ -20,12 +20,14 @@ package org.apache.cxf.rs.security.jose.jwe;
 
 import java.nio.charset.StandardCharsets;
 
+import org.apache.cxf.rs.security.jose.common.JoseException;
 import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
 import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
 
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 public class JwePbeHmacAesWrapTest {
     
@@ -64,4 +66,36 @@ public class JwePbeHmacAesWrapTest {
         assertEquals(specPlainText, decryptedText);
 
     }
+
+    @Test
+    public void testDecryptWithInvalidLargeP2CValue() throws Exception {
+        final String specPlainText = "Live long and prosper.";
+        JweHeaders headers = new JweHeaders();
+        headers.setKeyEncryptionAlgorithm(KeyAlgorithm.PBES2_HS256_A128KW);
+        headers.setContentEncryptionAlgorithm(ContentAlgorithm.A128GCM);
+        final String password = "Thus from my lips, by yours, my sin is 
purged.";
+        KeyEncryptionProvider keyEncryption =
+            new PbesHmacAesWrapKeyEncryptionAlgorithm(password, 1_500_000, 
KeyAlgorithm.PBES2_HS256_A128KW, false);
+        JweEncryptionProvider encryption = new JweEncryption(keyEncryption,
+            new AesGcmContentEncryptionAlgorithm(ContentAlgorithm.A128GCM));
+        String jweContent = 
encryption.encrypt(specPlainText.getBytes(StandardCharsets.UTF_8), null);
+
+        // 1. It should fail by default
+        PbesHmacAesWrapKeyDecryptionAlgorithm keyDecryption = new 
PbesHmacAesWrapKeyDecryptionAlgorithm(password);
+        JweDecryptionProvider decryption = new JweDecryption(keyDecryption,
+                                               new 
AesGcmContentDecryptionAlgorithm(ContentAlgorithm.A128GCM));
+        try {
+            decryption.decrypt(jweContent).getContentText();
+            fail("Failure expected on a too large p2c value");
+        } catch (JoseException ex) {
+            // expected
+        }
+
+        // 2. Now we allow 1.5M iterations and it passes
+        keyDecryption = new PbesHmacAesWrapKeyDecryptionAlgorithm(password, 
1_500_000);
+        decryption = new JweDecryption(keyDecryption,
+                                               new 
AesGcmContentDecryptionAlgorithm(ContentAlgorithm.A128GCM));
+        String decryptedText = decryption.decrypt(jweContent).getContentText();
+        assertEquals(specPlainText, decryptedText);
+    }
 }

Reply via email to