]> Cypherpunks.ru repositories - pyderasn.git/commitdiff
PrintableString can optionally allow * and & 5.6
authorSergey Matveev <stargrave@stargrave.org>
Thu, 23 Jan 2020 15:59:49 +0000 (18:59 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Thu, 23 Jan 2020 16:24:29 +0000 (19:24 +0300)
doc/news.rst
pyderasn.py
tests/test_pyderasn.py

index fe3a2938ddd6bfaf1a8d0749403969eea7820325..4baa4623c6af17e5349998961a2ce375d9f6eb3b 100644 (file)
@@ -8,6 +8,10 @@ News
 * Convenient ``.decod()`` method, that raises if tail is not empty
 * Control characters (like newlines) of text fields in pprinted output
   are escaped
+* Ability to allow asterisk and ampersand characters
+  (``allow_asterisk``, ``allow_ampersand`` kwargs) in
+  ``PrintableString``, that unfortunately could be met
+  in X.509 certificates
 
 .. _release5.5:
 
index 2972db70407fe7ce715f8e1cd47ddf687c360d6b..f4f38a2c7121329bbd4ba797a55b87a2cf09e56a 100755 (executable)
@@ -570,6 +570,7 @@ _____________
 PrintableString
 _______________
 .. autoclass:: pyderasn.PrintableString
+   :members: __init__
 
 UTCTime
 _______
@@ -3779,6 +3780,32 @@ class PrintableString(AllowableCharsMixin, CommonString):
     _allowable_chars = frozenset(
         (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
     )
+    _asterisk = frozenset("*".encode("ascii"))
+    _ampersand = frozenset("&".encode("ascii"))
+
+    def __init__(
+            self,
+            value=None,
+            bounds=None,
+            impl=None,
+            expl=None,
+            default=None,
+            optional=False,
+            _decoded=(0, 0, 0),
+            allow_asterisk=False,
+            allow_ampersand=False,
+    ):
+        """
+        :param allow_asterisk: allow asterisk character
+        :param allow_ampersand: allow ampersand character
+        """
+        if allow_asterisk:
+            self._allowable_chars |= self._asterisk
+        if allow_ampersand:
+            self._allowable_chars |= self._ampersand
+        super(PrintableString, self).__init__(
+            value, bounds, impl, expl, default, optional, _decoded,
+        )
 
     def _value_sanitize(self, value):
         value = super(PrintableString, self)._value_sanitize(value)
@@ -3786,6 +3813,34 @@ class PrintableString(AllowableCharsMixin, CommonString):
             raise DecodeError("non-printable value")
         return value
 
+    def copy(self):
+        obj = super(PrintableString, self).copy()
+        obj._allowable_chars = self._allowable_chars
+        return obj
+
+    def __call__(
+            self,
+            value=None,
+            bounds=None,
+            impl=None,
+            expl=None,
+            default=None,
+            optional=None,
+    ):
+        return self.__class__(
+            value=value,
+            bounds=(
+                (self._bound_min, self._bound_max)
+                if bounds is None else bounds
+            ),
+            impl=self.tag if impl is None else impl,
+            expl=self._expl if expl is None else expl,
+            default=self.default if default is None else default,
+            optional=self.optional if optional is None else optional,
+            allow_asterisk=self._asterisk <= self._allowable_chars,
+            allow_ampersand=self._ampersand <= self._allowable_chars,
+        )
+
 
 class TeletexString(CommonString):
     __slots__ = ()
index 9fbb33eb39f2d75231721cee73de95a32d66d717..aaac6cd56957f2bff73496750b953d7565d58697 100644 (file)
@@ -3506,6 +3506,21 @@ class TestPrintableString(
         self.assertEqual(err.exception.offset, offset)
         self.assertEqual(err.exception.decode_path, decode_path)
 
+    def test_allowable_invalid_chars(self):
+        for c, kwargs in (
+                ("*", {"allow_asterisk": True}),
+                ("&", {"allow_ampersand": True}),
+                ("&*", {"allow_asterisk": True, "allow_ampersand": True}),
+        ):
+            s = "hello invalid " + c
+            with assertRaisesRegex(self, DecodeError, "non-printable"):
+                self.base_klass(s)
+            self.base_klass(s, **kwargs)
+            klass = self.base_klass(**kwargs)
+            obj = klass(s)
+            obj = obj.copy()
+            obj(s)
+
 
 class TestTeletexString(
         UnicodeDecodeErrorMixin,