File CVE-2024-33664.patch of Package python-python-jose

From ff3357d9f91b93bc957aac9bc5a447c5c0bb74da Mon Sep 17 00:00:00 2001
From: "alistair.watts@groupbc.com" <alistair.watts@groupbc.com>
Date: Tue, 7 May 2024 14:50:53 +0100
Subject: [PATCH] Fix for CVE-2024-33664. JWE limited to 250K

---
 jose/constants.py |  2 ++
 jose/jwe.py       | 24 ++++++++++++++++++------
 tests/test_jwe.py | 34 +++++++++++++++++++++++++++++++++-
 3 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/jose/constants.py b/jose/constants.py
index ab4d74d3..58787d46 100644
--- a/jose/constants.py
+++ b/jose/constants.py
@@ -96,3 +96,5 @@ class Zips:
 
 
 ZIPS = Zips()
+
+JWE_SIZE_LIMIT = 250 * 1024
diff --git a/jose/jwe.py b/jose/jwe.py
index 2c387ff4..04923873 100644
--- a/jose/jwe.py
+++ b/jose/jwe.py
@@ -6,7 +6,7 @@
 
 from . import jwk
 from .backends import get_random_bytes
-from .constants import ALGORITHMS, ZIPS
+from .constants import ALGORITHMS, ZIPS, JWE_SIZE_LIMIT
 from .exceptions import JWEError, JWEParseError
 from .utils import base64url_decode, base64url_encode, ensure_binary
 
@@ -76,6 +76,13 @@ def decrypt(jwe_str, key):
         >>> jwe.decrypt(jwe_string, 'asecret128bitkey')
         'Hello, World!'
     """
+
+    # Limit the token size - if the data is compressed then decompressing the
+    # data could lead to large memory usage. This helps address This addresses
+    # CVE-2024-33664. Also see _decompress()
+    if len(jwe_str) > JWE_SIZE_LIMIT:
+        raise JWEError("JWE string exceeds {JWE_SIZE_LIMIT} bytes")
+
     header, encoded_header, encrypted_key, iv, cipher_text, auth_tag = _jwe_compact_deserialize(jwe_str)
 
     # Verify that the implementation understands and can process all
@@ -424,13 +431,13 @@ def _compress(zip, plaintext):
         (bytes): Compressed plaintext
     """
     if zip not in ZIPS.SUPPORTED:
-        raise NotImplementedError("ZIP {} is not supported!")
+        raise NotImplementedError(f"ZIP {zip} is not supported!")
     if zip is None:
         compressed = plaintext
     elif zip == ZIPS.DEF:
         compressed = zlib.compress(plaintext)
     else:
-        raise NotImplementedError("ZIP {} is not implemented!")
+        raise NotImplementedError(f"ZIP {zip} is not implemented!")
     return compressed
 
 
@@ -446,13 +453,18 @@ def _decompress(zip, compressed):
         (bytes): Compressed plaintext
     """
     if zip not in ZIPS.SUPPORTED:
-        raise NotImplementedError("ZIP {} is not supported!")
+        raise NotImplementedError(f"ZIP {zip} is not supported!")
     if zip is None:
         decompressed = compressed
     elif zip == ZIPS.DEF:
-        decompressed = zlib.decompress(compressed)
+        # If, during decompression, there is more data than expected, the
+        # decompression halts and raise an error. This addresses CVE-2024-33664
+        decompressor = zlib.decompressobj()
+        decompressed = decompressor.decompress(compressed, max_length=JWE_SIZE_LIMIT)
+        if decompressor.unconsumed_tail:
+            raise JWEError(f"Decompressed JWE string exceeds {JWE_SIZE_LIMIT} bytes")
     else:
-        raise NotImplementedError("ZIP {} is not implemented!")
+        raise NotImplementedError(f"ZIP {zip} is not implemented!")
     return decompressed
 
 
diff --git a/tests/test_jwe.py b/tests/test_jwe.py
index f089d565..8c5ff387 100644
--- a/tests/test_jwe.py
+++ b/tests/test_jwe.py
@@ -5,7 +5,7 @@
 import jose.backends
 from jose import jwe
 from jose.constants import ALGORITHMS, ZIPS
-from jose.exceptions import JWEParseError
+from jose.exceptions import JWEParseError, JWEError
 from jose.jwk import AESKey, RSAKey
 from jose.utils import base64url_decode
 
@@ -525,3 +525,35 @@ def test_kid_header_not_present_when_not_provided(self):
         encrypted = jwe.encrypt("Text", PUBLIC_KEY_PEM, enc, alg)
         header = json.loads(base64url_decode(encrypted.split(b".")[0]))
         assert "kid" not in header
+
+    @pytest.mark.skipif(AESKey is None, reason="No AES backend")
+    def test_jwe_with_excessive_data(self):
+        enc = ALGORITHMS.A256CBC_HS512
+        alg = ALGORITHMS.RSA_OAEP_256
+        import jose.constants
+        old_limit = jose.constants.JWE_SIZE_LIMIT
+        try:
+            jose.constants.JWE_SIZE_LIMIT = 1024
+            encrypted = jwe.encrypt(b"Text"*64*1024, PUBLIC_KEY_PEM, enc, alg)
+            header = json.loads(base64url_decode(encrypted.split(b".")[0]))
+            with pytest.raises(JWEError):
+                actual = jwe.decrypt(encrypted, PRIVATE_KEY_PEM)
+        finally:
+            jose.constants.JWE_SIZE_LIMIT = old_limit
+
+    @pytest.mark.skipif(AESKey is None, reason="No AES backend")
+    def test_jwe_zip_with_excessive_data(self):
+        # Test that a fix for CVE-2024-33664 is in place.
+        enc = ALGORITHMS.A256CBC_HS512
+        alg = ALGORITHMS.RSA_OAEP_256
+        import jose.constants
+        old_limit = jose.constants.JWE_SIZE_LIMIT
+        try:
+            jose.constants.JWE_SIZE_LIMIT = 1024
+            encrypted = jwe.encrypt(b"Text"*64*1024, PUBLIC_KEY_PEM, enc, alg, zip=ZIPS.DEF)
+            assert len(encrypted) < jose.constants.JWE_SIZE_LIMIT
+            header = json.loads(base64url_decode(encrypted.split(b".")[0]))
+            with pytest.raises(JWEError):
+                actual = jwe.decrypt(encrypted, PRIVATE_KEY_PEM)
+        finally:
+            jose.constants.JWE_SIZE_LIMIT = old_limit
openSUSE Build Service is sponsored by