]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - tests/test_pyderasn.py
Separate ber/ber_encoded attributes
[pyderasn.git] / tests / test_pyderasn.py
index 147e3cd30457860db037ab519467e05dce6c2933..dd3506b88c3216a221fe15096ccdc1d8c8fbf9ff 100644 (file)
@@ -608,8 +608,9 @@ class TestBoolean(CommonMixin, TestCase):
             ctx={"bered": True},
         )
         self.assertTrue(bool(obj))
-        self.assertTrue(obj.bered)
+        self.assertTrue(obj.ber_encoded)
         self.assertFalse(obj.lenindef)
+        self.assertTrue(obj.bered)
 
     @given(
         integers(min_value=1).map(tag_ctxc),
@@ -624,6 +625,9 @@ class TestBoolean(CommonMixin, TestCase):
             ctx={"bered": True},
         )
         self.assertTrue(obj.expl_lenindef)
+        self.assertFalse(obj.lenindef)
+        self.assertFalse(obj.ber_encoded)
+        self.assertTrue(obj.bered)
         self.assertSequenceEqual(tail, junk)
 
     @given(
@@ -657,9 +661,10 @@ class TestBoolean(CommonMixin, TestCase):
                     v.expl_tlvlen,
                     v.expl_tlen,
                     v.expl_llen,
-                    v.bered,
+                    v.ber_encoded,
                     v.lenindef,
                     v.expl_lenindef,
+                    v.bered,
                 ) for v in seqof
             ),
             set(((
@@ -670,6 +675,7 @@ class TestBoolean(CommonMixin, TestCase):
                 False,
                 False,
                 True,
+                True,
             ),)),
         )
 
@@ -809,9 +815,19 @@ class TestInteger(CommonMixin, TestCase):
         with self.assertRaises(BoundsError) as err:
             Integer(value=values[0], bounds=(values[1], values[2]))
         repr(err.exception)
+        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+            Integer(bounds=(values[1], values[2])).decode(
+                Integer(values[0]).encode()
+            )
+        repr(err.exception)
         with self.assertRaises(BoundsError) as err:
             Integer(value=values[2], bounds=(values[0], values[1]))
         repr(err.exception)
+        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+            Integer(bounds=(values[0], values[1])).decode(
+                Integer(values[2]).encode()
+            )
+        repr(err.exception)
 
     @given(data_strategy())
     def test_call(self, d):
@@ -1528,8 +1544,9 @@ class TestBitString(CommonMixin, TestCase):
             self.assertSequenceEqual(tail, junk)
             self.assertEqual(obj.bit_len, bit_len_expected)
             self.assertSequenceEqual(bytes(obj), payload_expected)
-            self.assertTrue(obj.bered)
+            self.assertTrue(obj.ber_encoded)
             self.assertEqual(obj.lenindef, lenindef_expected)
+            self.assertTrue(obj.bered)
             self.assertEqual(len(encoded), obj.tlvlen)
 
     @given(
@@ -1659,8 +1676,9 @@ class TestBitString(CommonMixin, TestCase):
         )
         self.assertSequenceEqual(tail, b"")
         self.assertEqual(obj, vector)
-        self.assertTrue(obj.bered)
+        self.assertTrue(obj.ber_encoded)
         self.assertTrue(obj.lenindef)
+        self.assertTrue(obj.bered)
 
 
 @composite
@@ -1762,10 +1780,20 @@ class TestOctetString(CommonMixin, TestCase):
         with self.assertRaises(BoundsError) as err:
             OctetString(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
+        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+            OctetString(bounds=(bound_min, bound_max)).decode(
+                OctetString(value).encode()
+            )
+        repr(err.exception)
         value = d.draw(binary(min_size=bound_max + 1))
         with self.assertRaises(BoundsError) as err:
             OctetString(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
+        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+            OctetString(bounds=(bound_min, bound_max)).decode(
+                OctetString(value).encode()
+            )
+        repr(err.exception)
 
     @given(data_strategy())
     def test_call(self, d):
@@ -2027,8 +2055,9 @@ class TestOctetString(CommonMixin, TestCase):
             )
             self.assertSequenceEqual(tail, junk)
             self.assertSequenceEqual(bytes(obj), payload_expected)
-            self.assertTrue(obj.bered)
+            self.assertTrue(obj.ber_encoded)
             self.assertEqual(obj.lenindef, lenindef_expected)
+            self.assertTrue(obj.bered)
             self.assertEqual(len(encoded), obj.tlvlen)
 
     @given(
@@ -2978,10 +3007,20 @@ class StringMixin(object):
         with self.assertRaises(BoundsError) as err:
             self.base_klass(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
+        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+            self.base_klass(bounds=(bound_min, bound_max)).decode(
+                self.base_klass(value).encode()
+            )
+        repr(err.exception)
         value = d.draw(text(alphabet=self.text_alphabet(), min_size=bound_max + 1))
         with self.assertRaises(BoundsError) as err:
             self.base_klass(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
+        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+            self.base_klass(bounds=(bound_min, bound_max)).decode(
+                self.base_klass(value).encode()
+            )
+        repr(err.exception)
 
     @given(data_strategy())
     def test_call(self, d):
@@ -3292,8 +3331,9 @@ class TestVisibleString(
         obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
         self.assertSequenceEqual(tail, b"")
         self.assertEqual(str(obj), "Jones")
-        self.assertFalse(obj.bered)
+        self.assertFalse(obj.ber_encoded)
         self.assertFalse(obj.lenindef)
+        self.assertFalse(obj.bered)
 
         obj, tail = VisibleString().decode(
             hexdec("3A0904034A6F6E04026573"),
@@ -3301,8 +3341,9 @@ class TestVisibleString(
         )
         self.assertSequenceEqual(tail, b"")
         self.assertEqual(str(obj), "Jones")
-        self.assertTrue(obj.bered)
+        self.assertTrue(obj.ber_encoded)
         self.assertFalse(obj.lenindef)
+        self.assertTrue(obj.bered)
 
         obj, tail = VisibleString().decode(
             hexdec("3A8004034A6F6E040265730000"),
@@ -3310,8 +3351,9 @@ class TestVisibleString(
         )
         self.assertSequenceEqual(tail, b"")
         self.assertEqual(str(obj), "Jones")
-        self.assertTrue(obj.bered)
+        self.assertTrue(obj.ber_encoded)
         self.assertTrue(obj.lenindef)
+        self.assertTrue(obj.bered)
 
 
 class TestGeneralString(
@@ -3979,6 +4021,9 @@ class TestAny(CommonMixin, TestCase):
         self.assertSequenceEqual(tail, junk)
         self.assertEqual(obj.offset, offset)
         self.assertEqual(obj.tlvlen, len(encoded))
+        self.assertTrue(obj.lenindef)
+        self.assertFalse(obj.ber_encoded)
+        self.assertTrue(obj.bered)
         with self.assertRaises(NotEnoughData) as err:
             Any().decode(
                 encoded[:-1],
@@ -4719,6 +4764,8 @@ class SeqMixing(object):
         seq_encoded = seq.encode()
         seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
         self.assertFalse(seq_decoded.lenindef)
+        self.assertFalse(seq_decoded.ber_encoded)
+        self.assertFalse(seq_decoded.bered)
 
         t, _, lv = tag_strip(seq_encoded)
         _, _, v = len_decode(lv)
@@ -4728,6 +4775,7 @@ class SeqMixing(object):
             ctx={"bered": True},
         )
         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):
@@ -4810,7 +4858,7 @@ class SeqMixing(object):
         self.assertSequenceEqual(seq.encode(), empty_seq)
 
     @given(data_strategy())
-    def test_encoded_default_accepted(self, d):
+    def test_encoded_default_not_accepted(self, d):
         _schema = list(d.draw(dictionaries(
             text_letters(),
             integers(),
@@ -4838,10 +4886,15 @@ class SeqMixing(object):
                 for (n, v), t in zip(_schema, tags)
             ]
         seq_with_default = SeqWithDefault()
-        seq_decoded, _ = seq_with_default.decode(seq_encoded)
-        for name, value in _schema:
-            self.assertEqual(seq_decoded[name], seq_with_default[name])
-            self.assertEqual(seq_decoded[name], value)
+        with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+            seq_with_default.decode(seq_encoded)
+        for ctx in ({"bered": True}, {"allow_default_values": True}):
+            seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
+            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)
 
     @given(data_strategy())
     def test_missing_from_spec(self, d):
@@ -4867,6 +4920,31 @@ class SeqMixing(object):
         with self.assertRaises(TagMismatch):
             seq_missing.decode(seq_encoded)
 
+    @given(data_strategy())
+    def test_bered(self, d):
+        class Seq(self.base_klass):
+            schema = (("underlying", Boolean()),)
+        encoded = Boolean.tag_default + len_encode(1) + b"\x01"
+        encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
+        decoded, _ = Seq().decode(encoded, ctx={"bered": True})
+        self.assertFalse(decoded.ber_encoded)
+        self.assertFalse(decoded.lenindef)
+        self.assertTrue(decoded.bered)
+
+        class Seq(self.base_klass):
+            schema = (("underlying", OctetString()),)
+        encoded = (
+            tag_encode(form=TagFormConstructed, num=4) +
+            LENINDEF +
+            OctetString(b"whatever").encode() +
+            EOC
+        )
+        encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
+        decoded, _ = Seq().decode(encoded, ctx={"bered": True})
+        self.assertFalse(decoded.ber_encoded)
+        self.assertFalse(decoded.lenindef)
+        self.assertTrue(decoded.bered)
+
 
 class TestSequence(SeqMixing, CommonMixin, TestCase):
     base_klass = Sequence
@@ -4937,6 +5015,36 @@ class TestSet(SeqMixing, CommonMixin, TestCase):
             b"".join(sorted([seq[name].encode() for name, _ in Seq.schema])),
         )
 
+    @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
+    @given(data_strategy())
+    def test_unsorted(self, d):
+        tags = [
+            tag_encode(tag) for tag in
+            d.draw(sets(integers(min_value=1), min_size=2, max_size=5))
+        ]
+        tags = d.draw(permutations(tags))
+        assume(tags != sorted(tags))
+        encoded = b"".join(OctetString(t, impl=t).encode() for t in tags)
+        seq_encoded = b"".join((
+            Set.tag_default,
+            len_encode(len(encoded)),
+            encoded,
+        ))
+
+        class Seq(Set):
+            schema = [(str(i), OctetString(impl=t)) for i, t in enumerate(tags)]
+        seq = Seq()
+        with assertRaisesRegex(self, DecodeError, "unordered SET"):
+            seq.decode(seq_encoded)
+        for ctx in ({"bered": True}, {"allow_unordered_set": True}):
+            seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
+            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],
+            )
+
 
 @composite
 def seqof_values_strategy(draw, schema=None, do_expl=False):
@@ -5080,17 +5188,27 @@ class SeqOfMixing(object):
             schema = Boolean()
         bound_min = d.draw(integers(min_value=1, max_value=1 << 7))
         bound_max = d.draw(integers(min_value=bound_min, max_value=1 << 7))
-        value = [Boolean()] * d.draw(integers(max_value=bound_min - 1))
+        value = [Boolean(False)] * d.draw(integers(max_value=bound_min - 1))
         with self.assertRaises(BoundsError) as err:
             SeqOf(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
-        value = [Boolean()] * d.draw(integers(
+        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+            SeqOf(bounds=(bound_min, bound_max)).decode(
+                SeqOf(value).encode()
+            )
+        repr(err.exception)
+        value = [Boolean(True)] * d.draw(integers(
             min_value=bound_max + 1,
             max_value=bound_max + 10,
         ))
         with self.assertRaises(BoundsError) as err:
             SeqOf(value=value, bounds=(bound_min, bound_max))
         repr(err.exception)
+        with assertRaisesRegex(self, DecodeError, "bounds") as err:
+            SeqOf(bounds=(bound_min, bound_max)).decode(
+                SeqOf(value).encode()
+            )
+        repr(err.exception)
 
     @given(integers(min_value=1, max_value=10))
     def test_out_of_bounds(self, bound_max):
@@ -5338,6 +5456,7 @@ class SeqOfMixing(object):
             ctx={"bered": True},
         )
         self.assertTrue(obj_decoded_lenindef.lenindef)
+        self.assertTrue(obj_decoded_lenindef.bered)
         repr(obj_decoded_lenindef)
         pprint(obj_decoded_lenindef)
         self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
@@ -5346,6 +5465,33 @@ class SeqOfMixing(object):
         with self.assertRaises(DecodeError):
             obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
 
+    @given(data_strategy())
+    def test_bered(self, d):
+        class SeqOf(self.base_klass):
+            schema = Boolean()
+        encoded = Boolean(False).encode()
+        encoded += Boolean.tag_default + len_encode(1) + b"\x01"
+        encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
+        decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
+        self.assertFalse(decoded.ber_encoded)
+        self.assertFalse(decoded.lenindef)
+        self.assertTrue(decoded.bered)
+
+        class SeqOf(self.base_klass):
+            schema = OctetString()
+        encoded = OctetString(b"whatever").encode()
+        encoded += (
+            tag_encode(form=TagFormConstructed, num=4) +
+            LENINDEF +
+            OctetString(b"whatever").encode() +
+            EOC
+        )
+        encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
+        decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
+        self.assertFalse(decoded.ber_encoded)
+        self.assertFalse(decoded.lenindef)
+        self.assertTrue(decoded.bered)
+
 
 class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
     class SeqOf(SequenceOf):
@@ -5383,6 +5529,38 @@ class TestSetOf(SeqOfMixing, CommonMixin, TestCase):
             b"".join(sorted([v.encode() for v in values])),
         )
 
+    @settings(max_examples=LONG_TEST_MAX_EXAMPLES)
+    @given(data_strategy())
+    def test_unsorted(self, d):
+        values = [OctetString(v).encode() for v in d.draw(sets(
+            binary(min_size=1, max_size=5),
+            min_size=2,
+            max_size=5,
+        ))]
+        values = d.draw(permutations(values))
+        assume(values != sorted(values))
+        encoded = b"".join(values)
+        seq_encoded = b"".join((
+            SetOf.tag_default,
+            len_encode(len(encoded)),
+            encoded,
+        ))
+
+        class Seq(SetOf):
+            schema = OctetString()
+        seq = Seq()
+        with assertRaisesRegex(self, DecodeError, "unordered SET OF"):
+            seq.decode(seq_encoded)
+
+        for ctx in ({"bered": True}, {"allow_unordered_set": True}):
+            seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
+            self.assertTrue(seq_decoded.ber_encoded)
+            self.assertTrue(seq_decoded.bered)
+            self.assertSequenceEqual(
+                [obj.encode() for obj in seq_decoded],
+                values,
+            )
+
 
 class TestGoMarshalVectors(TestCase):
     def runTest(self):
@@ -5831,18 +6009,23 @@ class TestStrictDefaultExistence(TestCase):
             ("int%d" % i, Integer(expl=tag_ctxc(i + 1)))
             for i in range(count)
         ]
-
-        class Seq(Sequence):
-            schema = _schema
-        seq = Seq()
-        for i in range(count):
-            seq["int%d" % i] = Integer(123)
-        raw = seq.encode()
-        chosen = "int%d" % chosen
-        seq.specs[chosen] = seq.specs[chosen](default=123)
-        seq.decode(raw)
-        with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
-            seq.decode(raw, ctx={"strict_default_existence": True})
+        for klass in (Sequence, Set):
+            class Seq(klass):
+                schema = _schema
+            seq = Seq()
+            for i in range(count):
+                seq["int%d" % i] = Integer(123)
+            raw = seq.encode()
+            chosen_choice = "int%d" % chosen
+            seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
+            with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+                seq.decode(raw)
+            decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
+            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)
 
 
 class TestX690PrefixedType(TestCase):
@@ -5882,3 +6065,13 @@ class TestX690PrefixedType(TestCase):
             VisibleString("Jones", impl=tag_ctxp(2)).encode(),
             hexdec("82054A6F6E6573"),
         )
+
+
+class TestExplOOB(TestCase):
+    def runTest(self):
+        expl = tag_ctxc(123)
+        raw = Integer(123).encode() + Integer(234).encode()
+        raw = b"".join((expl, len_encode(len(raw)), raw))
+        with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"):
+            Integer(expl=expl).decode(raw)
+        Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})