]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - pyderasn.py
pylint
[pyderasn.git] / pyderasn.py
index 6e772e09b5870c743b5c9228d3027a8d1cef35bf..099e8a436c21bf18412651ab6563958856feed16 100755 (executable)
@@ -849,6 +849,8 @@ class Obj(object):
         "offset",
         "llen",
         "vlen",
+        "lenindef",
+        "expl_lenindef",
         "bered",
     )
 
@@ -871,6 +873,8 @@ class Obj(object):
         self.optional = optional
         self.offset, self.llen, self.vlen = _decoded
         self.default = None
+        self.lenindef = False
+        self.expl_lenindef = False
         self.bered = False
 
     @property
@@ -982,6 +986,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_lenindef = True
             except DecodeError as err:
                 raise err.__class__(
                     msg=err.msg,
@@ -989,23 +1022,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 +1056,8 @@ class Obj(object):
 
     @property
     def expl_llen(self):
+        if self.expl_lenindef:
+            return 1
         return len(len_encode(self.tlvlen))
 
     @property
@@ -2087,12 +2123,12 @@ class BitString(Obj):
                 )
             if tag_only:
                 return
-            eoc_expected = False
+            lenindef = False
             try:
                 l, llen, v = len_decode(lv)
             except LenIndefiniteForm:
                 llen, l, v = 1, 0, lv[1:]
-                eoc_expected = True
+                lenindef = True
             except DecodeError as err:
                 raise err.__class__(
                     msg=err.msg,
@@ -2107,7 +2143,7 @@ class BitString(Obj):
                     decode_path=decode_path,
                     offset=offset,
                 )
-            if not eoc_expected and l == 0:
+            if not lenindef and l == 0:
                 raise NotEnoughData(
                     "zero length",
                     klass=self.__class__,
@@ -2118,7 +2154,7 @@ class BitString(Obj):
             sub_offset = offset + tlen + llen
             vlen = 0
             while True:
-                if eoc_expected:
+                if lenindef:
                     if v[:EOC_LEN].tobytes() == EOC:
                         break
                 else:
@@ -2176,10 +2212,11 @@ class BitString(Obj):
                 default=self.default,
                 optional=self.optional,
                 _specs=self.specs,
-                _decoded=(offset, llen, vlen + (EOC_LEN if eoc_expected else 0)),
+                _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
             )
+            obj.lenindef = lenindef
             obj.bered = True
-            return obj, v[EOC_LEN if eoc_expected else 0:]
+            return obj, (v[EOC_LEN:] if lenindef else v)
         raise TagMismatch(
             klass=self.__class__,
             decode_path=decode_path,
@@ -2438,12 +2475,12 @@ class OctetString(Obj):
                 )
             if tag_only:
                 return
-            eoc_expected = False
+            lenindef = False
             try:
                 l, llen, v = len_decode(lv)
             except LenIndefiniteForm:
                 llen, l, v = 1, 0, lv[1:]
-                eoc_expected = True
+                lenindef = True
             except DecodeError as err:
                 raise err.__class__(
                     msg=err.msg,
@@ -2458,7 +2495,7 @@ class OctetString(Obj):
                     decode_path=decode_path,
                     offset=offset,
                 )
-            if not eoc_expected and l == 0:
+            if not lenindef and l == 0:
                 raise NotEnoughData(
                     "zero length",
                     klass=self.__class__,
@@ -2469,7 +2506,7 @@ class OctetString(Obj):
             sub_offset = offset + tlen + llen
             vlen = 0
             while True:
-                if eoc_expected:
+                if lenindef:
                     if v[:EOC_LEN].tobytes() == EOC:
                         break
                 else:
@@ -2514,7 +2551,7 @@ class OctetString(Obj):
                     expl=self._expl,
                     default=self.default,
                     optional=self.optional,
-                    _decoded=(offset, llen, vlen + (EOC_LEN if eoc_expected else 0)),
+                    _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
                 )
             except DecodeError as err:
                 raise DecodeError(
@@ -2530,8 +2567,9 @@ class OctetString(Obj):
                     decode_path=decode_path,
                     offset=offset,
                 )
+            obj.lenindef = lenindef
             obj.bered = True
-            return obj, v[EOC_LEN if eoc_expected else 0:]
+            return obj, (v[EOC_LEN:] if lenindef else v)
         raise TagMismatch(
             klass=self.__class__,
             decode_path=decode_path,
@@ -3852,7 +3890,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.lenindef = 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,
@@ -4199,8 +4279,19 @@ class Sequence(Obj):
             )
         if tag_only:
             return
+        lenindef = 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:]
+            lenindef = True
         except DecodeError as err:
             raise err.__class__(
                 msg=err.msg,
@@ -4215,11 +4306,16 @@ class Sequence(Obj):
                 decode_path=decode_path,
                 offset=offset,
             )
-        v, tail = v[:l], v[l:]
+        if not lenindef:
+            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 (
+                    (lenindef and v[:EOC_LEN].tobytes() == EOC) or
+                    len(v) == 0
+            ):
                 continue
             sub_decode_path = decode_path + (name,)
             try:
@@ -4282,7 +4378,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):
@@ -4309,7 +4407,17 @@ class Sequence(Obj):
                             abs_decode_path(sub_decode_path[:-1], rel_path),
                             (value, defined),
                         ))
-        if len(v) > 0:
+        if lenindef:
+            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__,
@@ -4322,9 +4430,10 @@ class Sequence(Obj):
             expl=self._expl,
             default=self.default,
             optional=self.optional,
-            _decoded=(offset, llen, l),
+            _decoded=(offset, llen, vlen),
         )
         obj._value = values
+        obj.lenindef = lenindef
         return obj, tail
 
     def __repr__(self):
@@ -4395,8 +4504,19 @@ class Set(Sequence):
             )
         if tag_only:
             return
+        lenindef = 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:]
+            lenindef = True
         except DecodeError as err:
             raise err.__class__(
                 msg=err.msg,
@@ -4410,11 +4530,15 @@ class Set(Sequence):
                 klass=self.__class__,
                 offset=offset,
             )
-        v, tail = v[:l], v[l:]
+        if not lenindef:
+            v, tail = v[:l], v[l:]
+        vlen = 0
         sub_offset = offset + tlen + llen
         values = {}
         specs_items = self.specs.items
         while len(v) > 0:
+            if lenindef and v[:EOC_LEN].tobytes() == EOC:
+                break
             for name, spec in specs_items():
                 sub_decode_path = decode_path + (name,)
                 try:
@@ -4442,9 +4566,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
@@ -4455,10 +4579,18 @@ class Set(Sequence):
             expl=self._expl,
             default=self.default,
             optional=self.optional,
-            _decoded=(offset, llen, l),
+            _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
         )
         obj._value = values
-        return obj, tail
+        if not obj.ready:
+            raise DecodeError(
+                msg="not all values are ready",
+                klass=self.__class__,
+                decode_path=decode_path,
+                offset=offset,
+            )
+        obj.lenindef = lenindef
+        return obj, (v[EOC_LEN:] if lenindef else tail)
 
 
 class SequenceOf(Obj):
@@ -4659,8 +4791,19 @@ class SequenceOf(Obj):
             )
         if tag_only:
             return
+        lenindef = 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:]
+            lenindef = True
         except DecodeError as err:
             raise err.__class__(
                 msg=err.msg,
@@ -4675,11 +4818,15 @@ class SequenceOf(Obj):
                 decode_path=decode_path,
                 offset=offset,
             )
-        v, tail = v[:l], v[l:]
+        if not lenindef:
+            v, tail = v[:l], v[l:]
+        vlen = 0
         sub_offset = offset + tlen + llen
         _value = []
         spec = self.spec
         while len(v) > 0:
+            if lenindef and v[:EOC_LEN].tobytes() == EOC:
+                break
             value, v_tail = spec.decode(
                 v,
                 sub_offset,
@@ -4687,7 +4834,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__(
@@ -4698,9 +4847,10 @@ class SequenceOf(Obj):
             expl=self._expl,
             default=self.default,
             optional=self.optional,
-            _decoded=(offset, llen, l),
+            _decoded=(offset, llen, vlen),
         )
-        return obj, tail
+        obj.lenindef = lenindef
+        return obj, (v[EOC_LEN:] if lenindef else tail)
 
     def __repr__(self):
         return "%s[%s]" % (
@@ -4843,13 +4993,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,