From 3ef2a2faa140bac2bbf3b024e827a7db63b5e38d Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Sat, 19 May 2018 23:49:53 +0300 Subject: [PATCH] BER Any/Sequence/Set/SequenceOf support --- pyderasn.py | 147 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 127 insertions(+), 20 deletions(-) diff --git a/pyderasn.py b/pyderasn.py index 6be00cb..a048f4d 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -3886,7 +3886,49 @@ class Any(Obj): def _decode(self, tlv, offset, decode_path, ctx, tag_only): try: t, tlen, lv = tag_strip(tlv) + except DecodeError as err: + raise err.__class__( + msg=err.msg, + klass=self.__class__, + decode_path=decode_path, + offset=offset, + ) + 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, vlen, v = 1, 0, lv[1:] + sub_offset = offset + tlen + llen + chunk_i = 0 + while True: + if v[:EOC_LEN].tobytes() == EOC: + tlvlen = tlen + llen + vlen + EOC_LEN + obj = self.__class__( + value=tlv[:tlvlen].tobytes(), + expl=self._expl, + optional=self.optional, + _decoded=(offset, 0, tlvlen), + ) + obj.bered = True + obj.tag = t + return obj, v[EOC_LEN:] + else: + chunk, v = Any().decode( + v, + offset=sub_offset, + decode_path=decode_path + (str(chunk_i),), + leavemm=True, + ctx=ctx, + ) + vlen += chunk.tlvlen + sub_offset += chunk.tlvlen + chunk_i += 1 except DecodeError as err: raise err.__class__( msg=err.msg, @@ -4233,8 +4275,19 @@ class Sequence(Obj): ) if tag_only: return + eoc_expected = False 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, + ) + l, llen, v = 0, 1, lv[1:] + eoc_expected = True except DecodeError as err: raise err.__class__( msg=err.msg, @@ -4249,11 +4302,16 @@ class Sequence(Obj): decode_path=decode_path, offset=offset, ) - v, tail = v[:l], v[l:] + if not eoc_expected: + v, tail = v[:l], v[l:] + vlen = 0 sub_offset = offset + tlen + llen values = {} for name, spec in self.specs.items(): - if len(v) == 0 and spec.optional: + if spec.optional and ( + (eoc_expected and v[:EOC_LEN].tobytes() == EOC) or + len(v) == 0 + ): continue sub_decode_path = decode_path + (name,) try: @@ -4316,7 +4374,9 @@ class Sequence(Obj): ) value.defined = (defined_by, defined_value) - sub_offset += (value.expl_tlvlen if value.expled else value.tlvlen) + value_len = value.expl_tlvlen if value.expled else value.tlvlen + vlen += value_len + sub_offset += value_len v = v_tail if spec.default is not None and value == spec.default: if ctx.get("strict_default_existence", False): @@ -4343,7 +4403,17 @@ class Sequence(Obj): abs_decode_path(sub_decode_path[:-1], rel_path), (value, defined), )) - if len(v) > 0: + if eoc_expected: + if v[:EOC_LEN].tobytes() != EOC: + raise DecodeError( + "no EOC", + klass=self.__class__, + decode_path=decode_path, + offset=offset, + ) + tail = v[EOC_LEN:] + vlen += EOC_LEN + elif len(v) > 0: raise DecodeError( "remaining data", klass=self.__class__, @@ -4356,9 +4426,11 @@ class Sequence(Obj): expl=self._expl, default=self.default, optional=self.optional, - _decoded=(offset, llen, l), + _decoded=(offset, llen, vlen), ) obj._value = values + if eoc_expected: + obj.bered = True return obj, tail def __repr__(self): @@ -4429,8 +4501,19 @@ class Set(Sequence): ) if tag_only: return + eoc_expected = False 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, + ) + l, llen, v = 0, 1, lv[1:] + eoc_expected = True except DecodeError as err: raise err.__class__( msg=err.msg, @@ -4444,11 +4527,15 @@ class Set(Sequence): klass=self.__class__, offset=offset, ) - v, tail = v[:l], v[l:] + if not eoc_expected: + v, tail = v[:l], v[l:] + vlen = 0 sub_offset = offset + tlen + llen values = {} specs_items = self.specs.items while len(v) > 0: + if eoc_expected and v[:EOC_LEN].tobytes() == EOC: + break for name, spec in specs_items(): sub_decode_path = decode_path + (name,) try: @@ -4476,9 +4563,9 @@ class Set(Sequence): decode_path=sub_decode_path, ctx=ctx, ) - sub_offset += ( - value.expl_tlvlen if value.expled else value.tlvlen - ) + value_len = value.expl_tlvlen if value.expled else value.tlvlen + sub_offset += value_len + vlen += value_len v = v_tail if spec.default is None or value != spec.default: # pragma: no cover # SeqMixing.test_encoded_default_accepted covers that place @@ -4489,7 +4576,7 @@ class Set(Sequence): expl=self._expl, default=self.default, optional=self.optional, - _decoded=(offset, llen, l), + _decoded=(offset, llen, vlen + (EOC_LEN if eoc_expected else 0)), ) obj._value = values if not obj.ready: @@ -4499,6 +4586,9 @@ class Set(Sequence): decode_path=decode_path, offset=offset, ) + if eoc_expected: + obj.bered = True + tail = v[EOC_LEN:] return obj, tail @@ -4700,8 +4790,19 @@ class SequenceOf(Obj): ) if tag_only: return + eoc_expected = False 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, + ) + l, llen, v = 0, 1, lv[1:] + eoc_expected = True except DecodeError as err: raise err.__class__( msg=err.msg, @@ -4716,11 +4817,15 @@ class SequenceOf(Obj): decode_path=decode_path, offset=offset, ) - v, tail = v[:l], v[l:] + if not eoc_expected: + v, tail = v[:l], v[l:] + vlen = 0 sub_offset = offset + tlen + llen _value = [] spec = self.spec while len(v) > 0: + if eoc_expected and v[:EOC_LEN].tobytes() == EOC: + break value, v_tail = spec.decode( v, sub_offset, @@ -4728,7 +4833,9 @@ class SequenceOf(Obj): decode_path=decode_path + (str(len(_value)),), ctx=ctx, ) - sub_offset += (value.expl_tlvlen if value.expled else value.tlvlen) + value_len = value.expl_tlvlen if value.expled else value.tlvlen + sub_offset += value_len + vlen += value_len v = v_tail _value.append(value) obj = self.__class__( @@ -4739,8 +4846,11 @@ class SequenceOf(Obj): expl=self._expl, default=self.default, optional=self.optional, - _decoded=(offset, llen, l), + _decoded=(offset, llen, vlen), ) + if eoc_expected: + obj.bered = True + tail = v[EOC_LEN:] return obj, tail def __repr__(self): @@ -4884,13 +4994,10 @@ def main(): # pragma: no cover pprinter = partial(pprint, big_blobs=True) else: schema, pprinter = generic_decoder() - obj, tail = schema().decode( - der, - ctx=( - None if args.defines_by_path is None else - {"defines_by_path": obj_by_path(args.defines_by_path)} - ), - ) + ctx = {"bered": True} + if args.defines_by_path is not None: + ctx["defines_by_path"] = obj_by_path(args.defines_by_path) + obj, tail = schema().decode(der, ctx=ctx) print(pprinter( obj, oids=oids, -- 2.44.0