File CVE-2026-23490.patch of Package python-pyasn1.42350

From 3908f144229eed4df24bd569d16e5991ace44970 Mon Sep 17 00:00:00 2001
From: Simon Pichugin <simon.pichugin@gmail.com>
Date: Fri, 16 Jan 2026 08:57:23 -0800
Subject: [PATCH] Merge commit from fork

Add limit of 20 continuation octets per OID arc to prevent a potential memory
exhaustion from excessive continuation bytes input.
---
 pyasn1/codec/ber/decoder.py     |  20 ++++-
 tests/codec/ber/test_decoder.py | 130 ++++++++++++++++++++++++++++++++
 2 files changed, 149 insertions(+), 1 deletion(-)

Index: pyasn1-0.4.2/pyasn1/codec/ber/decoder.py
===================================================================
--- pyasn1-0.4.2.orig/pyasn1/codec/ber/decoder.py
+++ pyasn1-0.4.2/pyasn1/codec/ber/decoder.py
@@ -36,6 +36,10 @@ class AbstractDecoder(object):
                              **options):
         raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,))
 
+# 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
+
 
 class AbstractSimpleDecoder(AbstractDecoder):
     @staticmethod
@@ -325,7 +329,14 @@ class ObjectIdentifierDecoder(AbstractSi
                 # Construct subid from a number of octets
                 nextSubId = subId
                 subId = 0
+                continuationOctetCount = 0
                 while nextSubId >= 128:
+                    continuationOctetCount += 1
+                    if continuationOctetCount > MAX_OID_ARC_CONTINUATION_OCTETS:
+                        raise error.PyAsn1Error(
+                            'OID arc exceeds maximum continuation octets limit (%d) '
+                            'at position %d' % (MAX_OID_ARC_CONTINUATION_OCTETS, index)
+                        )
                     subId = (subId << 7) + (nextSubId & 0x7F)
                     if index >= substrateLen:
                         raise error.SubstrateUnderrunError(
Index: pyasn1-0.4.2/tests/codec/ber/test_decoder.py
===================================================================
--- pyasn1-0.4.2.orig/tests/codec/ber/test_decoder.py
+++ pyasn1-0.4.2/tests/codec/ber/test_decoder.py
@@ -22,6 +22,7 @@ from pyasn1.type import char
 from pyasn1.codec.ber import decoder
 from pyasn1.codec.ber import eoo
 from pyasn1.compat.octets import ints2octs, str2octs, null
+from pyasn1 import error
 from pyasn1.error import PyAsn1Error
 
 
@@ -407,6 +408,72 @@ class ObjectIdentifierDecoderTestCase(Ba
             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 testExcessiveContinuationOctets(self):
+        """Test that OID arcs with excessive continuation octets are rejected."""
+        # Create a payload with 25 continuation octets (exceeds 20 limit)
+        # 0x81 bytes are continuation octets, 0x01 terminates
+        malicious_payload = ints2octs([0x06, 26]) + ints2octs([0x81] * 25) + ints2octs([0x01])
+        try:
+            decoder.decode(malicious_payload)
+        except error.PyAsn1Error:
+            pass
+        else:
+            assert 0, 'Excessive continuation octets tolerated'
+
+    def testMaxAllowedContinuationOctets(self):
+        """Test that OID arcs at the maximum continuation octets limit work."""
+        # Create a payload with exactly 20 continuation octets (at limit)
+        # This should succeed
+        payload = ints2octs([0x06, 21]) + ints2octs([0x81] * 20) + ints2octs([0x01])
+        try:
+            decoder.decode(payload)
+        except error.PyAsn1Error:
+            assert 0, 'Valid OID with 20 continuation octets rejected'
+
+    def testOneOverContinuationLimit(self):
+        """Test boundary: 21 continuation octets (one over limit) is rejected."""
+        payload = ints2octs([0x06, 22]) + ints2octs([0x81] * 21) + ints2octs([0x01])
+        try:
+            decoder.decode(payload)
+        except error.PyAsn1Error:
+            pass
+        else:
+            assert 0, '21 continuation octets tolerated (should be rejected)'
+
+    def testExcessiveContinuationInSecondArc(self):
+        """Test that limit applies to subsequent arcs, not just the first."""
+        # First arc: valid simple byte (0x55 = 85, decodes to arc 2.5)
+        # Second arc: excessive continuation octets
+        payload = ints2octs([0x06, 27]) + ints2octs([0x55]) + ints2octs([0x81] * 25) + ints2octs([0x01])
+        try:
+            decoder.decode(payload)
+        except error.PyAsn1Error:
+            pass
+        else:
+            assert 0, 'Excessive continuation in second arc tolerated'
+
+    def testMultipleArcsAtLimit(self):
+        """Test multiple arcs each at the continuation limit work correctly."""
+        # Two arcs, each with 20 continuation octets (both at limit)
+        arc1 = ints2octs([0x81] * 20) + ints2octs([0x01])  # 21 bytes
+        arc2 = ints2octs([0x81] * 20) + ints2octs([0x01])  # 21 bytes
+        payload = ints2octs([0x06, 42]) + arc1 + arc2
+        try:
+            decoder.decode(payload)
+        except error.PyAsn1Error:
+            assert 0, 'Multiple valid arcs at limit rejected'
+
+    def testExcessiveContinuationWithMaxBytes(self):
+        """Test with 0xFF continuation bytes (maximum value, not just 0x81)."""
+        # 0xFF bytes are also continuation octets (high bit set)
+        malicious_payload = ints2octs([0x06, 26]) + ints2octs([0xFF] * 25) + ints2octs([0x01])
+        try:
+            decoder.decode(malicious_payload)
+        except error.PyAsn1Error:
+            pass
+        else:
+            assert 0, 'Excessive 0xFF continuation octets tolerated'
+
 
 class RealDecoderTestCase(BaseTestCase):
     def testChar(self):
openSUSE Build Service is sponsored by