From d8f05bb5f06096c6e061c82d40aeb9f43bbb1a21 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Sat, 19 May 2018 19:27:07 +0300 Subject: [PATCH] BER explicit tag support --- pyderasn.py | 64 ++++++++++++++++++++++++++++++++---------- tests/test_pyderasn.py | 30 ++++++++++++++++++++ 2 files changed, 79 insertions(+), 15 deletions(-) diff --git a/pyderasn.py b/pyderasn.py index 6e772e0..3cbe67d 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -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 diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index 15f54f9..faa8569 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -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): -- 2.44.0