]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - tests/test_pyderasn.py
Check for OID arc values normalization
[pyderasn.git] / tests / test_pyderasn.py
index 8f02a02ad0fddaff99d2509bea8e726eebf1606d..174abb6d7beaaca1871cc4fadb84c208d0e8cc37 100644 (file)
@@ -1,6 +1,6 @@
 # coding: utf-8
 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
-# Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
+# Copyright (C) 2017-2019 Sergey Matveev <stargrave@stargrave.org>
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as
@@ -16,6 +16,7 @@
 # License along with this program.  If not, see
 # <http://www.gnu.org/licenses/>.
 
+from copy import deepcopy
 from datetime import datetime
 from string import ascii_letters
 from string import digits
@@ -132,6 +133,7 @@ tag_forms = sampled_from((TagFormConstructed, TagFormPrimitive))
 decode_path_strat = lists(integers(), max_size=3).map(
     lambda decode_path: tuple(str(dp) for dp in decode_path)
 )
+ctx_dummy = dictionaries(integers(), integers(), min_size=2, max_size=4).example()
 
 
 class TestHex(TestCase):
@@ -561,10 +563,13 @@ class TestBoolean(CommonMixin, TestCase):
             list(obj_expled.pps())
             pprint(obj_expled, big_blobs=True, with_decode_path=True)
             obj_expled_encoded = obj_expled.encode()
+            ctx_copied = deepcopy(ctx_dummy)
             obj_decoded, tail = obj_expled.decode(
                 obj_expled_encoded + tail_junk,
                 offset=offset,
+                ctx=ctx_copied,
             )
+            self.assertDictEqual(ctx_copied, ctx_dummy)
             repr(obj_decoded)
             list(obj_decoded.pps())
             pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -1041,10 +1046,13 @@ class TestInteger(CommonMixin, TestCase):
             list(obj_expled.pps())
             pprint(obj_expled, big_blobs=True, with_decode_path=True)
             obj_expled_encoded = obj_expled.encode()
+            ctx_copied = deepcopy(ctx_dummy)
             obj_decoded, tail = obj_expled.decode(
                 obj_expled_encoded + tail_junk,
                 offset=offset,
+                ctx=ctx_copied,
             )
+            self.assertDictEqual(ctx_copied, ctx_dummy)
             repr(obj_decoded)
             list(obj_decoded.pps())
             pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -1424,10 +1432,13 @@ class TestBitString(CommonMixin, TestCase):
             list(obj_expled.pps())
             pprint(obj_expled, big_blobs=True, with_decode_path=True)
             obj_expled_encoded = obj_expled.encode()
+            ctx_copied = deepcopy(ctx_dummy)
             obj_decoded, tail = obj_expled.decode(
                 obj_expled_encoded + tail_junk,
                 offset=offset,
+                ctx=ctx_copied,
             )
+            self.assertDictEqual(ctx_copied, ctx_dummy)
             repr(obj_decoded)
             list(obj_decoded.pps())
             pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -2002,10 +2013,13 @@ class TestOctetString(CommonMixin, TestCase):
             list(obj_expled.pps())
             pprint(obj_expled, big_blobs=True, with_decode_path=True)
             obj_expled_encoded = obj_expled.encode()
+            ctx_copied = deepcopy(ctx_dummy)
             obj_decoded, tail = obj_expled.decode(
                 obj_expled_encoded + tail_junk,
                 offset=offset,
+                ctx=ctx_copied,
             )
+            self.assertDictEqual(ctx_copied, ctx_dummy)
             repr(obj_decoded)
             list(obj_decoded.pps())
             pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -2299,10 +2313,13 @@ class TestNull(CommonMixin, TestCase):
             list(obj_expled.pps())
             pprint(obj_expled, big_blobs=True, with_decode_path=True)
             obj_expled_encoded = obj_expled.encode()
+            ctx_copied = deepcopy(ctx_dummy)
             obj_decoded, tail = obj_expled.decode(
                 obj_expled_encoded + tail_junk,
                 offset=offset,
+                ctx=ctx_copied,
             )
+            self.assertDictEqual(ctx_copied, ctx_dummy)
             repr(obj_decoded)
             list(obj_decoded.pps())
             pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -2631,10 +2648,13 @@ class TestObjectIdentifier(CommonMixin, TestCase):
             list(obj_expled.pps())
             pprint(obj_expled, big_blobs=True, with_decode_path=True)
             obj_expled_encoded = obj_expled.encode()
+            ctx_copied = deepcopy(ctx_dummy)
             obj_decoded, tail = obj_expled.decode(
                 obj_expled_encoded + tail_junk,
                 offset=offset,
+                ctx=ctx_copied,
             )
+            self.assertDictEqual(ctx_copied, ctx_dummy)
             repr(obj_decoded)
             list(obj_decoded.pps())
             pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -2700,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):
@@ -2922,10 +2982,13 @@ class TestEnumerated(CommonMixin, TestCase):
         list(obj_expled.pps())
         pprint(obj_expled, big_blobs=True, with_decode_path=True)
         obj_expled_encoded = obj_expled.encode()
+        ctx_copied = deepcopy(ctx_dummy)
         obj_decoded, tail = obj_expled.decode(
             obj_expled_encoded + tail_junk,
             offset=offset,
+            ctx=ctx_copied,
         )
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         repr(obj_decoded)
         list(obj_decoded.pps())
         pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -3247,10 +3310,13 @@ class StringMixin(object):
         list(obj_expled.pps())
         pprint(obj_expled, big_blobs=True, with_decode_path=True)
         obj_expled_encoded = obj_expled.encode()
+        ctx_copied = deepcopy(ctx_dummy)
         obj_decoded, tail = obj_expled.decode(
             obj_expled_encoded + tail_junk,
             offset=offset,
+            ctx=ctx_copied,
         )
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         repr(obj_decoded)
         list(obj_decoded.pps())
         pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -3673,10 +3739,13 @@ class TimeMixin(object):
         list(obj_expled.pps())
         pprint(obj_expled, big_blobs=True, with_decode_path=True)
         obj_expled_encoded = obj_expled.encode()
+        ctx_copied = deepcopy(ctx_dummy)
         obj_decoded, tail = obj_expled.decode(
             obj_expled_encoded + tail_junk,
             offset=offset,
+            ctx=ctx_copied,
         )
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         repr(obj_decoded)
         list(obj_decoded.pps())
         pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -4060,10 +4129,13 @@ class TestAny(CommonMixin, TestCase):
             list(obj_expled.pps())
             pprint(obj_expled, big_blobs=True, with_decode_path=True)
             obj_expled_encoded = obj_expled.encode()
+            ctx_copied = deepcopy(ctx_dummy)
             obj_decoded, tail = obj_expled.decode(
                 obj_expled_encoded + tail_junk,
                 offset=offset,
+                ctx=ctx_copied,
             )
+            self.assertDictEqual(ctx_copied, ctx_dummy)
             repr(obj_decoded)
             list(obj_decoded.pps())
             pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -4411,10 +4483,13 @@ class TestChoice(CommonMixin, TestCase):
         list(obj_expled.pps())
         pprint(obj_expled, big_blobs=True, with_decode_path=True)
         obj_expled_encoded = obj_expled.encode()
+        ctx_copied = deepcopy(ctx_dummy)
         obj_decoded, tail = obj_expled.decode(
             obj_expled_encoded + tail_junk,
             offset=offset,
+            ctx=ctx_copied,
         )
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         repr(obj_decoded)
         list(obj_decoded.pps())
         pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -4922,10 +4997,14 @@ class SeqMixing(object):
         t, _, lv = tag_strip(seq_encoded)
         _, _, v = len_decode(lv)
         seq_encoded_lenindef = t + LENINDEF + v + EOC
+        ctx_copied = deepcopy(ctx_dummy)
+        ctx_copied["bered"] = True
         seq_decoded_lenindef, tail_lenindef = seq.decode(
             seq_encoded_lenindef + tail_junk,
-            ctx={"bered": True},
+            ctx=ctx_copied,
         )
+        del ctx_copied["bered"]
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         self.assertTrue(seq_decoded_lenindef.lenindef)
         self.assertTrue(seq_decoded_lenindef.bered)
         with self.assertRaises(DecodeError):
@@ -5575,10 +5654,13 @@ class SeqOfMixing(object):
         list(obj_expled.pps())
         pprint(obj_expled, big_blobs=True, with_decode_path=True)
         obj_expled_encoded = obj_expled.encode()
+        ctx_copied = deepcopy(ctx_dummy)
         obj_decoded, tail = obj_expled.decode(
             obj_expled_encoded + tail_junk,
             offset=offset,
+            ctx=ctx_copied,
         )
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         repr(obj_decoded)
         list(obj_decoded.pps())
         pprint(obj_decoded, big_blobs=True, with_decode_path=True)
@@ -5869,10 +5951,10 @@ class TestGoMarshalVectors(TestCase):
         seq["erste"] = PrintableString("test")
         self.assertSequenceEqual(seq.encode(), hexdec("3006130474657374"))
         # Asterisk is actually not allowable
-        PrintableString.allowable_chars |= set(b"*")
+        PrintableString._allowable_chars |= set(b"*")
         seq["erste"] = PrintableString("test*")
         self.assertSequenceEqual(seq.encode(), hexdec("30071305746573742a"))
-        PrintableString.allowable_chars -= set(b"*")
+        PrintableString._allowable_chars -= set(b"*")
 
         class Seq(Sequence):
             schema = (
@@ -6044,7 +6126,12 @@ class TestDefinesByPath(TestCase):
         pprint(seq_sequenced, big_blobs=True, with_decode_path=True)
 
         defines_by_path = []
-        seq_integered, _ = Seq().decode(seq_integered_raw)
+        ctx_copied = deepcopy(ctx_dummy)
+        seq_integered, _ = Seq().decode(
+            seq_integered_raw,
+            ctx=ctx_copied,
+        )
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         self.assertIsNone(seq_integered["value"].defined)
         defines_by_path.append(
             (("type",), ((("value",), {
@@ -6052,10 +6139,13 @@ class TestDefinesByPath(TestCase):
                 type_sequenced: SeqInner(),
             }),))
         )
+        ctx_copied["defines_by_path"] = defines_by_path
         seq_integered, _ = Seq().decode(
             seq_integered_raw,
-            ctx={"defines_by_path": defines_by_path},
+            ctx=ctx_copied,
         )
+        del ctx_copied["defines_by_path"]
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         self.assertIsNotNone(seq_integered["value"].defined)
         self.assertEqual(seq_integered["value"].defined[0], type_integered)
         self.assertEqual(seq_integered["value"].defined[1], Integer(123))
@@ -6066,10 +6156,13 @@ class TestDefinesByPath(TestCase):
         list(seq_integered.pps())
         pprint(seq_integered, big_blobs=True, with_decode_path=True)
 
+        ctx_copied["defines_by_path"] = defines_by_path
         seq_sequenced, _ = Seq().decode(
             seq_sequenced_raw,
-            ctx={"defines_by_path": defines_by_path},
+            ctx=ctx_copied,
         )
+        del ctx_copied["defines_by_path"]
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         self.assertIsNotNone(seq_sequenced["value"].defined)
         self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
         seq_inner = seq_sequenced["value"].defined[1]
@@ -6082,10 +6175,13 @@ class TestDefinesByPath(TestCase):
             ("value", DecodePathDefBy(type_sequenced), "typeInner"),
             ((("valueInner",), {type_innered: Pairs()}),),
         ))
+        ctx_copied["defines_by_path"] = defines_by_path
         seq_sequenced, _ = Seq().decode(
             seq_sequenced_raw,
-            ctx={"defines_by_path": defines_by_path},
+            ctx=ctx_copied,
         )
+        del ctx_copied["defines_by_path"]
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         self.assertIsNotNone(seq_sequenced["value"].defined)
         self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
         seq_inner = seq_sequenced["value"].defined[1]
@@ -6112,10 +6208,13 @@ class TestDefinesByPath(TestCase):
                 type_octet_stringed: OctetString(),
             }),),
         ))
+        ctx_copied["defines_by_path"] = defines_by_path
         seq_sequenced, _ = Seq().decode(
             seq_sequenced_raw,
-            ctx={"defines_by_path": defines_by_path},
+            ctx=ctx_copied,
         )
+        del ctx_copied["defines_by_path"]
+        self.assertDictEqual(ctx_copied, ctx_dummy)
         self.assertIsNotNone(seq_sequenced["value"].defined)
         self.assertEqual(seq_sequenced["value"].defined[0], type_sequenced)
         seq_inner = seq_sequenced["value"].defined[1]