From 3805b0c7c30b54109709c2ccddb0ce0042984363 Mon Sep 17 00:00:00 2001 From: Azure Linux Security Servicing Account Date: Fri, 17 Jul 2026 14:34:36 +0000 Subject: [PATCH 1/5] Patch python-pyasn1 for CVE-2026-59886, CVE-2026-59885, CVE-2026-59884 --- SPECS/python-pyasn1/CVE-2026-59884.patch | 245 +++++++++++++++++++++++ SPECS/python-pyasn1/CVE-2026-59885.patch | 133 ++++++++++++ SPECS/python-pyasn1/CVE-2026-59886.patch | 53 +++++ SPECS/python-pyasn1/python-pyasn1.spec | 8 +- 4 files changed, 438 insertions(+), 1 deletion(-) create mode 100644 SPECS/python-pyasn1/CVE-2026-59884.patch create mode 100644 SPECS/python-pyasn1/CVE-2026-59885.patch create mode 100644 SPECS/python-pyasn1/CVE-2026-59886.patch diff --git a/SPECS/python-pyasn1/CVE-2026-59884.patch b/SPECS/python-pyasn1/CVE-2026-59884.patch new file mode 100644 index 00000000000..88af45d1d84 --- /dev/null +++ b/SPECS/python-pyasn1/CVE-2026-59884.patch @@ -0,0 +1,245 @@ +From 09842c66a4333928b6baa30367ea8f491ff9cfe3 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Fri, 17 Jul 2026 14:27:57 +0000 +Subject: [PATCH] Backport long tag bounds and huge tag repr fixes + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/pyasn1/pyasn1/commit/628e36ecbb5277a3f01572ce418ef54271b165a5.patch +--- + pyasn1/codec/ber/decoder.py | 4 ++++ + pyasn1/type/tag.py | 20 ++++++++++++++++---- + tests/codec/ber/test_decoder.py | 26 ++++++++++++++++++++++++++ + tests/codec/cer/test_decoder.py | 16 ++++++++++++++++ + tests/codec/der/test_decoder.py | 16 ++++++++++++++++ + tests/type/test_tag.py | 22 ++++++++++++++++++++++ + 6 files changed, 100 insertions(+), 4 deletions(-) + +diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py +index 1844811..37caf97 100644 +--- a/pyasn1/codec/ber/decoder.py ++++ b/pyasn1/codec/ber/decoder.py +@@ -24,6 +24,10 @@ noValue = base.noValue + + + # Maximum nesting depth to protect against excessively nested ASN.1 structures ++# ++# Maximum number of octets in a long-form tag ID (20 octets = up to ++# 140-bit tag IDs, matching the OID arc limit) ++MAX_TAG_OCTETS = 20 + MAX_NESTING_DEPTH = 100 + + +diff --git a/pyasn1/type/tag.py b/pyasn1/type/tag.py +index b88a734..a9811c4 100644 +--- a/pyasn1/type/tag.py ++++ b/pyasn1/type/tag.py +@@ -34,6 +34,16 @@ tagCategoryExplicit = 0x02 + tagCategoryUntagged = 0x04 + + ++def _tagIdToStr(tagId): ++ # Decimal rendering of a huge tag ID can exceed the interpreter's ++ # integer-to-string conversion limit (sys.get_int_max_str_digits(), ++ # Python 3.11+) and raise ValueError; hexadecimal is not limited ++ try: ++ return str(tagId) ++ except ValueError: ++ return hex(tagId) ++ ++ + class Tag(object): + """Create ASN.1 tag + +@@ -56,7 +66,8 @@ class Tag(object): + """ + def __init__(self, tagClass, tagFormat, tagId): + if tagId < 0: +- raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId) ++ raise error.PyAsn1Error( ++ 'Negative tag ID (%s) not allowed' % _tagIdToStr(tagId)) + self.__tagClass = tagClass + self.__tagFormat = tagFormat + self.__tagId = tagId +@@ -65,7 +76,7 @@ class Tag(object): + + def __repr__(self): + representation = '[%s:%s:%s]' % ( +- self.__tagClass, self.__tagFormat, self.__tagId) ++ self.__tagClass, self.__tagFormat, _tagIdToStr(self.__tagId)) + return '<%s object, tag %s>' % ( + self.__class__.__name__, representation) + +@@ -194,8 +205,9 @@ class TagSet(object): + self.__hash = hash(self.__superTagsClassId) + + def __repr__(self): +- representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId) +- for x in self.__superTags]) ++ representation = '-'.join( ++ ['%s:%s:%s' % (x.tagClass, x.tagFormat, _tagIdToStr(x.tagId)) ++ for x in self.__superTags]) + if representation: + representation = 'tags ' + representation + else: +diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py +index f2a5975..8c11e26 100644 +--- a/tests/codec/ber/test_decoder.py ++++ b/tests/codec/ber/test_decoder.py +@@ -20,6 +20,7 @@ from pyasn1.type import opentype + from pyasn1.type import univ + from pyasn1.type import char + from pyasn1.codec.ber import decoder ++from pyasn1.codec.ber import encoder + from pyasn1.codec.ber import eoo + from pyasn1.compat.octets import ints2octs, str2octs, null + from pyasn1.error import PyAsn1Error +@@ -32,6 +33,31 @@ class LargeTagDecoderTestCase(BaseTestCase): + def testLongTag(self): + assert decoder.decode(ints2octs((0x1f, 2, 1, 0)))[0].tagSet == univ.Integer.tagSet + ++ def testVeryLongTagRoundTrip(self): ++ # (1 << 140) - 1 is the largest tag ID fitting the 20 octet limit ++ for tagId in (1 << 77, (1 << 140) - 1): ++ largeTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, tagId) ++ asn1Spec = univ.Integer().subtype(implicitTag=largeTag) ++ value = univ.Integer(1).subtype(implicitTag=largeTag) ++ ++ decoded, rest = decoder.decode(encoder.encode(value), asn1Spec=asn1Spec) ++ ++ assert rest == b'' ++ assert decoded == 1 ++ ++ def testExcessiveLongTag(self): ++ # 1 << 140 is the smallest tag ID needing 21 octets, one over the limit ++ excessiveTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 140) ++ asn1Spec = univ.Integer().subtype(implicitTag=excessiveTag) ++ substrate = encoder.encode(univ.Integer(1).subtype(implicitTag=excessiveTag)) ++ ++ try: ++ decoder.decode(substrate, asn1Spec=asn1Spec) ++ except PyAsn1Error: ++ pass ++ else: ++ assert 0, 'excessive long tag tolerated' ++ + def testTagsEquivalence(self): + integer = univ.Integer(2).subtype(implicitTag=tag.Tag(tag.tagClassContext, 0, 0)) + assert decoder.decode(ints2octs((0x9f, 0x80, 0x00, 0x02, 0x01, 0x02)), asn1Spec=integer) == decoder.decode( +diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py +index 5064f92..927e1f4 100644 +--- a/tests/codec/cer/test_decoder.py ++++ b/tests/codec/cer/test_decoder.py +@@ -18,6 +18,7 @@ from pyasn1.type import namedtype + from pyasn1.type import opentype + from pyasn1.type import univ + from pyasn1.codec.cer import decoder ++from pyasn1.codec.cer import encoder + from pyasn1.compat.octets import ints2octs, str2octs, null + from pyasn1.error import PyAsn1Error + +@@ -69,6 +70,21 @@ class OctetStringDecoderTestCase(BaseTestCase): + # TODO: test failures on short chunked and long unchunked substrate samples + + ++class LargeTagDecoderTestCase(BaseTestCase): ++ def testExcessiveLongTag(self): ++ # 1 << 140 is the smallest tag ID needing 21 octets, one over the limit ++ excessiveTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 140) ++ asn1Spec = univ.Integer().subtype(implicitTag=excessiveTag) ++ substrate = encoder.encode(univ.Integer(1).subtype(implicitTag=excessiveTag)) ++ ++ try: ++ decoder.decode(substrate, asn1Spec=asn1Spec) ++ except PyAsn1Error: ++ pass ++ else: ++ assert 0, 'excessive long tag tolerated' ++ ++ + class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase): + def setUp(self): + openType = opentype.OpenType( +diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py +index 53ffd9a..c2908c0 100644 +--- a/tests/codec/der/test_decoder.py ++++ b/tests/codec/der/test_decoder.py +@@ -19,6 +19,7 @@ from pyasn1.type import namedtype + from pyasn1.type import opentype + from pyasn1.type import univ + from pyasn1.codec.der import decoder ++from pyasn1.codec.der import encoder + from pyasn1.compat.octets import ints2octs, null + from pyasn1.error import PyAsn1Error + +@@ -77,6 +78,21 @@ class OctetStringDecoderTestCase(BaseTestCase): + assert 0, 'chunked encoding tolerated' + + ++class LargeTagDecoderTestCase(BaseTestCase): ++ def testExcessiveLongTag(self): ++ # 1 << 140 is the smallest tag ID needing 21 octets, one over the limit ++ excessiveTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 140) ++ asn1Spec = univ.Integer().subtype(implicitTag=excessiveTag) ++ substrate = encoder.encode(univ.Integer(1).subtype(implicitTag=excessiveTag)) ++ ++ try: ++ decoder.decode(substrate, asn1Spec=asn1Spec) ++ except PyAsn1Error: ++ pass ++ else: ++ assert 0, 'excessive long tag tolerated' ++ ++ + class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase): + def setUp(self): + openType = opentype.OpenType( +diff --git a/tests/type/test_tag.py b/tests/type/test_tag.py +index e8dd7a3..7814efc 100644 +--- a/tests/type/test_tag.py ++++ b/tests/type/test_tag.py +@@ -14,6 +14,7 @@ except ImportError: + + from tests.base import BaseTestCase + ++from pyasn1 import error + from pyasn1.type import tag + + +@@ -28,6 +29,20 @@ class TagReprTestCase(TagTestCaseBase): + def testRepr(self): + assert 'Tag' in repr(self.t1) + ++ def testReprHugeTagId(self): ++ # must not hit the interpreter's int-to-str conversion limit ++ hugeTag = tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 100000) ++ assert 'Tag' in repr(hugeTag) ++ ++ def testNegativeHugeTagId(self): ++ try: ++ tag.Tag(tag.tagClassContext, tag.tagFormatSimple, -(1 << 100000)) ++ except error.PyAsn1Error: ++ pass ++ else: ++ assert 0, 'negative tag ID tolerated' ++ ++ + + class TagCmpTestCase(TagTestCaseBase): + def testCmp(self): +@@ -59,6 +74,13 @@ class TagSetReprTestCase(TagSetTestCaseBase): + def testRepr(self): + assert 'TagSet' in repr(self.ts1) + ++ def testReprHugeTagId(self): ++ # must not hit the interpreter's int-to-str conversion limit ++ hugeTagSet = self.ts1.tagImplicitly( ++ tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 100000)) ++ assert 'TagSet' in repr(hugeTagSet) ++ ++ + + class TagSetCmpTestCase(TagSetTestCaseBase): + def testCmp(self): +-- +2.45.4 + diff --git a/SPECS/python-pyasn1/CVE-2026-59885.patch b/SPECS/python-pyasn1/CVE-2026-59885.patch new file mode 100644 index 00000000000..85050c36dd4 --- /dev/null +++ b/SPECS/python-pyasn1/CVE-2026-59885.patch @@ -0,0 +1,133 @@ +From b8267e6df8fc3150de2e35912108d4e35be9bf58 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Fri, 17 Jul 2026 14:28:25 +0000 +Subject: [PATCH] Backport BER OID list-based processing and arc stress tests + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/pyasn1/pyasn1/commit/45bdb19eb7df4b3780fe9c912c63e99bffc39dd9.patch +--- + pyasn1/codec/ber/decoder.py | 18 ++++++++++-------- + pyasn1/codec/ber/encoder.py | 12 ++++++------ + tests/codec/ber/test_decoder.py | 8 ++++++++ + 3 files changed, 24 insertions(+), 14 deletions(-) + +diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py +index 37caf97..0d8a719 100644 +--- a/pyasn1/codec/ber/decoder.py ++++ b/pyasn1/codec/ber/decoder.py +@@ -338,14 +338,14 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder): + + head = octs2ints(head) + +- oid = () ++ oid = [] + index = 0 + substrateLen = len(head) + while index < substrateLen: + subId = head[index] + index += 1 + if subId < 128: +- oid += (subId,) ++ oid.append(subId) + elif subId > 128: + # Construct subid from a number of octets + nextSubId = subId +@@ -354,11 +354,11 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder): + subId = (subId << 7) + (nextSubId & 0x7F) + if index >= substrateLen: + raise error.SubstrateUnderrunError( +- 'Short substrate for sub-OID past %s' % (oid,) ++ 'Short substrate for sub-OID past %s' % (tuple(oid),) + ) + nextSubId = head[index] + index += 1 +- oid += ((subId << 7) + nextSubId,) ++ oid.append((subId << 7) + nextSubId) + elif subId == 128: + # ASN.1 spec forbids leading zeros (0x80) in OID + # encoding, tolerating it opens a vulnerability. See +@@ -368,15 +368,17 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder): + + # Decode two leading arcs + if 0 <= oid[0] <= 39: +- oid = (0,) + oid ++ oid.insert(0, 0) + elif 40 <= oid[0] <= 79: +- oid = (1, oid[0] - 40) + oid[1:] ++ oid[0] -= 40 ++ oid.insert(0, 1) + elif oid[0] >= 80: +- oid = (2, oid[0] - 80) + oid[1:] ++ oid[0] -= 80 ++ oid.insert(0, 2) + else: + raise error.PyAsn1Error('Malformed first OID octet: %s' % head[0]) + +- return self._createComponent(asn1Spec, tagSet, oid, **options), tail ++ return self._createComponent(asn1Spec, tagSet, tuple(oid), **options), tail + + + class RealDecoder(AbstractSimpleDecoder): +diff --git a/pyasn1/codec/ber/encoder.py b/pyasn1/codec/ber/encoder.py +index 778aa86..c02b6c0 100644 +--- a/pyasn1/codec/ber/encoder.py ++++ b/pyasn1/codec/ber/encoder.py +@@ -326,30 +326,30 @@ class ObjectIdentifierEncoder(AbstractItemEncoder): + else: + raise error.PyAsn1Error('Impossible first/second arcs at %s' % (value,)) + +- octets = () ++ octets = [] + + # Cycle through subIds + for subOid in oid: + if 0 <= subOid <= 127: + # Optimize for the common case +- octets += (subOid,) ++ octets.append(subOid) + + elif subOid > 127: + # Pack large Sub-Object IDs +- res = (subOid & 0x7f,) ++ res = [subOid & 0x7f] + subOid >>= 7 + + while subOid: +- res = (0x80 | (subOid & 0x7f),) + res ++ res.append(0x80 | (subOid & 0x7f)) + subOid >>= 7 + + # Add packed Sub-Object ID to resulted Object ID +- octets += res ++ octets.extend(reversed(res)) + + else: + raise error.PyAsn1Error('Negative OID arc %s at %s' % (subOid, value)) + +- return octets, False, False ++ return tuple(octets), False, False + + + class RealEncoder(AbstractItemEncoder): +diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py +index 8c11e26..8c6253d 100644 +--- a/tests/codec/ber/test_decoder.py ++++ b/tests/codec/ber/test_decoder.py +@@ -26,6 +26,14 @@ from pyasn1.compat.octets import ints2octs, str2octs, null + from pyasn1.error import PyAsn1Error + + ++def encode_length(length): ++ if length < 128: ++ return bytes([length]) ++ ++ lengthBytes = length.to_bytes((length.bit_length() + 7) // 8, 'big') ++ return bytes([0x80 | len(lengthBytes)]) + lengthBytes ++ ++ + class LargeTagDecoderTestCase(BaseTestCase): + def testLargeTag(self): + assert decoder.decode(ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1))) == (1, null) +-- +2.45.4 + diff --git a/SPECS/python-pyasn1/CVE-2026-59886.patch b/SPECS/python-pyasn1/CVE-2026-59886.patch new file mode 100644 index 00000000000..7a6775191dc --- /dev/null +++ b/SPECS/python-pyasn1/CVE-2026-59886.patch @@ -0,0 +1,53 @@ +From b5ebf86a62552fb37176bb10873ac010d019659b Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Wed, 8 Jul 2026 17:32:09 -0700 +Subject: [PATCH] Merge commit from fork + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://github.com/pyasn1/pyasn1/commit/e60c691cb91addb8fcefa2f537e85ede6fb1e886.patch +--- + pyasn1/type/univ.py | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py +index aa688b2..7a153b6 100644 +--- a/pyasn1/type/univ.py ++++ b/pyasn1/type/univ.py +@@ -1333,7 +1333,7 @@ class Real(base.SimpleAsn1Type): + def __normalizeBase10(value): + m, b, e = value + while m and m % 10 == 0: +- m /= 10 ++ m //= 10 + e += 1 + return m, b, e + +@@ -1472,10 +1472,21 @@ class Real(base.SimpleAsn1Type): + def __float__(self): + if self._value in self._inf: + return self._value +- else: +- return float( +- self._value[0] * pow(self._value[1], self._value[2]) +- ) ++ ++ mantissa, base, exponent = self._value ++ ++ if not mantissa: ++ return 0.0 ++ ++ if base == 2: ++ return math.ldexp(float(mantissa), exponent) ++ ++ # base is 10 (prettyIn() rejects everything else); refuse to ++ # materialize astronomically large integers via pow() ++ if exponent > sys.float_info.max_10_exp: ++ raise OverflowError('Real value too large to convert to float') ++ ++ return float(mantissa * pow(base, exponent)) + + def __abs__(self): + return self.clone(abs(float(self))) +-- +2.45.4 + diff --git a/SPECS/python-pyasn1/python-pyasn1.spec b/SPECS/python-pyasn1/python-pyasn1.spec index 7e72eceaae1..17819d0a061 100644 --- a/SPECS/python-pyasn1/python-pyasn1.spec +++ b/SPECS/python-pyasn1/python-pyasn1.spec @@ -1,7 +1,7 @@ Summary: Implementation of ASN.1 types and codecs in Python programming language Name: python-pyasn1 Version: 0.4.8 -Release: 2%{?dist} +Release: 3%{?dist} License: BSD Vendor: Microsoft Corporation Distribution: Azure Linux @@ -9,6 +9,9 @@ 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 +Patch1: CVE-2026-59884.patch +Patch2: CVE-2026-59885.patch +Patch3: CVE-2026-59886.patch BuildArch: noarch %description @@ -42,6 +45,9 @@ to be suitable for a wide range of protocols based on ASN.1 specification. %{python3_sitelib}/* %changelog +* Fri Jul 17 2026 Azure Linux Security Servicing Account - 0.4.8-3 +- Patch for CVE-2026-59886, CVE-2026-59885, CVE-2026-59884 + * Wed Mar 25 2026 Azure Linux Security Servicing Account - 0.4.8-2 - Patch for CVE-2026-30922 From e383cd9b3053680aabd051448c7a8326a971e86e Mon Sep 17 00:00:00 2001 From: BinduSri-6522866 Date: Sat, 18 Jul 2026 12:22:29 +0000 Subject: [PATCH 2/5] manually backported all three patches --- SPECS/python-pyasn1/CVE-2026-59884.patch | 41 ++--- SPECS/python-pyasn1/CVE-2026-59885.patch | 64 ++++++-- SPECS/python-pyasn1/CVE-2026-59886.patch | 183 ++++++++++++++++++++++- 3 files changed, 254 insertions(+), 34 deletions(-) diff --git a/SPECS/python-pyasn1/CVE-2026-59884.patch b/SPECS/python-pyasn1/CVE-2026-59884.patch index 88af45d1d84..c6b0b2d300e 100644 --- a/SPECS/python-pyasn1/CVE-2026-59884.patch +++ b/SPECS/python-pyasn1/CVE-2026-59884.patch @@ -1,34 +1,43 @@ -From 09842c66a4333928b6baa30367ea8f491ff9cfe3 Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Fri, 17 Jul 2026 14:27:57 +0000 -Subject: [PATCH] Backport long tag bounds and huge tag repr fixes +From 628e36ecbb5277a3f01572ce418ef54271b165a5 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Wed, 8 Jul 2026 17:36:30 -0700 +Subject: [PATCH] Merge commit from fork -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/pyasn1/pyasn1/commit/628e36ecbb5277a3f01572ce418ef54271b165a5.patch +Upstream Patch reference: https://github.com/pyasn1/pyasn1/commit/628e36ecbb5277a3f01572ce418ef54271b165a5.patch --- - pyasn1/codec/ber/decoder.py | 4 ++++ + pyasn1/codec/ber/decoder.py | 7 +++++++ pyasn1/type/tag.py | 20 ++++++++++++++++---- tests/codec/ber/test_decoder.py | 26 ++++++++++++++++++++++++++ tests/codec/cer/test_decoder.py | 16 ++++++++++++++++ tests/codec/der/test_decoder.py | 16 ++++++++++++++++ - tests/type/test_tag.py | 22 ++++++++++++++++++++++ - 6 files changed, 100 insertions(+), 4 deletions(-) + tests/type/test_tag.py | 20 ++++++++++++++++++++ + 6 files changed, 101 insertions(+), 4 deletions(-) diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py -index 1844811..37caf97 100644 +index 1844811..950b6b4 100644 --- a/pyasn1/codec/ber/decoder.py +++ b/pyasn1/codec/ber/decoder.py @@ -24,6 +24,10 @@ noValue = base.noValue # Maximum nesting depth to protect against excessively nested ASN.1 structures -+# ++ +# Maximum number of octets in a long-form tag ID (20 octets = up to +# 140-bit tag IDs, matching the OID arc limit) +MAX_TAG_OCTETS = 20 MAX_NESTING_DEPTH = 100 +@@ -1373,6 +1377,9 @@ class Decoder(object): + while True: + integerTag = oct2int(substrate[lengthOctetIdx]) + lengthOctetIdx += 1 ++ ++ if lengthOctetIdx > MAX_TAG_OCTETS: ++ raise error.PyAsn1Error('Tag ID octet count exceeds limit (%d)' % (MAX_TAG_OCTETS,)) + tagId <<= 7 + tagId |= (integerTag & 0x7F) + if not integerTag & 0x80: diff --git a/pyasn1/type/tag.py b/pyasn1/type/tag.py index b88a734..a9811c4 100644 --- a/pyasn1/type/tag.py @@ -194,7 +203,7 @@ index 53ffd9a..c2908c0 100644 def setUp(self): openType = opentype.OpenType( diff --git a/tests/type/test_tag.py b/tests/type/test_tag.py -index e8dd7a3..7814efc 100644 +index e8dd7a3..d737c94 100644 --- a/tests/type/test_tag.py +++ b/tests/type/test_tag.py @@ -14,6 +14,7 @@ except ImportError: @@ -205,7 +214,7 @@ index e8dd7a3..7814efc 100644 from pyasn1.type import tag -@@ -28,6 +29,20 @@ class TagReprTestCase(TagTestCaseBase): +@@ -28,6 +29,19 @@ class TagReprTestCase(TagTestCaseBase): def testRepr(self): assert 'Tag' in repr(self.t1) @@ -221,12 +230,11 @@ index e8dd7a3..7814efc 100644 + pass + else: + assert 0, 'negative tag ID tolerated' -+ + class TagCmpTestCase(TagTestCaseBase): def testCmp(self): -@@ -59,6 +74,13 @@ class TagSetReprTestCase(TagSetTestCaseBase): +@@ -59,6 +73,12 @@ class TagSetReprTestCase(TagSetTestCaseBase): def testRepr(self): assert 'TagSet' in repr(self.ts1) @@ -235,11 +243,10 @@ index e8dd7a3..7814efc 100644 + hugeTagSet = self.ts1.tagImplicitly( + tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1 << 100000)) + assert 'TagSet' in repr(hugeTagSet) -+ + class TagSetCmpTestCase(TagSetTestCaseBase): def testCmp(self): -- -2.45.4 +2.43.0 diff --git a/SPECS/python-pyasn1/CVE-2026-59885.patch b/SPECS/python-pyasn1/CVE-2026-59885.patch index 85050c36dd4..dfbba62fee7 100644 --- a/SPECS/python-pyasn1/CVE-2026-59885.patch +++ b/SPECS/python-pyasn1/CVE-2026-59885.patch @@ -1,18 +1,18 @@ -From b8267e6df8fc3150de2e35912108d4e35be9bf58 Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Fri, 17 Jul 2026 14:28:25 +0000 -Subject: [PATCH] Backport BER OID list-based processing and arc stress tests +From 45bdb19eb7df4b3780fe9c912c63e99bffc39dd9 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Wed, 8 Jul 2026 17:37:40 -0700 +Subject: [PATCH] Merge commit from fork -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/pyasn1/pyasn1/commit/45bdb19eb7df4b3780fe9c912c63e99bffc39dd9.patch +Upstream Patch reference: https://github.com/pyasn1/pyasn1/commit/45bdb19eb7df4b3780fe9c912c63e99bffc39dd9.patch --- pyasn1/codec/ber/decoder.py | 18 ++++++++++-------- pyasn1/codec/ber/encoder.py | 12 ++++++------ - tests/codec/ber/test_decoder.py | 8 ++++++++ - 3 files changed, 24 insertions(+), 14 deletions(-) + tests/codec/ber/test_decoder.py | 22 ++++++++++++++++++++++ + tests/codec/ber/test_encoder.py | 10 ++++++++++ + 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py -index 37caf97..0d8a719 100644 +index 950b6b4..50c8975 100644 --- a/pyasn1/codec/ber/decoder.py +++ b/pyasn1/codec/ber/decoder.py @@ -338,14 +338,14 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder): @@ -110,7 +110,7 @@ index 778aa86..c02b6c0 100644 class RealEncoder(AbstractItemEncoder): diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py -index 8c11e26..8c6253d 100644 +index 8c11e26..64d0780 100644 --- a/tests/codec/ber/test_decoder.py +++ b/tests/codec/ber/test_decoder.py @@ -26,6 +26,14 @@ from pyasn1.compat.octets import ints2octs, str2octs, null @@ -128,6 +128,48 @@ index 8c11e26..8c6253d 100644 class LargeTagDecoderTestCase(BaseTestCase): def testLargeTag(self): assert decoder.decode(ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1))) == (1, null) +@@ -433,6 +441,20 @@ class ObjectIdentifierDecoderTestCase(BaseTestCase): + ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, 0xE2, 0xB6, 0x47)) + ) == ((2, 999, 18446744073709551535184467440737095), null) + ++ def testManySingleByteArcs(self): ++ encodedArcCount = 4096 ++ substrate = ( ++ bytes([0x06]) + ++ encode_length(encodedArcCount) + ++ bytes([0x01] * encodedArcCount) ++ ) ++ ++ value, rest = decoder.decode(substrate) ++ assert rest == b'' ++ assert len(value) == encodedArcCount + 1 ++ assert tuple(value[:3]) == (0, 1, 1) ++ assert tuple(value[-3:]) == (1, 1, 1) ++ + + class RealDecoderTestCase(BaseTestCase): + def testChar(self): +diff --git a/tests/codec/ber/test_encoder.py b/tests/codec/ber/test_encoder.py +index df82e7b..d60053a 100644 +--- a/tests/codec/ber/test_encoder.py ++++ b/tests/codec/ber/test_encoder.py +@@ -354,6 +354,16 @@ class ObjectIdentifierEncoderTestCase(BaseTestCase): + ) == ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, + 0xB8, 0xCB, 0xE2, 0xB6, 0x47)) + ++def testManySingleByteArcs(self): ++ arcCount = 4096 ++ substrate = encoder.encode( ++ univ.ObjectIdentifier((1, 3) + (1,) * arcCount) ++ ) ++ ++ assert substrate == ( ++ bytes([0x06, 0x82, 0x10, 0x01, 0x2B]) + bytes([0x01] * arcCount) ++ ) ++ + + class ObjectIdentifierWithSchemaEncoderTestCase(BaseTestCase): + def testOne(self): -- -2.45.4 +2.43.0 diff --git a/SPECS/python-pyasn1/CVE-2026-59886.patch b/SPECS/python-pyasn1/CVE-2026-59886.patch index 7a6775191dc..95b46b5ca69 100644 --- a/SPECS/python-pyasn1/CVE-2026-59886.patch +++ b/SPECS/python-pyasn1/CVE-2026-59886.patch @@ -1,13 +1,16 @@ -From b5ebf86a62552fb37176bb10873ac010d019659b Mon Sep 17 00:00:00 2001 +From e60c691cb91addb8fcefa2f537e85ede6fb1e886 Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Wed, 8 Jul 2026 17:32:09 -0700 Subject: [PATCH] Merge commit from fork -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: https://github.com/pyasn1/pyasn1/commit/e60c691cb91addb8fcefa2f537e85ede6fb1e886.patch +Upstream Patch reference: https://github.com/pyasn1/pyasn1/commit/e60c691cb91addb8fcefa2f537e85ede6fb1e886.patch --- - pyasn1/type/univ.py | 21 ++++++++++++++++----- - 1 file changed, 16 insertions(+), 5 deletions(-) + pyasn1/type/univ.py | 21 +++++++++---- + tests/codec/ber/test_decoder.py | 52 +++++++++++++++++++++++++++------ + tests/codec/cer/test_decoder.py | 9 ++++++ + tests/codec/der/test_decoder.py | 18 ++++++++++++ + tests/type/test_univ.py | 40 +++++++++++++++++++++++++ + 5 files changed, 126 insertions(+), 14 deletions(-) diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py index aa688b2..7a153b6 100644 @@ -48,6 +51,174 @@ index aa688b2..7a153b6 100644 def __abs__(self): return self.clone(abs(float(self))) +diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py +index 64d0780..1c0246e 100644 +--- a/tests/codec/ber/test_decoder.py ++++ b/tests/codec/ber/test_decoder.py +@@ -487,17 +487,51 @@ class RealDecoderTestCase(BaseTestCase): + ints2octs((9, 4, 161, 255, 1, 3)) + ) == (univ.Real((3, 2, -1020)), null) + +-# TODO: this requires Real type comparison fix ++ def testBin6(self): # large exponent, base = 16 ++ value, rest = decoder.decode( ++ bytes((9, 5, 162, 0, 255, 255, 1)) ++ ) ++ ++ assert tuple(value) == (1, 2, 262140) ++ assert rest == b'' ++ ++ def testBin7(self): # large exponent in 4-octet form, base = 16 ++ value, rest = decoder.decode( ++ bytes((9, 7, 227, 4, 1, 35, 69, 103, 1)) ++ ) ++ ++ assert tuple(value) == (-1, 2, 76354972) ++ assert rest == b'' ++ ++ def testLargeBinaryRoundTrip(self): ++ substrate = encoder.encode(univ.Real((-1, 2, 76354972))) ++ value, rest = decoder.decode(substrate) ++ ++ assert tuple(value) == (-1, 2, 76354972) ++ assert rest == b'' ++ ++ def testLongFormBinaryRealExponentLength(self): ++ value, rest = decoder.decode( ++ bytes((9, 6, 0x83, 3, 0x0f, 0x42, 0x40, 1)) ++ ) ++ ++ assert tuple(value) == (1, 2, 1000000) ++ assert rest == b'' + +-# def testBin6(self): +-# assert decoder.decode( +-# ints2octs((9, 5, 162, 0, 255, 255, 1)) +-# ) == (univ.Real((1, 2, 262140)), null) ++ def testLargeBinaryPrettyPrintOverflow(self): ++ value, rest = decoder.decode( ++ b'\t\t\xeb\x060662.666\xd0B\x00\x00\x00\x00\x00\x00\x00' ++ ) ++ ++ assert value.prettyPrint() == '' ++ assert rest == b'6\xd0B\x00\x00\x00\x00\x00\x00\x00' + +-# def testBin7(self): +-# assert decoder.decode( +-# ints2octs((9, 7, 227, 4, 1, 35, 69, 103, 1)) +-# ) == (univ.Real((-1, 2, 76354972)), null) ++ try: ++ float(value) ++ except OverflowError: ++ pass ++ else: ++ assert 0, '__float__() tolerated overflow' + + def testPlusInf(self): + assert decoder.decode( +diff --git a/tests/codec/cer/test_decoder.py b/tests/codec/cer/test_decoder.py +index 927e1f4..f910313 100644 +--- a/tests/codec/cer/test_decoder.py ++++ b/tests/codec/cer/test_decoder.py +@@ -56,6 +56,15 @@ class BitStringDecoderTestCase(BaseTestCase): + # TODO: test failures on short chunked and long unchunked substrate samples + + ++class RealDecoderTestCase(BaseTestCase): ++ def testLargeBinaryRoundTrip(self): ++ substrate = encoder.encode(univ.Real((-1, 2, 76354972))) ++ value, rest = decoder.decode(substrate) ++ ++ assert tuple(value) == (-1, 2, 76354972) ++ assert rest == b'' ++ ++ + class OctetStringDecoderTestCase(BaseTestCase): + def testShortMode(self): + assert decoder.decode( +diff --git a/tests/codec/der/test_decoder.py b/tests/codec/der/test_decoder.py +index c2908c0..6809d12 100644 +--- a/tests/codec/der/test_decoder.py ++++ b/tests/codec/der/test_decoder.py +@@ -93,6 +93,24 @@ class LargeTagDecoderTestCase(BaseTestCase): + assert 0, 'excessive long tag tolerated' + + ++class RealDecoderTestCase(BaseTestCase): ++ def testCanonicalLargeBinaryReal(self): ++ substrate = encoder.encode(univ.Real((1, 2, 1000000))) ++ assert substrate == bytes((9, 5, 0x82, 0x0f, 0x42, 0x40, 1)) ++ ++ value, rest = decoder.decode(substrate) ++ ++ assert tuple(value) == (1, 2, 1000000) ++ assert rest == b'' ++ ++ def testLargeBinaryRoundTrip(self): ++ substrate = encoder.encode(univ.Real((-1, 2, 76354972))) ++ value, rest = decoder.decode(substrate) ++ ++ assert tuple(value) == (-1, 2, 76354972) ++ assert rest == b'' ++ ++ + class SequenceDecoderWithUntaggedOpenTypesTestCase(BaseTestCase): + def setUp(self): + openType = opentype.OpenType( +diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py +index 124e5e9..ba65eae 100644 +--- a/tests/type/test_univ.py ++++ b/tests/type/test_univ.py +@@ -803,9 +803,49 @@ class RealTestCase(BaseTestCase): + def testFloat(self): + assert float(univ.Real(4.0)) == 4.0, '__float__() fails' + ++ def testFloatBase10Precision(self): ++ assert float(univ.Real((3, 10, 23))) == 3e23, '__float__() lost base-10 behavior' ++ ++ def testFloatOverflow(self): ++ try: ++ float(univ.Real((1, 2, 1000000))) ++ except OverflowError: ++ pass ++ else: ++ assert 0, '__float__() tolerated overflow' ++ ++ assert univ.Real((1, 2, 1000000)).prettyPrint() == '' ++ ++ def testFloatUnderflow(self): ++ assert float(univ.Real((1, 2, -1000000))) == 0.0, '__float__() failed underflow' ++ ++ def testFloatZeroMantissa(self): ++ assert float(univ.Real((0, 10, 1000000000))) == 0.0, '__float__() failed zero mantissa' ++ assert float(univ.Real((0, 2, 1000000000))) == 0.0, '__float__() failed zero mantissa' ++ ++ def testFloatBase10Overflow(self): ++ try: ++ float(univ.Real((1, 10, sys.float_info.max_10_exp + 1))) ++ except OverflowError: ++ pass ++ else: ++ assert 0, '__float__() tolerated base-10 overflow' ++ ++ def testFloatBase10NormalizedOverflow(self): ++ try: ++ float(univ.Real((10, 10, sys.float_info.max_10_exp))) ++ except OverflowError: ++ pass ++ else: ++ assert 0, '__float__() tolerated normalized base-10 overflow' ++ + def testPrettyIn(self): + assert univ.Real((3, 10, 0)) == 3, 'prettyIn() fails' + ++ def testPrettyInBigBase10Mantissa(self): ++ assert tuple(univ.Real((10 ** 400, 10, 0))) == (1, 10, 400), \ ++ 'prettyIn() big mantissa normalization fails' ++ + # infinite float values + def testStrInf(self): + assert str(univ.Real('inf')) == 'inf', 'str() fails' -- -2.45.4 +2.43.0 From 79f94a1729721dfd2da4739d7d1c65f29560b4c5 Mon Sep 17 00:00:00 2001 From: BinduSri-6522866 Date: Mon, 20 Jul 2026 05:56:06 +0000 Subject: [PATCH 3/5] updated CVE-2026-59885 --- SPECS/python-pyasn1/CVE-2026-59885.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SPECS/python-pyasn1/CVE-2026-59885.patch b/SPECS/python-pyasn1/CVE-2026-59885.patch index dfbba62fee7..0da0a2031f2 100644 --- a/SPECS/python-pyasn1/CVE-2026-59885.patch +++ b/SPECS/python-pyasn1/CVE-2026-59885.patch @@ -150,14 +150,14 @@ index 8c11e26..64d0780 100644 class RealDecoderTestCase(BaseTestCase): def testChar(self): diff --git a/tests/codec/ber/test_encoder.py b/tests/codec/ber/test_encoder.py -index df82e7b..d60053a 100644 +index df82e7b..88b3876 100644 --- a/tests/codec/ber/test_encoder.py +++ b/tests/codec/ber/test_encoder.py @@ -354,6 +354,16 @@ class ObjectIdentifierEncoderTestCase(BaseTestCase): ) == ints2octs((0x06, 0x13, 0x88, 0x37, 0x83, 0xC6, 0xDF, 0xD4, 0xCC, 0xB3, 0xFF, 0xFF, 0xFE, 0xF0, 0xB8, 0xD6, 0xB8, 0xCB, 0xE2, 0xB6, 0x47)) -+def testManySingleByteArcs(self): ++ def testManySingleByteArcs(self): + arcCount = 4096 + substrate = encoder.encode( + univ.ObjectIdentifier((1, 3) + (1,) * arcCount) From abf110ed326a7edce7309c9b70e14918027ab2bb Mon Sep 17 00:00:00 2001 From: akhila-guruju Date: Mon, 20 Jul 2026 16:43:23 +0530 Subject: [PATCH 4/5] modify existing patch to fix ptest --- SPECS/python-pyasn1/CVE-2026-30922.patch | 39 ++++++++++++------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/SPECS/python-pyasn1/CVE-2026-30922.patch b/SPECS/python-pyasn1/CVE-2026-30922.patch index 131460f0f45..9c706385d37 100644 --- a/SPECS/python-pyasn1/CVE-2026-30922.patch +++ b/SPECS/python-pyasn1/CVE-2026-30922.patch @@ -7,15 +7,16 @@ Subject: [PATCH] BER decoder: enforce maximum nesting depth to prevent 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 ++++++++++++++++++++++++++++++++ + pyasn1/codec/ber/decoder.py | 14 ++++ + tests/codec/ber/test_decoder.py | 116 ++++++++++++++++++++++++++++++++ tests/codec/cer/test_decoder.py | 24 +++++++ - tests/codec/der/test_decoder.py | 43 ++++++++++++ + tests/codec/der/test_decoder.py | 42 ++++++++++++ 4 files changed, 196 insertions(+) diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py -index 5ff485f..1844811 100644 +index 5ff485f..49c0ed6 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) @@ -29,31 +30,31 @@ index 5ff485f..1844811 100644 class AbstractDecoder(object): protoComponent = None -@@ -1312,6 +1316,14 @@ class Decoder(object): +@@ -1312,6 +1316,16 @@ 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 +index e3b74df..450e78d 100644 --- a/tests/codec/ber/test_decoder.py +++ b/tests/codec/ber/test_decoder.py -@@ -1614,6 +1614,123 @@ class ErrorOnDecodingTestCase(BaseTestCase): +@@ -1614,6 +1614,122 @@ 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).""" + @@ -168,19 +169,19 @@ index e3b74df..f2a5975 100644 + 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 +index bb5ce93..50facd5 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.""" + @@ -203,19 +204,19 @@ index bb5ce93..5064f92 100644 + 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 +index 51ce296..ae4416d 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 +@@ -367,6 +367,48 @@ class SequenceDecoderWithExplicitlyTaggedSetOfOpenTypesTestCase(BaseTestCase): + assert s[1][0] == univ.OctetString(hexValue='02010C') + -+ +class NestingDepthLimitTestCase(BaseTestCase): + """Test DER decoder protection against deeply nested structures.""" + @@ -258,9 +259,9 @@ index 51ce296..53ffd9a 100644 + assert False, 'Got RecursionError instead of PyAsn1Error' + + - else: - assert False, 'unknown open type tolerated' + suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) + if __name__ == '__main__': -- -2.45.4 +2.34.1 From 49b515bcbb3fbd895e5cf374c9dc19b4892f17db Mon Sep 17 00:00:00 2001 From: BinduSri-6522866 Date: Mon, 20 Jul 2026 11:17:27 +0000 Subject: [PATCH 5/5] Updated CVE-2026-59884 --- SPECS/python-pyasn1/CVE-2026-59884.patch | 37 ++++++++++++++++++------ 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/SPECS/python-pyasn1/CVE-2026-59884.patch b/SPECS/python-pyasn1/CVE-2026-59884.patch index c6b0b2d300e..621d5c777ba 100644 --- a/SPECS/python-pyasn1/CVE-2026-59884.patch +++ b/SPECS/python-pyasn1/CVE-2026-59884.patch @@ -5,16 +5,16 @@ Subject: [PATCH] Merge commit from fork Upstream Patch reference: https://github.com/pyasn1/pyasn1/commit/628e36ecbb5277a3f01572ce418ef54271b165a5.patch --- - pyasn1/codec/ber/decoder.py | 7 +++++++ + pyasn1/codec/ber/decoder.py | 17 +++++++++++++---- pyasn1/type/tag.py | 20 ++++++++++++++++---- tests/codec/ber/test_decoder.py | 26 ++++++++++++++++++++++++++ tests/codec/cer/test_decoder.py | 16 ++++++++++++++++ tests/codec/der/test_decoder.py | 16 ++++++++++++++++ tests/type/test_tag.py | 20 ++++++++++++++++++++ - 6 files changed, 101 insertions(+), 4 deletions(-) + 6 files changed, 107 insertions(+), 8 deletions(-) diff --git a/pyasn1/codec/ber/decoder.py b/pyasn1/codec/ber/decoder.py -index 1844811..950b6b4 100644 +index 1844811..2cd8a82 100644 --- a/pyasn1/codec/ber/decoder.py +++ b/pyasn1/codec/ber/decoder.py @@ -24,6 +24,10 @@ noValue = base.noValue @@ -28,16 +28,35 @@ index 1844811..950b6b4 100644 MAX_NESTING_DEPTH = 100 -@@ -1373,6 +1377,9 @@ class Decoder(object): +@@ -1366,19 +1370,24 @@ class Decoder(object): + + if tagId == 0x1F: + isShortTag = False +- lengthOctetIdx = 0 ++ tagOctetCount = 0 + tagId = 0 + + try: while True: - integerTag = oct2int(substrate[lengthOctetIdx]) - lengthOctetIdx += 1 -+ -+ if lengthOctetIdx > MAX_TAG_OCTETS: -+ raise error.PyAsn1Error('Tag ID octet count exceeds limit (%d)' % (MAX_TAG_OCTETS,)) +- integerTag = oct2int(substrate[lengthOctetIdx]) +- lengthOctetIdx += 1 ++ integerTag = oct2int(substrate[tagOctetCount]) ++ tagOctetCount += 1 ++ if tagOctetCount > MAX_TAG_OCTETS: ++ raise error.PyAsn1Error( ++ 'Tag ID octet count exceeds limit (%d)' % ( ++ MAX_TAG_OCTETS,) ++ ) tagId <<= 7 tagId |= (integerTag & 0x7F) if not integerTag & 0x80: + break + +- substrate = substrate[lengthOctetIdx:] ++ substrate = substrate[tagOctetCount:] + + except IndexError: + raise error.SubstrateUnderrunError( diff --git a/pyasn1/type/tag.py b/pyasn1/type/tag.py index b88a734..a9811c4 100644 --- a/pyasn1/type/tag.py