]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - tests/test_pyderasn.py
More linter satisfaction
[pyderasn.git] / tests / test_pyderasn.py
index a0a60cb16adbea1b9cd358f54f307893b80f35e2..dec37f3f3c65823612ff5a68bf23492a954ea0bb 100644 (file)
@@ -1,11 +1,10 @@
 # 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-2020 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
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
+# published by the Free Software Foundation, version 3 of the License.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -622,6 +621,10 @@ class TestBoolean(CommonMixin, TestCase):
         self.assertTrue(obj.ber_encoded)
         self.assertFalse(obj.lenindef)
         self.assertTrue(obj.bered)
+        obj = obj.copy()
+        self.assertTrue(obj.ber_encoded)
+        self.assertFalse(obj.lenindef)
+        self.assertTrue(obj.bered)
 
     @given(
         integers(min_value=1).map(tag_ctxc),
@@ -641,6 +644,11 @@ class TestBoolean(CommonMixin, TestCase):
         self.assertFalse(obj.lenindef)
         self.assertFalse(obj.ber_encoded)
         self.assertTrue(obj.bered)
+        obj = obj.copy()
+        self.assertTrue(obj.expl_lenindef)
+        self.assertFalse(obj.lenindef)
+        self.assertFalse(obj.ber_encoded)
+        self.assertTrue(obj.bered)
         self.assertSequenceEqual(tail, junk)
         repr(obj)
         list(obj.pps())
@@ -1129,7 +1137,7 @@ def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=
 
     def _value(value_required):
         if not value_required and draw(booleans()):
-            return
+            return None
         generation_choice = 0
         if value_required:
             generation_choice = draw(sampled_from((1, 2, 3)))
@@ -1138,9 +1146,9 @@ def bit_string_values_strategy(draw, schema=None, value_required=False, do_expl=
                 sampled_from(("0", "1")),
                 max_size=len(schema),
             )))
-        elif generation_choice == 2 or draw(booleans()):
+        if generation_choice == 2 or draw(booleans()):
             return draw(binary(max_size=len(schema) // 8))
-        elif generation_choice == 3 or draw(booleans()):
+        if generation_choice == 3 or draw(booleans()):
             return tuple(draw(lists(sampled_from([name for name, _ in schema]))))
         return None
     value = _value(value_required)
@@ -1584,6 +1592,10 @@ class TestBitString(CommonMixin, TestCase):
             self.assertTrue(obj.ber_encoded)
             self.assertEqual(obj.lenindef, lenindef_expected)
             self.assertTrue(obj.bered)
+            obj = obj.copy()
+            self.assertTrue(obj.ber_encoded)
+            self.assertEqual(obj.lenindef, lenindef_expected)
+            self.assertTrue(obj.bered)
             self.assertEqual(len(encoded), obj.tlvlen)
 
     @given(
@@ -1716,6 +1728,10 @@ class TestBitString(CommonMixin, TestCase):
         self.assertTrue(obj.ber_encoded)
         self.assertTrue(obj.lenindef)
         self.assertTrue(obj.bered)
+        obj = obj.copy()
+        self.assertTrue(obj.ber_encoded)
+        self.assertTrue(obj.lenindef)
+        self.assertTrue(obj.bered)
 
 
 @composite
@@ -2103,6 +2119,10 @@ class TestOctetString(CommonMixin, TestCase):
             self.assertTrue(obj.ber_encoded)
             self.assertEqual(obj.lenindef, lenindef_expected)
             self.assertTrue(obj.bered)
+            obj = obj.copy()
+            self.assertTrue(obj.ber_encoded)
+            self.assertEqual(obj.lenindef, lenindef_expected)
+            self.assertTrue(obj.bered)
             self.assertEqual(len(encoded), obj.tlvlen)
 
     @given(
@@ -2410,6 +2430,7 @@ class TestObjectIdentifier(CommonMixin, TestCase):
         repr(err.exception)
         obj = ObjectIdentifier(value)
         self.assertTrue(obj.ready)
+        self.assertFalse(obj.ber_encoded)
         repr(obj)
         list(obj.pps())
         pprint(obj, big_blobs=True, with_decode_path=True)
@@ -2720,6 +2741,55 @@ class TestObjectIdentifier(CommonMixin, TestCase):
             ObjectIdentifier((2, 999, 3)),
         )
 
+    def test_nonnormalized_first_arc(self):
+        tampered = (
+            ObjectIdentifier.tag_default +
+            len_encode(2) +
+            b'\x80' +
+            ObjectIdentifier((1, 0)).encode()[-1:]
+        )
+        obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
+        self.assertTrue(obj.ber_encoded)
+        self.assertTrue(obj.bered)
+        obj = obj.copy()
+        self.assertTrue(obj.ber_encoded)
+        self.assertTrue(obj.bered)
+        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()
+        _, _, lv = tag_strip(dered)
+        _, _, 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
+        )
+        obj, _ = ObjectIdentifier().decode(tampered, ctx={"bered": True})
+        self.assertTrue(obj.ber_encoded)
+        self.assertTrue(obj.bered)
+        obj = obj.copy()
+        self.assertTrue(obj.ber_encoded)
+        self.assertTrue(obj.bered)
+        with assertRaisesRegex(self, DecodeError, "non normalized arc encoding"):
+            ObjectIdentifier().decode(tampered)
+
 
 @composite
 def enumerated_values_strategy(draw, schema=None, do_expl=False):
@@ -3451,6 +3521,10 @@ class TestVisibleString(
         self.assertTrue(obj.ber_encoded)
         self.assertFalse(obj.lenindef)
         self.assertTrue(obj.bered)
+        obj = obj.copy()
+        self.assertTrue(obj.ber_encoded)
+        self.assertFalse(obj.lenindef)
+        self.assertTrue(obj.bered)
 
         obj, tail = VisibleString().decode(
             hexdec("3A8004034A6F6E040265730000"),
@@ -3461,6 +3535,10 @@ class TestVisibleString(
         self.assertTrue(obj.ber_encoded)
         self.assertTrue(obj.lenindef)
         self.assertTrue(obj.bered)
+        obj = obj.copy()
+        self.assertTrue(obj.ber_encoded)
+        self.assertTrue(obj.lenindef)
+        self.assertTrue(obj.bered)
 
 
 class TestGeneralString(
@@ -3693,6 +3771,7 @@ class TimeMixin(object):
         pprint(obj, big_blobs=True, with_decode_path=True)
         self.assertFalse(obj.expled)
         obj_encoded = obj.encode()
+        self.additional_symmetric_check(value, obj_encoded)
         obj_expled = obj(value, expl=tag_expl)
         self.assertTrue(obj_expled.expled)
         repr(obj_expled)
@@ -3735,6 +3814,28 @@ class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
     min_datetime = datetime(1900, 1, 1)
     max_datetime = datetime(9999, 12, 31)
 
+    def additional_symmetric_check(self, value, obj_encoded):
+        if value.microsecond > 0:
+            self.assertFalse(obj_encoded.endswith(b"0Z"))
+
+    def test_x690_vector_valid(self):
+        for data in ((
+                b"19920521000000Z",
+                b"19920622123421Z",
+                b"19920722132100.3Z",
+        )):
+            GeneralizedTime(data)
+
+    def test_x690_vector_invalid(self):
+        for data in ((
+                b"19920520240000Z",
+                b"19920622123421.0Z",
+                b"19920722132100.30Z",
+        )):
+            with self.assertRaises(DecodeError) as err:
+                GeneralizedTime(data)
+            repr(err.exception)
+
     def test_go_vectors_invalid(self):
         for data in ((
                 b"20100102030405",
@@ -3811,6 +3912,11 @@ class TestGeneralizedTime(TimeMixin, CommonMixin, TestCase):
                 junk
             )
 
+    def test_ns_fractions(self):
+        GeneralizedTime(b"20010101000000.000001Z")
+        with assertRaisesRegex(self, DecodeError, "only microsecond fractions"):
+            GeneralizedTime(b"20010101000000.0000001Z")
+
 
 class TestUTCTime(TimeMixin, CommonMixin, TestCase):
     base_klass = UTCTime
@@ -3818,6 +3924,26 @@ class TestUTCTime(TimeMixin, CommonMixin, TestCase):
     min_datetime = datetime(2000, 1, 1)
     max_datetime = datetime(2049, 12, 31)
 
+    def additional_symmetric_check(self, value, obj_encoded):
+        pass
+
+    def test_x690_vector_valid(self):
+        for data in ((
+                b"920521000000Z",
+                b"920622123421Z",
+                b"920722132100Z",
+        )):
+            UTCTime(data)
+
+    def test_x690_vector_invalid(self):
+        for data in ((
+                b"920520240000Z",
+                b"9207221321Z",
+        )):
+            with self.assertRaises(DecodeError) as err:
+                UTCTime(data)
+            repr(err.exception)
+
     def test_go_vectors_invalid(self):
         for data in ((
                 b"a10506234540Z",
@@ -4154,6 +4280,10 @@ class TestAny(CommonMixin, TestCase):
         self.assertTrue(obj.lenindef)
         self.assertFalse(obj.ber_encoded)
         self.assertTrue(obj.bered)
+        obj = obj.copy()
+        self.assertTrue(obj.lenindef)
+        self.assertFalse(obj.ber_encoded)
+        self.assertTrue(obj.bered)
         repr(obj)
         list(obj.pps())
         pprint(obj, big_blobs=True, with_decode_path=True)
@@ -4539,15 +4669,13 @@ def seq_values_strategy(draw, seq_klass, do_expl=False):
     value = None
     if draw(booleans()):
         value = seq_klass()
-        value._value = {
-            k: v for k, v in draw(dictionaries(
-                integers(),
-                one_of(
-                    booleans().map(Boolean),
-                    integers().map(Integer),
-                ),
-            )).items()
-        }
+        value._value = draw(dictionaries(
+            integers(),
+            one_of(
+                booleans().map(Boolean),
+                integers().map(Integer),
+            ),
+        ))
     schema = None
     if draw(booleans()):
         schema = list(draw(dictionaries(
@@ -4566,15 +4694,13 @@ def seq_values_strategy(draw, seq_klass, do_expl=False):
     default = None
     if draw(booleans()):
         default = seq_klass()
-        default._value = {
-            k: v for k, v in draw(dictionaries(
-                integers(),
-                one_of(
-                    booleans().map(Boolean),
-                    integers().map(Integer),
-                ),
-            )).items()
-        }
+        default._value = draw(dictionaries(
+            integers(),
+            one_of(
+                booleans().map(Boolean),
+                integers().map(Integer),
+            ),
+        ))
     optional = draw(one_of(none(), booleans()))
     _decoded = (
         draw(integers(min_value=0)),
@@ -4967,6 +5093,9 @@ class SeqMixing(object):
         self.assertDictEqual(ctx_copied, ctx_dummy)
         self.assertTrue(seq_decoded_lenindef.lenindef)
         self.assertTrue(seq_decoded_lenindef.bered)
+        seq_decoded_lenindef = seq_decoded_lenindef.copy()
+        self.assertTrue(seq_decoded_lenindef.lenindef)
+        self.assertTrue(seq_decoded_lenindef.bered)
         with self.assertRaises(DecodeError):
             seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
         with self.assertRaises(DecodeError):
@@ -5084,6 +5213,9 @@ class SeqMixing(object):
             seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
             self.assertTrue(seq_decoded.ber_encoded)
             self.assertTrue(seq_decoded.bered)
+            seq_decoded = seq_decoded.copy()
+            self.assertTrue(seq_decoded.ber_encoded)
+            self.assertTrue(seq_decoded.bered)
             for name, value in _schema:
                 self.assertEqual(seq_decoded[name], seq_with_default[name])
                 self.assertEqual(seq_decoded[name], value)
@@ -5112,8 +5244,7 @@ class SeqMixing(object):
         with self.assertRaises(TagMismatch):
             seq_missing.decode(seq_encoded)
 
-    @given(data_strategy())
-    def test_bered(self, d):
+    def test_bered(self):
         class Seq(self.base_klass):
             schema = (("underlying", Boolean()),)
         encoded = Boolean.tag_default + len_encode(1) + b"\x01"
@@ -5122,6 +5253,10 @@ class SeqMixing(object):
         self.assertFalse(decoded.ber_encoded)
         self.assertFalse(decoded.lenindef)
         self.assertTrue(decoded.bered)
+        decoded = decoded.copy()
+        self.assertFalse(decoded.ber_encoded)
+        self.assertFalse(decoded.lenindef)
+        self.assertTrue(decoded.bered)
 
         class Seq(self.base_klass):
             schema = (("underlying", OctetString()),)
@@ -5138,6 +5273,10 @@ class SeqMixing(object):
         self.assertFalse(decoded.ber_encoded)
         self.assertFalse(decoded.lenindef)
         self.assertTrue(decoded.bered)
+        decoded = decoded.copy()
+        self.assertFalse(decoded.ber_encoded)
+        self.assertFalse(decoded.lenindef)
+        self.assertTrue(decoded.bered)
 
 
 class TestSequence(SeqMixing, CommonMixin, TestCase):
@@ -5234,9 +5373,12 @@ class TestSet(SeqMixing, CommonMixin, TestCase):
             seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
             self.assertTrue(seq_decoded.ber_encoded)
             self.assertTrue(seq_decoded.bered)
+            seq_decoded = seq_decoded.copy()
+            self.assertTrue(seq_decoded.ber_encoded)
+            self.assertTrue(seq_decoded.bered)
             self.assertSequenceEqual(
                 [bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
-                [t for t in tags],
+                tags,
             )
 
 
@@ -5659,6 +5801,9 @@ class SeqOfMixing(object):
         )
         self.assertTrue(obj_decoded_lenindef.lenindef)
         self.assertTrue(obj_decoded_lenindef.bered)
+        obj_decoded_lenindef = obj_decoded_lenindef.copy()
+        self.assertTrue(obj_decoded_lenindef.lenindef)
+        self.assertTrue(obj_decoded_lenindef.bered)
         repr(obj_decoded_lenindef)
         list(obj_decoded_lenindef.pps())
         pprint(obj_decoded_lenindef, big_blobs=True, with_decode_path=True)
@@ -5668,8 +5813,7 @@ class SeqOfMixing(object):
         with self.assertRaises(DecodeError):
             obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
 
-    @given(data_strategy())
-    def test_bered(self, d):
+    def test_bered(self):
         class SeqOf(self.base_klass):
             schema = Boolean()
         encoded = Boolean(False).encode()
@@ -5681,6 +5825,10 @@ class SeqOfMixing(object):
         self.assertFalse(decoded.ber_encoded)
         self.assertFalse(decoded.lenindef)
         self.assertTrue(decoded.bered)
+        decoded = decoded.copy()
+        self.assertFalse(decoded.ber_encoded)
+        self.assertFalse(decoded.lenindef)
+        self.assertTrue(decoded.bered)
 
         class SeqOf(self.base_klass):
             schema = OctetString()
@@ -5698,6 +5846,10 @@ class SeqOfMixing(object):
         self.assertFalse(decoded.ber_encoded)
         self.assertFalse(decoded.lenindef)
         self.assertTrue(decoded.bered)
+        decoded = decoded.copy()
+        self.assertFalse(decoded.ber_encoded)
+        self.assertFalse(decoded.lenindef)
+        self.assertTrue(decoded.bered)
 
 
 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
@@ -5763,6 +5915,9 @@ class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
             seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
             self.assertTrue(seq_decoded.ber_encoded)
             self.assertTrue(seq_decoded.bered)
+            seq_decoded = seq_decoded.copy()
+            self.assertTrue(seq_decoded.ber_encoded)
+            self.assertTrue(seq_decoded.bered)
             self.assertSequenceEqual(
                 [obj.encode() for obj in seq_decoded],
                 values,
@@ -5966,7 +6121,10 @@ class TestPP(TestCase):
         chosen_id = oids[chosen]
         pp = _pp(asn1_type_name=ObjectIdentifier.asn1_type_name, value=chosen)
         self.assertNotIn(chosen_id, pp_console_row(pp))
-        self.assertIn(chosen_id, pp_console_row(pp, oids=oids))
+        self.assertIn(
+            chosen_id,
+            pp_console_row(pp, oid_maps=[{'whatever': 'whenever'}, oids]),
+        )
 
 
 class TestAutoAddSlots(TestCase):
@@ -6268,9 +6426,15 @@ class TestStrictDefaultExistence(TestCase):
             decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
             self.assertTrue(decoded.ber_encoded)
             self.assertTrue(decoded.bered)
+            decoded = decoded.copy()
+            self.assertTrue(decoded.ber_encoded)
+            self.assertTrue(decoded.bered)
             decoded, _ = seq.decode(raw, ctx={"bered": True})
             self.assertTrue(decoded.ber_encoded)
             self.assertTrue(decoded.bered)
+            decoded = decoded.copy()
+            self.assertTrue(decoded.ber_encoded)
+            self.assertTrue(decoded.bered)
 
 
 class TestX690PrefixedType(TestCase):