File CVE-2026-23490.patch of Package python-pyasn1.42351
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.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
@@ -4,6 +4,10 @@ from pyasn1.codec.ber import eoo
from pyasn1.compat.octets import oct2int, isOctetsType
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
+
class AbstractDecoder:
protoComponent = None
def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
@@ -225,7 +229,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.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
@@ -1,6 +1,7 @@
from pyasn1.type import tag, namedtype, univ, char
from pyasn1.codec.ber import decoder, eoo
from pyasn1.compat.octets import ints2octs, str2octs, null
+from pyasn1 import error
from pyasn1.error import PyAsn1Error
from sys import version_info
if version_info[0:2] < (2, 7) or \
@@ -224,6 +225,72 @@ class ObjectIdentifierDecoderTestCase(un
ints2octs((6,2,0x81,0x00))
) == ((2,48), 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'
+
def testEdge7(self):
assert decoder.decode(