File CVE-2026-30922.patch of Package python-pyasn1.43235
Index: pyasn1-0.1.9/pyasn1/codec/ber/decoder.py
===================================================================
--- pyasn1-0.1.9.orig/pyasn1/codec/ber/decoder.py
+++ pyasn1-0.1.9/pyasn1/codec/ber/decoder.py
@@ -7,15 +7,17 @@ from pyasn1 import debug, error
# Maximum number of continuation octets (high-bit set) allowed per OID arc.
# 20 octets allows up to 140-bit integers, supporting UUID-based OIDs
MAX_OID_ARC_CONTINUATION_OCTETS = 20
+MAX_NESTING_DEPTH = 100
class AbstractDecoder:
protoComponent = None
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
raise error.PyAsn1Error('Decoder not implemented for %s' % (tagSet,))
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun,
+ **options):
raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,))
class AbstractSimpleDecoder(AbstractDecoder):
@@ -44,25 +46,28 @@ class ExplicitTagDecoder(AbstractSimpleD
protoComponent = univ.Any('')
tagFormats = (tag.tagFormatConstructed,)
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
if substrateFun:
return substrateFun(
self._createComponent(asn1Spec, tagSet, ''),
substrate, length
)
head, tail = substrate[:length], substrate[length:]
- value, _ = decodeFun(head, asn1Spec, tagSet, length)
+ value, _ = decodeFun(head, asn1Spec, tagSet, length, **options)
return value, tail
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun,
+ **options):
if substrateFun:
return substrateFun(
self._createComponent(asn1Spec, tagSet, ''),
substrate, length
)
- value, substrate = decodeFun(substrate, asn1Spec, tagSet, length)
- terminator, substrate = decodeFun(substrate, allowEoo=True)
+ value, substrate = decodeFun(substrate, asn1Spec, tagSet,
+ length, **options)
+ terminator, substrate = decodeFun(substrate, allowEoo=True,
+ **options)
if eoo.endOfOctets.isSameTypeWith(terminator) and \
terminator == eoo.endOfOctets:
return value, substrate
@@ -92,7 +97,7 @@ class IntegerDecoder(AbstractSimpleDecod
}
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
- state, decodeFun, substrateFun):
+ state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
if not head:
return self._createComponent(asn1Spec, tagSet, 0), tail
@@ -117,7 +122,7 @@ class BitStringDecoder(AbstractSimpleDec
protoComponent = univ.BitString(())
tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed)
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
- state, decodeFun, substrateFun):
+ state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check?
if not head:
@@ -143,18 +148,20 @@ class BitStringDecoder(AbstractSimpleDec
if substrateFun:
return substrateFun(r, substrate, length)
while head:
- component, head = decodeFun(head, self.protoComponent)
+ component, head = decodeFun(head, self.protoComponent,
+ **options)
r = r + component
return r, tail
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun,
+ **options):
r = self._createComponent(asn1Spec, tagSet, '')
if substrateFun:
return substrateFun(r, substrate, length)
while substrate:
component, substrate = decodeFun(substrate, self.protoComponent,
- allowEoo=True)
+ allowEoo=True, **options)
if eoo.endOfOctets.isSameTypeWith(component) and \
component == eoo.endOfOctets:
break
@@ -169,7 +176,7 @@ class OctetStringDecoder(AbstractSimpleD
protoComponent = univ.OctetString('')
tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed)
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
- state, decodeFun, substrateFun):
+ state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
if tagSet[0][1] == tag.tagFormatSimple: # XXX what tag to check?
return self._createComponent(asn1Spec, tagSet, head), tail
@@ -177,18 +184,20 @@ class OctetStringDecoder(AbstractSimpleD
if substrateFun:
return substrateFun(r, substrate, length)
while head:
- component, head = decodeFun(head, self.protoComponent)
+ component, head = decodeFun(head, self.protoComponent,
+ **options)
r = r + component
return r, tail
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun,
+ **options):
r = self._createComponent(asn1Spec, tagSet, '')
if substrateFun:
return substrateFun(r, substrate, length)
while substrate:
component, substrate = decodeFun(substrate, self.protoComponent,
- allowEoo=True)
+ allowEoo=True, **options)
if eoo.endOfOctets.isSameTypeWith(component) and \
component == eoo.endOfOctets:
break
@@ -202,7 +211,7 @@ class OctetStringDecoder(AbstractSimpleD
class NullDecoder(AbstractSimpleDecoder):
protoComponent = univ.Null('')
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
r = self._createComponent(asn1Spec, tagSet)
if head:
@@ -212,7 +221,7 @@ class NullDecoder(AbstractSimpleDecoder)
class ObjectIdentifierDecoder(AbstractSimpleDecoder):
protoComponent = univ.ObjectIdentifier(())
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
- state, decodeFun, substrateFun):
+ state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
if not head:
raise error.PyAsn1Error('Empty substrate')
@@ -267,7 +276,7 @@ class ObjectIdentifierDecoder(AbstractSi
class RealDecoder(AbstractSimpleDecoder):
protoComponent = univ.Real()
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
if not head:
return self._createComponent(asn1Spec, tagSet, 0.0), tail
@@ -342,7 +351,7 @@ class SequenceDecoder(AbstractConstructe
return r.getComponentPositionNearType(t, idx)
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
r = self._createComponent(asn1Spec, tagSet)
idx = 0
@@ -350,7 +359,7 @@ class SequenceDecoder(AbstractConstructe
return substrateFun(r, substrate, length)
while head:
asn1Spec = self._getComponentTagMap(r, idx)
- component, head = decodeFun(head, asn1Spec)
+ component, head = decodeFun(head, asn1Spec, **options)
idx = self._getComponentPositionByType(
r, component.getEffectiveTagSet(), idx
)
@@ -361,14 +370,16 @@ class SequenceDecoder(AbstractConstructe
return r, tail
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun,
+ **options):
r = self._createComponent(asn1Spec, tagSet)
if substrateFun:
return substrateFun(r, substrate, length)
idx = 0
while substrate:
asn1Spec = self._getComponentTagMap(r, idx)
- component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True)
+ component, substrate = decodeFun(substrate, asn1Spec,
+ allowEoo=True, **options)
if eoo.endOfOctets.isSameTypeWith(component) and \
component == eoo.endOfOctets:
break
@@ -388,7 +399,7 @@ class SequenceDecoder(AbstractConstructe
class SequenceOfDecoder(AbstractConstructedDecoder):
protoComponent = univ.SequenceOf()
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
r = self._createComponent(asn1Spec, tagSet)
if substrateFun:
@@ -396,21 +407,23 @@ class SequenceOfDecoder(AbstractConstruc
asn1Spec = r.getComponentType()
idx = 0
while head:
- component, head = decodeFun(head, asn1Spec)
+ component, head = decodeFun(head, asn1Spec, **options)
r.setComponentByPosition(idx, component, asn1Spec is None)
idx = idx + 1
r.verifySizeSpec()
return r, tail
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun,
+ **options):
r = self._createComponent(asn1Spec, tagSet)
if substrateFun:
return substrateFun(r, substrate, length)
asn1Spec = r.getComponentType()
idx = 0
while substrate:
- component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True)
+ component, substrate = decodeFun(substrate, asn1Spec,
+ allowEoo=True, **options)
if eoo.endOfOctets.isSameTypeWith(component) and \
component == eoo.endOfOctets:
break
@@ -442,18 +455,19 @@ class ChoiceDecoder(AbstractConstructedD
protoComponent = univ.Choice()
tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed)
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
r = self._createComponent(asn1Spec, tagSet)
if substrateFun:
return substrateFun(r, substrate, length)
if r.getTagSet() == tagSet: # explicitly tagged Choice
component, head = decodeFun(
- head, r.getComponentTagMap()
+ head, r.getComponentTagMap(), **options
)
else:
component, head = decodeFun(
- head, r.getComponentTagMap(), tagSet, length, state
+ head, r.getComponentTagMap(), tagSet, length, state,
+ **options
)
if isinstance(component, univ.Choice):
effectiveTagSet = component.getEffectiveTagSet()
@@ -463,20 +477,24 @@ class ChoiceDecoder(AbstractConstructedD
return r, tail
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
r = self._createComponent(asn1Spec, tagSet)
if substrateFun:
return substrateFun(r, substrate, length)
if r.getTagSet() == tagSet: # explicitly tagged Choice
- component, substrate = decodeFun(substrate, r.getComponentTagMap())
+ component, substrate = decodeFun(substrate,
+ r.getComponentTagMap(),
+ **options)
# eat up EOO marker
- eooMarker, substrate = decodeFun(substrate, allowEoo=True)
+ eooMarker, substrate = decodeFun(substrate, allowEoo=True,
+ **options)
if not eoo.endOfOctets.isSameTypeWith(eooMarker) or \
eooMarker != eoo.endOfOctets:
raise error.PyAsn1Error('No EOO seen before substrate ends')
else:
component, substrate= decodeFun(
- substrate, r.getComponentTagMap(), tagSet, length, state
+ substrate, r.getComponentTagMap(), tagSet, length,
+ state, **options
)
if isinstance(component, univ.Choice):
effectiveTagSet = component.getEffectiveTagSet()
@@ -489,7 +507,7 @@ class AnyDecoder(AbstractSimpleDecoder):
protoComponent = univ.Any()
tagFormats = (tag.tagFormatSimple, tag.tagFormatConstructed)
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun, **options):
if asn1Spec is None or \
asn1Spec is not None and tagSet != asn1Spec.getTagSet():
# untagged Any container, recover inner header substrate
@@ -502,7 +520,8 @@ class AnyDecoder(AbstractSimpleDecoder):
return self._createComponent(asn1Spec, tagSet, value=head), tail
def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
- length, state, decodeFun, substrateFun):
+ length, state, decodeFun, substrateFun,
+ **options):
if asn1Spec is not None and tagSet == asn1Spec.getTagSet():
# tagged Any type -- consume header substrate
header = ''
@@ -518,7 +537,8 @@ class AnyDecoder(AbstractSimpleDecoder):
if substrateFun:
return substrateFun(r, substrate, length)
while substrate:
- component, substrate = decodeFun(substrate, asn1Spec, allowEoo=True)
+ component, substrate = decodeFun(substrate, asn1Spec,
+ allowEoo=True, **options)
if eoo.endOfOctets.isSameTypeWith(component) and \
component == eoo.endOfOctets:
break
@@ -619,7 +639,16 @@ class Decoder:
def __call__(self, substrate, asn1Spec=None, tagSet=None,
length=None, state=stDecodeTag, recursiveFlag=1,
- substrateFun=None, allowEoo=False):
+ substrateFun=None, allowEoo=False, **options):
+ _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
+
if debug.logger & debug.flagDecoder:
debug.logger('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)))
fullSubstrate = substrate
@@ -828,12 +857,12 @@ class Decoder:
if length == -1: # indef length
value, substrate = concreteDecoder.indefLenValueDecoder(
fullSubstrate, substrate, asn1Spec, tagSet, length,
- stGetValueDecoder, self, substrateFun
+ stGetValueDecoder, self, substrateFun, **options
)
else:
value, substrate = concreteDecoder.valueDecoder(
fullSubstrate, substrate, asn1Spec, tagSet, length,
- stGetValueDecoder, self, substrateFun
+ stGetValueDecoder, self, substrateFun, **options
)
state = stStop
debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '<none>'))
Index: pyasn1-0.1.9/test/codec/ber/test_decoder.py
===================================================================
--- pyasn1-0.1.9.orig/test/codec/ber/test_decoder.py
+++ pyasn1-0.1.9/test/codec/ber/test_decoder.py
@@ -13,6 +13,23 @@ if version_info[0:2] < (2, 7) or \
else:
import unittest
+
+def bit_length(n):
+ s = bin(n)
+ s = s.lstrip('-0b')
+ return len(s)
+
+def to_bytes(n, length=1, byteorder='big', signed=False):
+ if byteorder == 'little':
+ order = range(length)
+ elif byteorder == 'big':
+ order = reversed(range(length))
+ else:
+ raise ValueError("byteorder must be either 'little' or 'big'")
+
+ return bytes((n >> i*8) & 0xff for i in order)
+
+
class LargeTagDecoderTestCase(unittest.TestCase):
def testLargeTag(self):
assert decoder.decode(ints2octs((127, 141, 245, 182, 253, 47, 3, 2, 1, 1))) == (1, null)
@@ -791,4 +808,119 @@ class EndOfOctetsTestCase(unittest.TestC
else:
assert 0, 'end-of-contents octets accepted with unexpected data'
+class NestingDepthLimitTestCase(unittest.TestCase):
+ """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 error.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 error.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 = to_bytes(length,
+ (bit_length(length) + 7) // 8, 'big')
+ inner = b'\x30' + bytes([0x80 | len(length_bytes)]) + \
+ length_bytes + inner
+ try:
+ decoder.decode(inner)
+ except error.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 = to_bytes(length,
+ (bit_length(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 = to_bytes(length,
+ (bit_length(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 error.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 error.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 error.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 error.PyAsn1Error:
+ pass
+ else:
+ assert False, 'Deeply nested with schema not rejected'
+
if __name__ == '__main__': unittest.main()
Index: pyasn1-0.1.9/test/codec/cer/test_decoder.py
===================================================================
--- pyasn1-0.1.9.orig/test/codec/cer/test_decoder.py
+++ pyasn1-0.1.9/test/codec/cer/test_decoder.py
@@ -12,6 +12,7 @@ if version_info[0:2] < (2, 7) or \
else:
import unittest
+
class BooleanDecoderTestCase(unittest.TestCase):
def testTrue(self):
assert decoder.decode(ints2octs((1, 1, 255))) == (1, null)
@@ -38,4 +39,28 @@ class OctetStringDecoderTestCase(unittes
ints2octs((36, 128, 4, 130, 3, 232) + (81,)*1000 + (4, 1, 81, 0, 0))
) == (str2octs('Q'*1001), null)
+class NestingDepthLimitTestCase(unittest.TestCase):
+ """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'
+
+
if __name__ == '__main__': unittest.main()
Index: pyasn1-0.1.9/test/codec/der/test_decoder.py
===================================================================
--- pyasn1-0.1.9.orig/test/codec/der/test_decoder.py
+++ pyasn1-0.1.9/test/codec/der/test_decoder.py
@@ -12,6 +12,23 @@ if version_info[0:2] < (2, 7) or \
else:
import unittest
+
+def bit_length(n):
+ s = bin(n)
+ s = s.lstrip('-0b')
+ return len(s)
+
+def to_bytes(n, length=1, byteorder='big', signed=False):
+ if byteorder == 'little':
+ order = range(length)
+ elif byteorder == 'big':
+ order = reversed(range(length))
+ else:
+ raise ValueError("byteorder must be either 'little' or 'big'")
+
+ return bytes((n >> i*8) & 0xff for i in order)
+
+
class OctetStringDecoderTestCase(unittest.TestCase):
def testShortMode(self):
assert decoder.decode(
@@ -28,4 +45,45 @@ class OctetStringDecoderTestCase(unittes
else:
assert 0, 'indefinite length encoding tolerated'
+class NestingDepthLimitTestCase(unittest.TestCase):
+ """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 = to_bytes(length,
+ (bit_length(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 = to_bytes(length,
+ (bit_length(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'
+
if __name__ == '__main__': unittest.main()
Index: pyasn1-0.1.9/pyasn1/codec/cer/decoder.py
===================================================================
--- pyasn1-0.1.9.orig/pyasn1/codec/cer/decoder.py
+++ pyasn1-0.1.9/pyasn1/codec/cer/decoder.py
@@ -7,7 +7,7 @@ from pyasn1 import error
class BooleanDecoder(decoder.AbstractSimpleDecoder):
protoComponent = univ.Boolean(0)
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet, length,
- state, decodeFun, substrateFun):
+ state, decodeFun, substrateFun, **options):
head, tail = substrate[:length], substrate[length:]
if not head or length != 1:
raise error.PyAsn1Error('Not single-octet Boolean payload')