From 40b9fcc9381c4456152deb9a448b4e5fd014b7e7 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Sun, 30 Dec 2018 00:09:37 +0300 Subject: [PATCH] Check for OID arc values normalization --- doc/news.rst | 2 ++ pyderasn.py | 2 ++ tests/test_pyderasn.py | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/doc/news.rst b/doc/news.rst index 90bf903..a187825 100644 --- a/doc/news.rst +++ b/doc/news.rst @@ -8,6 +8,8 @@ News * Added `COMPLI `__ ASN.1:2008 test suite. PyDERASN passes it (except for REAL values), but it is more strict sometimes and aimed to be compliant with X.690-201508 +* Check for arc values normalization in ObjectIdentifier. + Forbid non-normalized in DER encoding .. _release4.5: diff --git a/pyderasn.py b/pyderasn.py index 482b345..4e9def7 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -3228,6 +3228,8 @@ class ObjectIdentifier(Obj): arc = 0 while True: octet = indexbytes(v, i) + if i == 0 and octet == 0x80 and not ctx.get("bered", False): + raise DecodeError("non normalized arc encoding") arc = (arc << 7) | (octet & 0x7F) if octet & 0x80 == 0: arcs.append(arc) diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index 94d6343..174abb6 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -2720,6 +2720,46 @@ class TestObjectIdentifier(CommonMixin, TestCase): ObjectIdentifier((2, 999, 3)), ) + @given(data_strategy()) + def test_nonnormalized_first_arc(self, d): + tampered = ( + ObjectIdentifier.tag_default + + len_encode(2) + + b'\x80' + + ObjectIdentifier((1, 0)).encode()[-1:] + ) + ObjectIdentifier().decode(tampered, ctx={"bered": True}) + with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"): + ObjectIdentifier().decode(tampered) + + @given(data_strategy()) + def test_nonnormalized_arcs(self, d): + arcs = d.draw(lists( + integers(min_value=0, max_value=100), + min_size=1, + max_size=5, + )) + dered = ObjectIdentifier((1, 0) + tuple(arcs)).encode() + _, tlen, lv = tag_strip(dered) + _, llen, v = len_decode(lv) + v_no_first_arc = v[1:] + idx_for_tamper = d.draw(integers( + min_value=0, + max_value=len(v_no_first_arc) - 1, + )) + tampered = list(bytearray(v_no_first_arc)) + for _ in range(d.draw(integers(min_value=1, max_value=3))): + tampered.insert(idx_for_tamper, 0x80) + tampered = bytes(bytearray(tampered)) + tampered = ( + ObjectIdentifier.tag_default + + len_encode(len(tampered)) + + tampered + ) + ObjectIdentifier().decode(tampered, ctx={"bered": True}) + with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"): + ObjectIdentifier().decode(tampered) + @composite def enumerated_values_strategy(draw, schema=None, do_expl=False): -- 2.44.0