python-pyasn1/python-pyasn1-0.3.7-CVE-2026-59886.patch
Masahiro Matsuya d4c2f2d440 Fix missing 'from pyasn1.type import univ' in test patches
Add the missing import to the cer and der test_decoder.py sections
of python-pyasn1-0.3.7-CVE-2026-59886.patch. The new tests use
univ.Real() but the import line was not added along with the
encoder import, causing NameError at test time.

Signed-off-by: Masahiro Matsuya <mmatsuya@redhat.com>
2026-08-03 15:05:24 +09:00

250 lines
8.4 KiB
Diff

From e8f259647c04cf9a41130c8387cef2690d8ec19e Mon Sep 17 00:00:00 2001
From: Simon Pichugin <simon.pichugin@gmail.com>
Date: Wed, 8 Jul 2026 17:32:09 -0700
Subject: [PATCH] Merge commit from fork
---
pyasn1/type/univ.py | 21 ++++++++++---
tests/codec/ber/test_decoder.py | 54 +++++++++++++++++++++++++++------
tests/codec/cer/test_decoder.py | 11 +++++++
tests/codec/der/test_decoder.py | 20 ++++++++++++
tests/type/test_univ.py | 40 ++++++++++++++++++++++++
5 files changed, 131 insertions(+), 15 deletions(-)
diff --git a/pyasn1/type/univ.py b/pyasn1/type/univ.py
index a90c648..5d6c23a 100644
--- a/pyasn1/type/univ.py
+++ b/pyasn1/type/univ.py
@@ -1444,7 +1444,7 @@ class Real(base.AbstractSimpleAsn1Item):
def __normalizeBase10(value):
m, b, e = value
while m and m % 10 == 0:
- m /= 10
+ m //= 10
e += 1
return m, b, e
@@ -1595,10 +1595,21 @@ class Real(base.AbstractSimpleAsn1Item):
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)))
diff --git a/tests/codec/ber/test_decoder.py b/tests/codec/ber/test_decoder.py
index ba7dfec..9c98864 100644
--- a/tests/codec/ber/test_decoder.py
+++ b/tests/codec/ber/test_decoder.py
@@ -13,7 +13,7 @@ except ImportError:
from tests.base import BaseTestCase
from pyasn1.type import tag, namedtype, univ, char
-from pyasn1.codec.ber import decoder, eoo
+from pyasn1.codec.ber import decoder, encoder, eoo
from pyasn1.compat.octets import ints2octs, str2octs, null
from pyasn1.error import PyAsn1Error
@@ -501,17 +501,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(
+ ints2octs((9, 5, 162, 0, 255, 255, 1))
+ )
+
+ assert tuple(value) == (1, 2, 262140)
+ assert rest == null
+
+ def testBin7(self): # large exponent in 4-octet form, base = 16
+ value, rest = decoder.decode(
+ ints2octs((9, 7, 227, 4, 1, 35, 69, 103, 1))
+ )
-# def testBin6(self):
-# assert decoder.decode(
-# ints2octs((9, 5, 162, 0, 255, 255, 1))
-# ) == (univ.Real((1, 2, 262140)), null)
+ assert tuple(value) == (-1, 2, 76354972)
+ assert rest == null
+
+ def testLargeBinaryRoundTrip(self):
+ substrate = encoder.encode(univ.Real((-1, 2, 76354972)))
+ value, rest = decoder.decode(substrate)
+
+ assert tuple(value) == (-1, 2, 76354972)
+ assert rest == null
+
+ def testLongFormBinaryRealExponentLength(self):
+ value, rest = decoder.decode(
+ ints2octs((9, 6, 0x83, 3, 0x0f, 0x42, 0x40, 1))
+ )
-# def testBin7(self):
-# assert decoder.decode(
-# ints2octs((9, 7, 227, 4, 1, 35, 69, 103, 1))
-# ) == (univ.Real((-1, 2, 76354972)), null)
+ assert tuple(value) == (1, 2, 1000000)
+ assert rest == 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() == '<overflow>'
+ assert rest == b'6\xd0B\x00\x00\x00\x00\x00\x00\x00'
+
+ 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 828c17f..c4a91db 100644
--- a/tests/codec/cer/test_decoder.py
+++ b/tests/codec/cer/test_decoder.py
@@ -14,6 +14,8 @@ except ImportError:
from tests.base import BaseTestCase
from pyasn1.codec.cer import decoder
+from pyasn1.codec.cer import encoder
+from pyasn1.type import univ
from pyasn1.compat.octets import ints2octs, str2octs, null
from pyasn1.error import PyAsn1Error
@@ -65,6 +66,16 @@ class OctetStringDecoderTestCase(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 == null
+
+
+
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 6f292fd..08101a4 100644
--- a/tests/codec/der/test_decoder.py
+++ b/tests/codec/der/test_decoder.py
@@ -14,6 +14,8 @@ except ImportError:
from tests.base import BaseTestCase
from pyasn1.codec.der import decoder
+from pyasn1.codec.der import encoder
+from pyasn1.type import univ
from pyasn1.compat.octets import ints2octs, null
from pyasn1.error import PyAsn1Error
@@ -72,6 +73,25 @@ class OctetStringDecoderTestCase(BaseTestCase):
assert 0, 'chunked encoding tolerated'
+class RealDecoderTestCase(BaseTestCase):
+ def testCanonicalLargeBinaryReal(self):
+ substrate = encoder.encode(univ.Real((1, 2, 1000000)))
+ assert substrate == ints2octs((9, 5, 0x82, 0x0f, 0x42, 0x40, 1))
+
+ value, rest = decoder.decode(substrate)
+
+ assert tuple(value) == (1, 2, 1000000)
+ assert rest == null
+
+ def testLargeBinaryRoundTrip(self):
+ substrate = encoder.encode(univ.Real((-1, 2, 76354972)))
+ value, rest = decoder.decode(substrate)
+
+ assert tuple(value) == (-1, 2, 76354972)
+ assert rest == null
+
+
+
suite = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__])
if __name__ == '__main__':
diff --git a/tests/type/test_univ.py b/tests/type/test_univ.py
index f5124df..3453d11 100644
--- a/tests/type/test_univ.py
+++ b/tests/type/test_univ.py
@@ -632,9 +632,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() == '<overflow>'
+
+ 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'