diff --git a/SPECS/python-pyasn1/CVE-2026-30922.patch b/SPECS/python-pyasn1/CVE-2026-30922.patch deleted file mode 100644 index 131460f0f45..00000000000 --- a/SPECS/python-pyasn1/CVE-2026-30922.patch +++ /dev/null @@ -1,266 +0,0 @@ -From 2b4ddcb3b2ff71f687338acd935f6c8dadd4ae94 Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Wed, 25 Mar 2026 09:19:45 +0000 -Subject: [PATCH] BER decoder: enforce maximum nesting depth to prevent - excessively nested ASN.1 structures; add tests for BER/CER/DER decoders - verifying depth limit and error messaging - -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/pyasn1/pyasn1/commit/25ad481c19fdb006e20485ef3fc2e5b3eff30ef0.patch ---- - pyasn1/codec/ber/decoder.py | 12 ++++ - tests/codec/ber/test_decoder.py | 117 ++++++++++++++++++++++++++++++++ - tests/codec/cer/test_decoder.py | 24 +++++++ - tests/codec/der/test_decoder.py | 43 ++++++++++++ - 4 files changed, 196 insertions(+) - -diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py -index 5ff485f..1844811 100644 ---- a/pyasn1/codec/ber/decoder.py -+++ b/pyasn1/codec/ber/decoder.py -@@ -23,6 +23,10 @@ LOG = debug.registerLoggee(__name__, flags=debug.DEBUG_DECODER) - noValue = base.noValue - - -+# Maximum nesting depth to protect against excessively nested ASN.1 structures -+MAX_NESTING_DEPTH = 100 -+ -+ - class AbstractDecoder(object): - protoComponent = None - -@@ -1312,6 +1316,14 @@ class Decoder(object): - if LOG: - LOG('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate))) - -+ -+ _nestingLevel = options.get('_nestingLevel', 0) -+ if _nestingLevel > MAX_NESTING_DEPTH: -+ raise error.PyAsn1Error( -+ 'ASN.1 structure nesting depth exceeds limit (%d)' % MAX_NESTING_DEPTH -+ ) -+ options['_nestingLevel'] = _nestingLevel + 1 -+ - allowEoo = options.pop('allowEoo', False) - - # Look for end-of-octets sentinel -diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py -index e3b74df..f2a5975 100644 ---- a/tests/codec/ber/test_decoder.py -+++ b/tests/codec/ber/test_decoder.py -@@ -1614,6 +1614,123 @@ class ErrorOnDecodingTestCase(BaseTestCase): - 'Unexpected rest of substrate after raw dump %r' % rest) - - -+ -+ -+class NestingDepthLimitTestCase(BaseTestCase): -+ """Test protection against deeply nested ASN.1 structures (CVE prevention).""" -+ -+ def testIndefLenSequenceNesting(self): -+ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error.""" -+ # Each \x30\x80 opens a new indefinite-length SEQUENCE -+ payload = b'\x30\x80' * 200 -+ try: -+ decoder.decode(payload) -+ except PyAsn1Error: -+ pass -+ else: -+ assert False, 'Deeply nested indef-length SEQUENCEs not rejected' -+ -+ def testIndefLenSetNesting(self): -+ """Deeply nested indefinite-length SETs must raise PyAsn1Error.""" -+ # Each \x31\x80 opens a new indefinite-length SET -+ payload = b'\x31\x80' * 200 -+ try: -+ decoder.decode(payload) -+ except PyAsn1Error: -+ pass -+ else: -+ assert False, 'Deeply nested indef-length SETs not rejected' -+ -+ def testDefiniteLenNesting(self): -+ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error.""" -+ inner = b'\x05\x00' # NULL -+ for _ in range(200): -+ length = len(inner) -+ if length < 128: -+ inner = b'\x30' + bytes([length]) + inner -+ else: -+ length_bytes = length.to_bytes( -+ (length.bit_length() + 7) // 8, 'big') -+ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ -+ length_bytes + inner -+ try: -+ decoder.decode(inner) -+ except PyAsn1Error: -+ pass -+ else: -+ assert False, 'Deeply nested definite-length SEQUENCEs not rejected' -+ -+ def testNestingUnderLimitWorks(self): -+ """Nesting within the limit must decode successfully.""" -+ inner = b'\x05\x00' # NULL -+ for _ in range(50): -+ length = len(inner) -+ if length < 128: -+ inner = b'\x30' + bytes([length]) + inner -+ else: -+ length_bytes = length.to_bytes( -+ (length.bit_length() + 7) // 8, 'big') -+ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ -+ length_bytes + inner -+ asn1Object, _ = decoder.decode(inner) -+ assert asn1Object is not None, 'Valid nested structure rejected' -+ -+ def testSiblingsDontIncreaseDepth(self): -+ """Sibling elements at the same level must not inflate depth count.""" -+ # SEQUENCE containing 200 INTEGER siblings - should decode fine -+ components = b'\x02\x01\x01' * 200 # 200 x INTEGER(1) -+ length = len(components) -+ length_bytes = length.to_bytes( -+ (length.bit_length() + 7) // 8, 'big') -+ payload = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ -+ length_bytes + components -+ asn1Object, _ = decoder.decode(payload) -+ assert asn1Object is not None, 'Siblings incorrectly rejected' -+ -+ def testErrorMessageContainsLimit(self): -+ """Error message must indicate the nesting depth limit.""" -+ payload = b'\x30\x80' * 200 -+ try: -+ decoder.decode(payload) -+ except PyAsn1Error as exc: -+ assert 'nesting depth' in str(exc).lower(), \ -+ 'Error message missing depth info: %s' % exc -+ else: -+ assert False, 'Expected PyAsn1Error' -+ -+ def testNoRecursionError(self): -+ """Must raise PyAsn1Error, not RecursionError.""" -+ payload = b'\x30\x80' * 50000 -+ try: -+ decoder.decode(payload) -+ except PyAsn1Error: -+ pass -+ except RecursionError: -+ assert False, 'Got RecursionError instead of PyAsn1Error' -+ -+ def testMixedNesting(self): -+ """Mixed SEQUENCE and SET nesting must be caught.""" -+ # Alternate SEQUENCE (0x30) and SET (0x31) with indef length -+ payload = b'' -+ for i in range(200): -+ payload += b'\x30\x80' if i % 2 == 0 else b'\x31\x80' -+ try: -+ decoder.decode(payload) -+ except PyAsn1Error: -+ pass -+ else: -+ assert False, 'Mixed nesting not rejected' -+ -+ def testWithSchema(self): -+ """Deeply nested structures must be caught even with schema.""" -+ payload = b'\x30\x80' * 200 -+ try: -+ decoder.decode(payload, asn1Spec=univ.Sequence()) -+ except PyAsn1Error: -+ pass -+ else: -+ assert False, 'Deeply nested with schema not rejected' -+ - suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) - - if __name__ == '__main__': -diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py -index bb5ce93..5064f92 100644 ---- a/tests/codec/cer/test_decoder.py -+++ b/tests/codec/cer/test_decoder.py -@@ -367,6 +367,30 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase): - assert s[1][0] == univ.OctetString(hexValue='02010C') - - -+ -+class NestingDepthLimitTestCase(BaseTestCase): -+ """Test CER decoder protection against deeply nested structures.""" -+ -+ def testIndefLenNesting(self): -+ """Deeply nested indefinite-length SEQUENCEs must raise PyAsn1Error.""" -+ payload = b'\x30\x80' * 200 -+ try: -+ decoder.decode(payload) -+ except PyAsn1Error: -+ pass -+ else: -+ assert False, 'Deeply nested indef-length SEQUENCEs not rejected' -+ -+ def testNoRecursionError(self): -+ """Must raise PyAsn1Error, not RecursionError.""" -+ payload = b'\x30\x80' * 50000 -+ try: -+ decoder.decode(payload) -+ except PyAsn1Error: -+ pass -+ except RecursionError: -+ assert False, 'Got RecursionError instead of PyAsn1Error' -+ - suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) - - if __name__ == '__main__': -diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py -index 51ce296..53ffd9a 100644 ---- a/tests/codec/der/test_decoder.py -+++ b/tests/codec/der/test_decoder.py -@@ -119,6 +119,49 @@ class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase): - except PyAsn1Error: - pass - -+ -+class NestingDepthLimitTestCase(BaseTestCase): -+ """Test DER decoder protection against deeply nested structures.""" -+ -+ def testDefiniteLenNesting(self): -+ """Deeply nested definite-length SEQUENCEs must raise PyAsn1Error.""" -+ inner = b'\x05\x00' # NULL -+ for _ in range(200): -+ length = len(inner) -+ if length < 128: -+ inner = b'\x30' + bytes([length]) + inner -+ else: -+ length_bytes = length.to_bytes( -+ (length.bit_length() + 7) // 8, 'big') -+ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ -+ length_bytes + inner -+ try: -+ decoder.decode(inner) -+ except PyAsn1Error: -+ pass -+ else: -+ assert False, 'Deeply nested definite-length SEQUENCEs not rejected' -+ -+ def testNoRecursionError(self): -+ """Must raise PyAsn1Error, not RecursionError.""" -+ inner = b'\x05\x00' -+ for _ in range(200): -+ length = len(inner) -+ if length < 128: -+ inner = b'\x30' + bytes([length]) + inner -+ else: -+ length_bytes = length.to_bytes( -+ (length.bit_length() + 7) // 8, 'big') -+ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \ -+ length_bytes + inner -+ try: -+ decoder.decode(inner) -+ except PyAsn1Error: -+ pass -+ except RecursionError: -+ assert False, 'Got RecursionError instead of PyAsn1Error' -+ -+ - else: - assert False, 'unknown open type tolerated' - --- -2.45.4 - diff --git a/SPECS/python-pyasn1/python-pyasn1.signatures.json b/SPECS/python-pyasn1/python-pyasn1.signatures.json index 3f85b0adc15..971b5096c8b 100644 --- a/SPECS/python-pyasn1/python-pyasn1.signatures.json +++ b/SPECS/python-pyasn1/python-pyasn1.signatures.json @@ -1,5 +1,5 @@ { "Signatures": { - "pyasn1-0.4.8.tar.gz": "aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba" + "pyasn1-0.6.4.tar.gz": "9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81" } -} +} \ No newline at end of file diff --git a/SPECS/python-pyasn1/python-pyasn1.spec b/SPECS/python-pyasn1/python-pyasn1.spec index 7e72eceaae1..019db3c6193 100644 --- a/SPECS/python-pyasn1/python-pyasn1.spec +++ b/SPECS/python-pyasn1/python-pyasn1.spec @@ -1,14 +1,13 @@ Summary: Implementation of ASN.1 types and codecs in Python programming language Name: python-pyasn1 -Version: 0.4.8 -Release: 2%{?dist} +Version: 0.6.4 +Release: 1%{?dist} License: BSD Vendor: Microsoft Corporation Distribution: Azure Linux Group: Development/Languages/Python URL: https://pypi.org/project/pyasn1 Source0: https://files.pythonhosted.org/packages/source/p/pyasn1/pyasn1-%{version}.tar.gz -Patch0: CVE-2026-30922.patch BuildArch: noarch %description @@ -17,6 +16,9 @@ This is an implementation of ASN.1 types and codecs in Python programming langua %package -n python3-pyasn1 Summary: Implementation of ASN.1 types and codecs in Python programming language BuildRequires: python3-devel +BuildRequires: python3-wheel +BuildRequires: python3-pytest +BuildRequires: python3-pip Requires: python3 %description -n python3-pyasn1 @@ -28,13 +30,16 @@ to be suitable for a wide range of protocols based on ASN.1 specification. %autosetup -p1 -n pyasn1-%{version} %build -%py3_build +# pyasn1 0.6.4 no longer supports the legacy setup.py build path used by %%py3_build. +%pyproject_wheel %install -%py3_install +# Install from the wheel using the modern pyproject-based packaging flow. +%pyproject_install %check -%python3 setup.py test +# Upstream tests pass under pytest; setup.py test is no longer available. +%pytest %files -n python3-pyasn1 %defattr(-,root,root,-) @@ -42,6 +47,9 @@ to be suitable for a wide range of protocols based on ASN.1 specification. %{python3_sitelib}/* %changelog +* Fri Jul 17 2026 BinduSri Adabala - 0.6.4-1 +- Upgrade to 0.6.4 - for CVE-2026-59884, CVE-2026-59885, CVE-2026-59886 + * Wed Mar 25 2026 Azure Linux Security Servicing Account - 0.4.8-2 - Patch for CVE-2026-30922 diff --git a/cgmanifest.json b/cgmanifest.json index 6c8c096c540..b804db5f3fb 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -24403,8 +24403,8 @@ "type": "other", "other": { "name": "python-pyasn1", - "version": "0.4.8", - "downloadUrl": "https://files.pythonhosted.org/packages/source/p/pyasn1/pyasn1-0.4.8.tar.gz" + "version": "0.6.4", + "downloadUrl": "https://files.pythonhosted.org/packages/source/p/pyasn1/pyasn1-0.6.4.tar.gz" } } },