Compare commits

...

No commits in common. "c9s" and "c8s-stream-DL1" have entirely different histories.

8 changed files with 29 additions and 345 deletions

16
.gitignore vendored
View File

@ -1,15 +1 @@
/jwcrypto-0.2.0.tar.gz
/jwcrypto-0.2.1.tar.gz
/jwcrypto-0.3.0.tar.gz
/jwcrypto-0.3.1.tar.gz
/jwcrypto-0.3.2.tar.gz
/jwcrypto-0.4.1.tar.gz
/jwcrypto-0.4.2.tar.gz
/jwcrypto-0.5.0.tar.gz
/jwcrypto-0.6.0.tar.gz
/jwcrypto-0.8.tar.gz
/jwcrypto-0.9.1.tar.gz
/jwcrypto-1.4.tar.gz
/jwcrypto-1.4.1.tar.gz
/jwcrypto-1.4.2.tar.gz
/jwcrypto-1.5.6.tar.gz
SOURCES/jwcrypto-0.5.0.tar.gz

View File

@ -0,0 +1 @@
8eccc6fbeeee2fedc602998a7c7a97b8bd550e59 SOURCES/jwcrypto-0.5.0.tar.gz

View File

@ -1,40 +0,0 @@
diff -Naur jwcrypto-1.5.6/jwcrypto/jwk.py jwcrypto-1.5.6-new/jwcrypto/jwk.py
--- jwcrypto-1.5.6/jwcrypto/jwk.py 2024-02-07 13:52:39.000000000 -0300
+++ jwcrypto-1.5.6-new/jwcrypto/jwk.py 2024-06-12 13:06:28.553972422 -0300
@@ -11,7 +11,15 @@
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric import rsa
-from typing_extensions import deprecated
+try:
+ from typing_extensions import deprecated
+except ImportError:
+ def deprecated(_fn, *args):
+ def inner(func):
+ return func
+
+ return inner
+
from jwcrypto.common import JWException
from jwcrypto.common import base64url_decode, base64url_encode
diff -Naur jwcrypto-1.5.6/jwcrypto/jwt.py jwcrypto-1.5.6-new/jwcrypto/jwt.py
--- jwcrypto-1.5.6/jwcrypto/jwt.py 2024-02-07 13:52:39.000000000 -0300
+++ jwcrypto-1.5.6-new/jwcrypto/jwt.py 2024-06-12 13:26:48.534696766 -0300
@@ -4,7 +4,15 @@
import time
import uuid
-from typing_extensions import deprecated
+try:
+ from typing_extensions import deprecated
+except ImportError:
+ def deprecated(*args):
+ def inner(func):
+ return func
+
+ return inner
+
from jwcrypto.common import JWException, JWKeyNotFound
from jwcrypto.common import json_decode, json_encode

View File

@ -1,153 +0,0 @@
From 25db861d8b29434838669a94a843af03d29ea6ed Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Mon, 6 Apr 2026 10:37:20 -0400
Subject: [PATCH] Limit max plaintext size for JWE decompression
This change introduces a maximum plaintext size limit (defaulting to 100MB)
during JWE decryption and updates the decompression logic to enforce it safely
using zlib.decompressobj. The decrypt method now accepts a max_plaintext
parameter to allow overriding the default limit.
This mitigates memory exhaustion and decompression bomb attacks when
processing highly compressed malicious JWE payloads.
Fixes CVE-2026-39373
Signed-off-by: Simo Sorce <simo@redhat.com>
---
jwcrypto/jwe.py | 27 +++++++++++++++++++++------
jwcrypto/tests.py | 34 ++++++++++++++++++++++++++--------
2 files changed, 47 insertions(+), 14 deletions(-)
diff --git a/jwcrypto/jwe.py b/jwcrypto/jwe.py
index e01aa1d..7895928 100644
--- a/jwcrypto/jwe.py
+++ b/jwcrypto/jwe.py
@@ -12,7 +12,8 @@
# Limit the amount of data we are willing to decompress by default.
default_max_compressed_size = 256 * 1024
-
+# Limit the maximum plaintext size to 100MB by default.
+default_max_plaintext_size = 100 * 1024 * 1024
# RFC 7516 - 4.1
# name: (description, supported?)
@@ -376,7 +377,7 @@ def _unwrap_decrypt(self, alg, enc, key, enckey, header,
return data
# FIXME: allow to specify which algorithms to accept as valid
- def _decrypt(self, key, ppe):
+ def _decrypt(self, key, ppe, max_plaintext=default_max_plaintext_size):
jh = self._get_jose_header(ppe.get('header', None))
@@ -434,19 +435,29 @@ def _decrypt(self, key, ppe):
raise InvalidJWEData(
'Compressed data exceeds maximum allowed'
'size' + f' ({default_max_compressed_size})')
- self.plaintext = zlib.decompress(data, -zlib.MAX_WBITS)
+ do = zlib.decompressobj(wbits=-zlib.MAX_WBITS)
+ self.plaintext = do.decompress(data, max_plaintext)
+ if do.unconsumed_tail or not do.eof:
+ self.plaintext = None
+ raise InvalidJWEData(
+ 'Compressed data exceeds maximum allowed'
+ 'output size' + f' ({max_plaintext})')
elif compress is None:
self.plaintext = data
else:
raise ValueError('Unknown compression')
- def decrypt(self, key):
+ def decrypt(self, key, max_plaintext=0):
"""Decrypt a JWE token.
:param key: The (:class:`jwcrypto.jwk.JWK`) decryption key.
:param key: A (:class:`jwcrypto.jwk.JWK`) decryption key,
or a (:class:`jwcrypto.jwk.JWKSet`) that contains a key indexed
by the 'kid' header or (deprecated) a string containing a password.
+ :param max_plaintext: Maximum plaintext size allowed, 0 means
+ the library default applies. Application writers are recommended
+ to set a limit here if they know what is the max plaintext size
+ for their application.
:raises InvalidJWEOperation: if the key is not a JWK object.
:raises InvalidJWEData: if the ciphertext can't be decrypted or
@@ -454,6 +465,10 @@ def decrypt(self, key):
:raises JWKeyNotFound: if key is a JWKSet and the key is not found.
"""
+ self.plaintext = None
+ if max_plaintext == 0:
+ max_plaintext = default_max_plaintext_size
+
if 'ciphertext' not in self.objects:
raise InvalidJWEOperation("No available ciphertext")
self.decryptlog = []
@@ -462,14 +477,14 @@ def decrypt(self, key):
if 'recipients' in self.objects:
for rec in self.objects['recipients']:
try:
- self._decrypt(key, rec)
+ self._decrypt(key, rec, max_plaintext=max_plaintext)
except Exception as e: # pylint: disable=broad-except
if isinstance(e, JWKeyNotFound):
missingkey = True
self.decryptlog.append('Failed: [%s]' % repr(e))
else:
try:
- self._decrypt(key, self.objects)
+ self._decrypt(key, self.objects, max_plaintext=max_plaintext)
except Exception as e: # pylint: disable=broad-except
if isinstance(e, JWKeyNotFound):
missingkey = True
diff --git a/jwcrypto/tests.py b/jwcrypto/tests.py
index cc612eb..3fc4b16 100644
--- a/jwcrypto/tests.py
+++ b/jwcrypto/tests.py
@@ -2124,18 +2124,36 @@ def test_jwe_decompression_max(self):
enc = jwe.JWE(payload.encode('utf-8'),
recipient=key,
protected=protected_header).serialize(compact=True)
+ check = jwe.JWE()
+ check.deserialize(enc)
with self.assertRaises(jwe.InvalidJWEData):
- check = jwe.JWE()
- check.deserialize(enc)
check.decrypt(key)
- defmax = jwe.default_max_compressed_size
- jwe.default_max_compressed_size = 1000000000
- # ensure we can eraise the limit and decrypt
- check = jwe.JWE()
- check.deserialize(enc)
+ # raise the limit on compressed token size so we can decrypt
+ defcmax = jwe.default_max_compressed_size
+ jwe.default_max_compressed_size = 10 * 1024 * 1024
+
+ # this passes if we explicitly allow larger plaintext via API
+ check.decrypt(key, max_plaintext=1000000000)
+
+ # this will still fail because the max plaintext length clamps this
+ with self.assertRaises(jwe.InvalidJWEData):
+ check.decrypt(key)
+
+ # ensure that now this can work with changed defaults
+ defpmax = jwe.default_max_plaintext_size
+ jwe.default_max_plaintext_size = 1000000000
check.decrypt(key)
- jwe.default_max_compressed_size = defmax
+
+ # restore limits
+ jwe.default_max_compressed_size = defcmax
+
+ # check that this fails the max compressed header limits
+ with self.assertRaises(jwe.InvalidJWEData):
+ check.decrypt(key)
+
+ # restore plaintext limits
+ jwe.default_max_plaintext_size = defpmax
class JWATests(unittest.TestCase):

View File

@ -5,51 +5,42 @@
%bcond_with python3
%endif
%if 0%{?fedora} > 31 || 0%{?rhel} > 7
%if 0%{?rhel} > 7
# Disable python2 build by default
%bcond_with python2
%else
%bcond_without python2
%endif
# Disable auto-generation of python dependencies.
%{?python_disable_dependency_generator}
%global srcname jwcrypto
Name: python-%{srcname}
Version: 1.5.6
Release: 3%{?dist}
Version: 0.5.0
Release: 1.1%{?dist}
Summary: Implements JWK, JWS, JWE specifications using python-cryptography
License: LGPLv3+
URL: https://github.com/latchset/%{srcname}
Source0: https://github.com/latchset/%{srcname}/releases/download/v%{version}/%{srcname}-%{version}.tar.gz
Patch1: 0001-ignore-deprecated-annotation.patch
# Security fix for CVE-2026-39373
Patch2: 0002-Limit-max-plaintext-size-for-JWE-decompression.patch
BuildArch: noarch
%if 0%{?with_python2}
%if %{with python2}
BuildRequires: python2-devel
BuildRequires: python2-setuptools
BuildRequires: python2-cryptography >= 1.5
BuildRequires: python2-pytest
%endif
%if 0%{?with_python3}
%if %{with python3}
BuildRequires: python%{python3_pkgversion}-devel
BuildRequires: python%{python3_pkgversion}-setuptools
BuildRequires: python%{python3_pkgversion}-cryptography >= 2.3
BuildRequires: python%{python3_pkgversion}-cryptography >= 1.5
BuildRequires: python%{python3_pkgversion}-pytest
%endif
%description
Implements JWK, JWS, JWE specifications using python-cryptography
%if 0%{?with_python2}
%if %{with python2}
%package -n python2-%{srcname}
Summary: Implements JWK,JWS,JWE specifications using python-cryptography
Requires: python2-cryptography >= 1.5
@ -59,11 +50,10 @@ Requires: python2-cryptography >= 1.5
Implements JWK, JWS, JWE specifications using python-cryptography
%endif
%if 0%{?with_python3}
%if %{with python3}
%package -n python%{python3_pkgversion}-%{srcname}
Summary: Implements JWK, JWS, JWE specifications using python-cryptography
Requires: python%{python3_pkgversion}-cryptography >= 2.3
Requires: python%{python3_pkgversion}-cryptography >= 1.5
%{?python_provide:%python_provide python%{python3_pkgversion}-%{srcname}}
%description -n python%{python3_pkgversion}-%{srcname}
@ -73,47 +63,40 @@ Implements JWK, JWS, JWE specifications using python-cryptography
%prep
%setup -q -n %{srcname}-%{version}
%patch -P 1 -p 1
%patch -P 2 -p 1
%build
%if 0%{?with_python2}
%if %{with python2}
%py2_build
%endif
%if 0%{?with_python3}
%if %{with python3}
%py3_build
%endif
%check
%if 0%{?with_python2}
%if %{with python2}
%{__python2} -bb -m pytest %{srcname}/test*.py
%endif
%if 0%{?with_python3}
%if %{with python3}
%{__python3} -bb -m pytest %{srcname}/test*.py
%endif
%install
%if 0%{?with_python2}
%if %{with python2}
%py2_install
%endif
%if 0%{?with_python3}
%py3_install
%endif
rm -rf %{buildroot}%{_docdir}/%{srcname}
%if 0%{?with_python2}
rm -rf %{buildroot}%{python2_sitelib}/%{srcname}/tests{,-cookbook}.py*
%endif
%if 0%{?with_python3}
%if %{with python3}
%py3_install
rm -rf %{buildroot}%{python3_sitelib}/%{srcname}/tests{,-cookbook}.py*
rm -rf %{buildroot}%{python3_sitelib}/%{srcname}/__pycache__/tests{,-cookbook}.*.py*
%endif
rm -rf %{buildroot}/usr/share/doc/jwcrypto
%if 0%{?with_python2}
%if %{with python2}
%files -n python2-%{srcname}
%doc README.md
%license LICENSE
@ -121,7 +104,7 @@ rm -rf %{buildroot}%{python3_sitelib}/%{srcname}/__pycache__/tests{,-cookbook}.*
%{python2_sitelib}/%{srcname}-%{version}-py%{python2_version}.egg-info
%endif
%if 0%{?with_python3}
%if %{with python3}
%files -n python%{python3_pkgversion}-%{srcname}
%doc README.md
%license LICENSE
@ -131,77 +114,18 @@ rm -rf %{buildroot}%{python3_sitelib}/%{srcname}/__pycache__/tests{,-cookbook}.*
%changelog
* Tue Apr 14 2026 Rafael Jeffman <rjeffman@redhat.com> - 1.5.6-3
- Limit max plaintext size for JWE decompression
Resolves: RHEL-166029
* Fri Jun 17 2022 Christian Heimes <cheimes@redhat.com> - 0.5.0-1.1
- Bump dist to solve version sorting issue, fixes RHBZ#2097800
* Fri Aug 09 2024 Rafael Jeffman <rjeffman@redhat.com> - 1.5.6-2
- Disable auto-generation of dependencies
Related: RHEL-34809
* Tue Jun 18 2024 Rafael Jeffman <rjeffman@redhat.com> - 1.5.6-1
- Rebase to version 1.5.6
Resolve: RHEL-34809
* Thu Apr 04 2024 Rafael Jeffman <rjeffman@redhat.com> - 0.8-5
- Address potential DoS with high compression ratio
Resolves: RHEL-28698
* Tue Aug 10 2021 Mohan Boddu <mboddu@redhat.com> - 0.8-4
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 0.8-3
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 0.8-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Tue Dec 01 2020 Simo Sorce <simo@redhat.com> - 0.8-1
- Sync with upstream release 0.8
* Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.0-9
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Tue May 26 2020 Miro Hrončok <mhroncok@redhat.com> - 0.6.0-8
- Rebuilt for Python 3.9
* Thu Jan 30 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.0-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Thu Oct 03 2019 Miro Hrončok <mhroncok@redhat.com> - 0.6.0-6
- Rebuilt for Python 3.8.0rc1 (#1748018)
* Thu Aug 29 2019 Christian Heimes <cheimes@redhat.com> - 0.6.0-5
- Remove Python 2 subpackages from F32+
- Resolves: RHBZ #1746760
* Mon Aug 19 2019 Miro Hrončok <mhroncok@redhat.com> - 0.6.0-4
- Rebuilt for Python 3.8
* Fri Jul 26 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Sat Feb 02 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Mon Nov 05 2018 Christian Heimes <cheimes@redhat.com> - 0.6.0-1
- New upstream release 0.6.0
* Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.5.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Mon Jul 02 2018 Miro Hrončok <mhroncok@redhat.com> - 0.5.0-2
- Rebuilt for Python 3.7
* Wed Jun 27 2018 Christian Heimes <cheimes@redhat.com> - 0.5.0-1
* Thu Jun 28 2018 Christian Heimes <cheimes@redhat.com> - 0.5.0-1
- New upstream release 0.5.0
- Fixes Coverity scan issue
* Tue Jun 19 2018 Miro Hrončok <mhroncok@redhat.com> - 0.4.2-5
- Rebuilt for Python 3.7
* Mon Apr 16 2018 Christian Heimes <cheimes@redhat.com> - 0.4.2-5
- Drop Python 2 subpackages from RHEL 8, fixes RHBZ#1567152
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.4.2-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Thu Nov 23 2017 Christian Heimes <cheimes@redhat.com> - 0.4.2-4
- Build Python 3 package on RHEL > 7, fixes RHBZ#1516813
* Wed Aug 02 2017 Christian Heimes <cheimes@redhat.com> - 0.4.2-3
- Run tests with bytes warning

View File

@ -1,7 +0,0 @@
# recipients: abokovoy, frenaud, kaleem, ftrivino, cheimes
--- !Policy
product_versions:
- rhel-9
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}

View File

@ -1 +0,0 @@
SHA512 (jwcrypto-1.5.6.tar.gz) = 1db62cf247bc006f1737c4603b80e5ca87e1a3db3b3dc37183a9725a8b3cae4baba706b2ec596119877130ab4d56525a01fb9d7efca07e59811d78021aa7ebf5

View File

@ -1,26 +0,0 @@
---
- hosts: localhost
tags:
- classic
pre_tasks:
- name: Enable CRB for python3-pytest on 1minutetip
ini_file:
path: /etc/yum.repos.d/rhel.repo
section: rhel-CRB
option: enabled
value: "1"
create: no
ignore_errors: yes
roles:
- role: standard-test-source
- role: standard-test-basic
required_packages:
- python3-jwcrypto
- python3-pytest
tests:
- unittests:
dir: "source"
# remove jwcrypto Python files to run tests with packages code
run: >-
rm -rf jwcrypto/j*.py jwcrypto/__init__.py jwcrypto/__pycache__ &&
python3 -m pytest jwcrypto/test*.py