]> Cypherpunks.ru repositories - pyderasn.git/commitdiff
BER explicit tag support
authorSergey Matveev <stargrave@stargrave.org>
Sat, 19 May 2018 16:27:07 +0000 (19:27 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sat, 19 May 2018 19:32:10 +0000 (22:32 +0300)
pyderasn.py
tests/test_pyderasn.py

index 6e772e09b5870c743b5c9228d3027a8d1cef35bf..3cbe67ddd1fbc7386f1df1556f700a54a360c242 100755 (executable)
@@ -850,6 +850,7 @@ class Obj(object):
         "llen",
         "vlen",
         "bered",
+        "expl_bered",
     )
 
     def __init__(
@@ -872,6 +873,7 @@ class Obj(object):
         self.offset, self.llen, self.vlen = _decoded
         self.default = None
         self.bered = False
+        self.expl_bered = False
 
     @property
     def ready(self):  # pragma: no cover
@@ -982,6 +984,35 @@ class Obj(object):
                 )
             try:
                 l, llen, v = len_decode(lv)
+            except LenIndefiniteForm as err:
+                if not ctx.get("bered", False):
+                    raise err.__class__(
+                        msg=err.msg,
+                        klass=self.__class__,
+                        decode_path=decode_path,
+                        offset=offset,
+                    )
+                llen, v = 1, lv[1:]
+                offset += tlen + llen
+                result = self._decode(
+                    v,
+                    offset=offset,
+                    decode_path=decode_path,
+                    ctx=ctx,
+                    tag_only=tag_only,
+                )
+                if tag_only:
+                    return
+                obj, tail = result
+                eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
+                if eoc_expected.tobytes() != EOC:
+                    raise DecodeError(
+                        msg="no EOC",
+                        decode_path=decode_path,
+                        offset=offset,
+                    )
+                obj.vlen += EOC_LEN
+                obj.expl_bered = True
             except DecodeError as err:
                 raise err.__class__(
                     msg=err.msg,
@@ -989,23 +1020,24 @@ class Obj(object):
                     decode_path=decode_path,
                     offset=offset,
                 )
-            if l > len(v):
-                raise NotEnoughData(
-                    "encoded length is longer than data",
-                    klass=self.__class__,
+            else:
+                if l > len(v):
+                    raise NotEnoughData(
+                        "encoded length is longer than data",
+                        klass=self.__class__,
+                        decode_path=decode_path,
+                        offset=offset,
+                    )
+                result = self._decode(
+                    v,
+                    offset=offset + tlen + llen,
                     decode_path=decode_path,
-                    offset=offset,
+                    ctx=ctx,
+                    tag_only=tag_only,
                 )
-            result = self._decode(
-                v,
-                offset=offset + tlen + llen,
-                decode_path=decode_path,
-                ctx=ctx,
-                tag_only=tag_only,
-            )
-            if tag_only:
-                return
-            obj, tail = result
+                if tag_only:
+                    return
+                obj, tail = result
         return obj, (tail if leavemm else tail.tobytes())
 
     @property
@@ -1022,6 +1054,8 @@ class Obj(object):
 
     @property
     def expl_llen(self):
+        if self.expl_bered:
+            return 1
         return len(len_encode(self.tlvlen))
 
     @property
index 15f54f90d43dd611b8239c5aa43e4490daf5554d..faa85699fd2d628058d3c9cf5d2ce83d8fbcc218 100644 (file)
@@ -64,6 +64,7 @@ from pyderasn import DecodeError
 from pyderasn import DecodePathDefBy
 from pyderasn import Enumerated
 from pyderasn import EOC
+from pyderasn import EOC_LEN
 from pyderasn import GeneralizedTime
 from pyderasn import GeneralString
 from pyderasn import GraphicString
@@ -607,6 +608,35 @@ class TestBoolean(CommonMixin, TestCase):
         self.assertTrue(bool(obj))
         self.assertTrue(obj.bered)
 
+    @given(
+        integers(min_value=1).map(tag_ctxc),
+        lists(
+            booleans(),
+            min_size=1,
+            max_size=5,
+        ),
+    )
+    def test_ber_expl(self, expl, values):
+        encoded = b""
+        for value in values:
+            encoded += (
+                expl +
+                b"\x80" +
+                Boolean(value).encode() +
+                EOC
+            )
+        encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded
+
+        class SeqOf(SequenceOf):
+            schema = Boolean(expl=expl)
+        seqof, tail = SeqOf().decode(encoded, ctx={"bered": True})
+        self.assertSequenceEqual(tail, b"")
+        self.assertSequenceEqual([bool(v) for v in seqof], values)
+        self.assertSetEqual(
+            set((v.tlvlen, v.expl_tlvlen, v.expl_tlen, v.expl_llen) for v in seqof),
+            set(((3 + EOC_LEN, len(expl) + 1 + 3 + EOC_LEN, len(expl), 1),)),
+        )
+
 
 @composite
 def integer_values_strategy(draw, do_expl=False):