]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - pyderasn.py
Unify quotes
[pyderasn.git] / pyderasn.py
index e69b19056ce010fa0ea09e4a111fd68964c34c95..3b5c4d824a47eda126121f843281c0050b2eed6a 100755 (executable)
@@ -269,11 +269,11 @@ for AlgorithmIdentifier of X.509's
 ``tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm``::
 
         (
-            (('parameters',), {
+            (("parameters",), {
                 id_ecPublicKey: ECParameters(),
                 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
             }),
-            (('..', 'subjectPublicKey'), {
+            (("..", "subjectPublicKey"), {
                 id_rsaEncryption: RSAPublicKey(),
                 id_GostR3410_2001: OctetString(),
             }),
@@ -289,7 +289,7 @@ Following types can be automatically decoded (DEFINED BY):
 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
 * :py:class:`pyderasn.OctetString`
 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
-  ``Any``/``OctetString``-s
+  ``Any``/``BitString``/``OctetString``-s
 
 When any of those fields is automatically decoded, then ``.defined``
 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
@@ -472,6 +472,8 @@ from collections import namedtuple
 from collections import OrderedDict
 from datetime import datetime
 from math import ceil
+from os import environ
+from string import digits
 
 from six import add_metaclass
 from six import binary_type
@@ -588,7 +590,7 @@ class DecodeError(Exception):
             c for c in (
                 "" if self.klass is None else self.klass.__name__,
                 (
-                    ("(%s)" % ".".join(self.decode_path))
+                    ("(%s)" % ".".join(str(dp) for dp in self.decode_path))
                     if len(self.decode_path) > 0 else ""
                 ),
                 ("(at %d)" % self.offset) if self.offset > 0 else "",
@@ -1011,7 +1013,7 @@ class Obj(object):
 class DecodePathDefBy(object):
     """DEFINED BY representation inside decode path
     """
-    __slots__ = ('defined_by',)
+    __slots__ = ("defined_by",)
 
     def __init__(self, defined_by):
         self.defined_by = defined_by
@@ -1130,9 +1132,9 @@ def pp_console_row(
             ):
                 cols.append(_colorize("%s:" % oids[value], "green", with_colours))
             else:
-                cols.append(_colorize("%s:" % value, "white", with_colours))
+                cols.append(_colorize("%s:" % value, "white", with_colours, ("reverse",)))
         else:
-            cols.append(_colorize("%s:" % ent, "yellow", with_colours))
+            cols.append(_colorize("%s:" % ent, "yellow", with_colours, ("reverse",)))
     if pp.expl is not None:
         klass, _, num = pp.expl
         col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
@@ -1146,7 +1148,7 @@ def pp_console_row(
     cols.append(_colorize(pp.asn1_type_name, "cyan", with_colours))
     if pp.value is not None:
         value = pp.value
-        cols.append(_colorize(value, "white", with_colours))
+        cols.append(_colorize(value, "white", with_colours, ("reverse",)))
         if (
                 oids is not None and
                 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
@@ -1764,12 +1766,12 @@ class BitString(Obj):
 
         class KeyUsage(BitString):
             schema = (
-                ('digitalSignature', 0),
-                ('nonRepudiation', 1),
-                ('keyEncipherment', 2),
+                ("digitalSignature", 0),
+                ("nonRepudiation", 1),
+                ("keyEncipherment", 2),
             )
 
-    >>> b = KeyUsage(('keyEncipherment', 'nonRepudiation'))
+    >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
     KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
     >>> b.named
     ['nonRepudiation', 'keyEncipherment']
@@ -2013,7 +2015,7 @@ class BitString(Obj):
                 decode_path=decode_path,
                 offset=offset,
             )
-        if byte2int(v[-1:]) & ((1 << pad_size) - 1) != 0:
+        if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
             raise DecodeError(
                 "invalid pad",
                 klass=self.__class__,
@@ -2254,6 +2256,13 @@ class OctetString(Obj):
                 optional=self.optional,
                 _decoded=(offset, llen, l),
             )
+        except DecodeError as err:
+            raise DecodeError(
+                msg=err.msg,
+                klass=self.__class__,
+                decode_path=decode_path,
+                offset=offset,
+            )
         except BoundsError as err:
             raise DecodeError(
                 msg=str(err),
@@ -2810,7 +2819,7 @@ class CommonString(OctetString):
 
     >>> PrintableString("привет мир")
     Traceback (most recent call last):
-    UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
+    pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
 
     >>> BMPString("ада", bounds=(2, 2))
     Traceback (most recent call last):
@@ -2866,14 +2875,17 @@ class CommonString(OctetString):
             value_raw = value
         else:
             raise InvalidValueType((self.__class__, text_type, binary_type))
-        value_raw = (
-            value_decoded.encode(self.encoding)
-            if value_raw is None else value_raw
-        )
-        value_decoded = (
-            value_raw.decode(self.encoding)
-            if value_decoded is None else value_decoded
-        )
+        try:
+            value_raw = (
+                value_decoded.encode(self.encoding)
+                if value_raw is None else value_raw
+            )
+            value_decoded = (
+                value_raw.decode(self.encoding)
+                if value_decoded is None else value_decoded
+            )
+        except (UnicodeEncodeError, UnicodeDecodeError) as err:
+            raise DecodeError(str(err))
         if not self._bound_min <= len(value_decoded) <= self._bound_max:
             raise BoundsError(
                 self._bound_min,
@@ -2935,6 +2947,13 @@ class NumericString(CommonString):
     tag_default = tag_encode(18)
     encoding = "ascii"
     asn1_type_name = "NumericString"
+    allowable_chars = set(digits.encode("ascii"))
+
+    def _value_sanitize(self, value):
+        value = super(NumericString, self)._value_sanitize(value)
+        if not set(value) <= self.allowable_chars:
+            raise DecodeError("non-numeric value")
+        return value
 
 
 class PrintableString(CommonString):
@@ -3209,8 +3228,8 @@ class Choice(Obj):
 
         class GeneralName(Choice):
             schema = (
-                ('rfc822Name', IA5String(impl=tag_ctxp(1))),
-                ('dNSName', IA5String(impl=tag_ctxp(2))),
+                ("rfc822Name", IA5String(impl=tag_ctxp(1))),
+                ("dNSName", IA5String(impl=tag_ctxp(2))),
             )
 
     >>> gn = GeneralName()
@@ -4499,11 +4518,6 @@ def main():  # pragma: no cover
         "--defines-by-path",
         help="Python path to decoder's defines_by_path",
     )
-    parser.add_argument(
-        "--with-colours",
-        action='store_true',
-        help="Enable coloured output",
-    )
     parser.add_argument(
         "DERFile",
         type=argparse.FileType("rb"),
@@ -4530,7 +4544,7 @@ def main():  # pragma: no cover
     print(pprinter(
         obj,
         oids=oids,
-        with_colours=True if args.with_colours else False,
+        with_colours=True if environ.get("NO_COLOR") is None else False,
     ))
     if tail != b"":
         print("\nTrailing data: %s" % hexenc(tail))