From: Sergey Matveev Date: Thu, 23 Jan 2020 15:59:49 +0000 (+0300) Subject: PrintableString can optionally allow * and & X-Git-Tag: 5.6^0 X-Git-Url: http://www.git.cypherpunks.ru/?p=pyderasn.git;a=commitdiff_plain;h=de2299f02a411f3b805058afa84118cf361c99c8 PrintableString can optionally allow * and & --- 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,