]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - pyderasn.py
Optionally disallow BER in utility
[pyderasn.git] / pyderasn.py
index c8e29e3d767249c9de62be911540c9c3cf9e7992..ffc788ca6cca7a8529cfa1a3ca93abc57d414675 100755 (executable)
@@ -608,7 +608,7 @@ class NotEnoughData(DecodeError):
     pass
 
 
-class LenIndefiniteForm(DecodeError):
+class LenIndefForm(DecodeError):
     pass
 
 
@@ -803,6 +803,11 @@ def len_encode(l):
 
 
 def len_decode(data):
+    """Decode length
+
+    :returns: (decoded length, length's length, remaining data)
+    :raises LenIndefForm: if indefinite form encoding is met
+    """
     if len(data) == 0:
         raise NotEnoughData("no data at all")
     first_octet = byte2int(data)
@@ -812,7 +817,7 @@ def len_decode(data):
     if octets_num + 1 > len(data):
         raise NotEnoughData("encoded length is longer than data")
     if octets_num == 0:
-        raise LenIndefiniteForm()
+        raise LenIndefForm()
     if byte2int(data[1:]) == 0:
         raise DecodeError("leading zeros")
     l = 0
@@ -849,8 +854,8 @@ class Obj(object):
         "offset",
         "llen",
         "vlen",
-        "lenindef",
         "expl_lenindef",
+        "lenindef",
         "bered",
     )
 
@@ -873,8 +878,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.lenindef = False
         self.bered = False
 
     @property
@@ -986,7 +991,7 @@ class Obj(object):
                 )
             try:
                 l, llen, v = len_decode(lv)
-            except LenIndefiniteForm as err:
+            except LenIndefForm as err:
                 if not ctx.get("bered", False):
                     raise err.__class__(
                         msg=err.msg,
@@ -1118,6 +1123,9 @@ PP = namedtuple("PP", (
     "expl_tlen",
     "expl_llen",
     "expl_vlen",
+    "expl_lenindef",
+    "lenindef",
+    "bered",
 ))
 
 
@@ -1139,6 +1147,9 @@ def _pp(
         expl_tlen=None,
         expl_llen=None,
         expl_vlen=None,
+        expl_lenindef=False,
+        lenindef=False,
+        bered=False,
 ):
     return PP(
         asn1_type_name,
@@ -1158,6 +1169,9 @@ def _pp(
         expl_tlen,
         expl_llen,
         expl_vlen,
+        expl_lenindef,
+        lenindef,
+        bered,
     )
 
 
@@ -1183,7 +1197,17 @@ def pp_console_row(
         )
         cols.append(_colorize(col, "red", with_colours, ()))
         col = "[%d,%d,%4d]" % (pp.tlen, pp.llen, pp.vlen)
-        cols.append(_colorize(col, "green", with_colours, ()))
+        col = _colorize(col, "green", with_colours, ())
+        ber_deoffset = 0
+        if pp.expl_lenindef:
+            ber_deoffset += 2
+        if pp.lenindef:
+            ber_deoffset += 2
+        col += (
+            "  " if ber_deoffset == 0 else
+            _colorize(("-%d" % ber_deoffset), "red", with_colours)
+        )
+        cols.append(col)
     if len(pp.decode_path) > 0:
         cols.append(" ." * (len(pp.decode_path)))
         ent = pp.decode_path[-1]
@@ -1211,6 +1235,8 @@ def pp_console_row(
         cols.append(_colorize(col, "blue", with_colours))
     if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
         cols.append(_colorize(pp.obj_name, "magenta", with_colours))
+    if pp.bered:
+        cols.append(_colorize("BER", "red", with_colours))
     cols.append(_colorize(pp.asn1_type_name, "cyan", with_colours))
     if pp.value is not None:
         value = pp.value
@@ -1234,7 +1260,7 @@ def pp_console_row(
 
 
 def pp_console_blob(pp):
-    cols = [" " * len("XXXXXYY [X,X,XXXX]")]
+    cols = [" " * len("XXXXXYY [X,X,XXXX]YY")]
     if len(pp.decode_path) > 0:
         cols.append(" ." * (len(pp.decode_path) + 1))
     if isinstance(pp.blob, binary_type):
@@ -1489,6 +1515,8 @@ class Boolean(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
+            bered=self.bered,
         )
 
 
@@ -1811,6 +1839,7 @@ class Integer(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
         )
 
 
@@ -1826,6 +1855,8 @@ class BitString(Obj):
     >>> b.bit_len
     88
 
+    >>> BitString("'0A3B5F291CD'H")
+    BIT STRING 44 bits 0a3b5f291cd0
     >>> b = BitString("'010110000000'B")
     BIT STRING 12 bits 5800
     >>> b.bit_len
@@ -1914,21 +1945,25 @@ class BitString(Obj):
         if isinstance(value, (string_types, binary_type)):
             if (
                     isinstance(value, string_types) and
-                    value.startswith("'") and
-                    value.endswith("'B")
+                    value.startswith("'")
             ):
-                value = value[1:-2]
-                if not set(value) <= set(("0", "1")):
-                    raise ValueError("B's coding contains unacceptable chars")
-                return self._bits2octets(value)
+                if value.endswith("'B"):
+                    value = value[1:-2]
+                    if not set(value) <= set(("0", "1")):
+                        raise ValueError("B's coding contains unacceptable chars")
+                    return self._bits2octets(value)
+                elif value.endswith("'H"):
+                    value = value[1:-2]
+                    return (
+                        len(value) * 4,
+                        hexdec(value + ("" if len(value) % 2 == 0 else "0")),
+                    )
+                else:
+                    raise InvalidValueType((self.__class__, string_types, binary_type))
             elif isinstance(value, binary_type):
                 return (len(value) * 8, value)
             else:
-                raise InvalidValueType((
-                    self.__class__,
-                    string_types,
-                    binary_type,
-                ))
+                raise InvalidValueType((self.__class__, string_types, binary_type))
         if isinstance(value, tuple):
             if (
                     len(value) == 2 and
@@ -2126,7 +2161,7 @@ class BitString(Obj):
             lenindef = False
             try:
                 l, llen, v = len_decode(lv)
-            except LenIndefiniteForm:
+            except LenIndefForm:
                 llen, l, v = 1, 0, lv[1:]
                 lenindef = True
             except DecodeError as err:
@@ -2252,6 +2287,9 @@ class BitString(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
+            lenindef=self.lenindef,
+            bered=self.bered,
         )
         defined_by, defined = self.defined or (None, None)
         if defined_by is not None:
@@ -2478,7 +2516,7 @@ class OctetString(Obj):
             lenindef = False
             try:
                 l, llen, v = len_decode(lv)
-            except LenIndefiniteForm:
+            except LenIndefForm:
                 llen, l, v = 1, 0, lv[1:]
                 lenindef = True
             except DecodeError as err:
@@ -2598,6 +2636,9 @@ class OctetString(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
+            lenindef=self.lenindef,
+            bered=self.bered,
         )
         defined_by, defined = self.defined or (None, None)
         if defined_by is not None:
@@ -2734,6 +2775,7 @@ class Null(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
         )
 
 
@@ -3022,6 +3064,7 @@ class ObjectIdentifier(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
         )
 
 
@@ -3240,6 +3283,11 @@ class CommonString(OctetString):
             tlen=self.tlen,
             llen=self.llen,
             vlen=self.vlen,
+            expl_offset=self.expl_offset if self.expled else None,
+            expl_tlen=self.expl_tlen if self.expled else None,
+            expl_llen=self.expl_llen if self.expled else None,
+            expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
         )
 
 
@@ -3428,6 +3476,11 @@ class UTCTime(CommonString):
             tlen=self.tlen,
             llen=self.llen,
             vlen=self.vlen,
+            expl_offset=self.expl_offset if self.expled else None,
+            expl_tlen=self.expl_tlen if self.expled else None,
+            expl_llen=self.expl_llen if self.expled else None,
+            expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
         )
 
 
@@ -3759,6 +3812,7 @@ class Choice(Obj):
             tlen=self.tlen,
             llen=self.llen,
             vlen=self.vlen,
+            expl_lenindef=self.expl_lenindef,
         )
         if self.ready:
             yield self.value.pps(decode_path=decode_path + (self.choice,))
@@ -3899,7 +3953,7 @@ class Any(Obj):
             )
         try:
             l, llen, v = len_decode(lv)
-        except LenIndefiniteForm as err:
+        except LenIndefForm as err:
             if not ctx.get("bered", False):
                 raise err.__class__(
                     msg=err.msg,
@@ -3979,6 +4033,8 @@ class Any(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
+            lenindef=self.lenindef,
         )
         defined_by, defined = self.defined or (None, None)
         if defined_by is not None:
@@ -4282,7 +4338,7 @@ class Sequence(Obj):
         lenindef = False
         try:
             l, llen, v = len_decode(lv)
-        except LenIndefiniteForm as err:
+        except LenIndefForm as err:
             if not ctx.get("bered", False):
                 raise err.__class__(
                     msg=err.msg,
@@ -4313,8 +4369,8 @@ class Sequence(Obj):
         values = {}
         for name, spec in self.specs.items():
             if spec.optional and (
-                (lenindef and v[:EOC_LEN].tobytes() == EOC) or
-                len(v) == 0
+                    (lenindef and v[:EOC_LEN].tobytes() == EOC) or
+                    len(v) == 0
             ):
                 continue
             sub_decode_path = decode_path + (name,)
@@ -4463,6 +4519,8 @@ class Sequence(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
+            lenindef=self.lenindef,
         )
         for name in self.specs:
             value = self._value.get(name)
@@ -4507,7 +4565,7 @@ class Set(Sequence):
         lenindef = False
         try:
             l, llen, v = len_decode(lv)
-        except LenIndefiniteForm as err:
+        except LenIndefForm as err:
             if not ctx.get("bered", False):
                 raise err.__class__(
                     msg=err.msg,
@@ -4794,7 +4852,7 @@ class SequenceOf(Obj):
         lenindef = False
         try:
             l, llen, v = len_decode(lv)
-        except LenIndefiniteForm as err:
+        except LenIndefForm as err:
             if not ctx.get("bered", False):
                 raise err.__class__(
                     msg=err.msg,
@@ -4875,6 +4933,8 @@ class SequenceOf(Obj):
             expl_tlen=self.expl_tlen if self.expled else None,
             expl_llen=self.expl_llen if self.expled else None,
             expl_vlen=self.expl_vlen if self.expled else None,
+            expl_lenindef=self.expl_lenindef,
+            lenindef=self.lenindef,
         )
         for i, value in enumerate(self._value):
             yield value.pps(decode_path=decode_path + (str(i),))
@@ -4977,6 +5037,11 @@ def main():  # pragma: no cover
         "--defines-by-path",
         help="Python path to decoder's defines_by_path",
     )
+    parser.add_argument(
+        "--nobered",
+        action='store_true',
+        help="Disallow BER encoding",
+    )
     parser.add_argument(
         "DERFile",
         type=argparse.FileType("rb"),
@@ -4993,7 +5058,7 @@ def main():  # pragma: no cover
         pprinter = partial(pprint, big_blobs=True)
     else:
         schema, pprinter = generic_decoder()
-    ctx = {"bered": True}
+    ctx = {"bered": not args.nobered}
     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)