summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/news.rst4
-rwxr-xr-xpyderasn.py55
-rw-r--r--tests/test_pyderasn.py15
3 files changed, 74 insertions, 0 deletions
diff --git a/doc/news.rst b/doc/news.rst
index fe3a293..4baa462 100644
--- a/doc/news.rst
+++ b/doc/news.rst
@@ -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:
diff --git a/pyderasn.py b/pyderasn.py
index 2972db7..f4f38a2 100755
--- a/pyderasn.py
+++ b/pyderasn.py
@@ -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__ = ()
diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py
index 9fbb33e..aaac6cd 100644
--- a/tests/test_pyderasn.py
+++ b/tests/test_pyderasn.py
@@ -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,