doc/news.rst | 2 ++ pyderasn.py | 24 ++++++++++++++++++------ tests/test_pyderasn.py | 23 +++++++++++++++++++++++ diff --git a/doc/news.rst b/doc/news.rst index a240d5f6312ffb5d55a65de63d6cf022cbfcaf4ca732e457b097fe390ad9c3b1..8fc3928f53029d33f9bae37589c2cd7ab6035b54c45213ff99aa14fdf14f168b 100644 --- a/doc/news.rst +++ b/doc/news.rst @@ -10,6 +10,8 @@ * Decoding process can be governed with optional :ref:`ctx ` keyword argument to ``decode()`` method * :ref:`defines_by_path ` option is now :ref:`decode context ` option, not a keyword argument +* Ability to do :ref:`strict validation ` + of defaulted values met in sequence, raising an exception .. _release1.6: diff --git a/pyderasn.py b/pyderasn.py index 4cf3446eb23186fea7b486289a525ea7f24f50487380bbd95725dd4483772350..a8b907ea1cc4ceff7c3675a5a898dfa25d6f29783fda0a4da8fc03678d10cba8 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -207,6 +207,7 @@ Currently available context options: * :ref:`defines_by_path ` +* :ref:`strict_default_existence ` .. _pprinting: @@ -3660,13 +3661,18 @@ (True, BOOLEAN True) All defaulted values are always optional. + .. _strict_default_existence_ctx: + .. warning:: When decoded DER contains defaulted value inside, then - technically this is not valid DER encoding. But we allow - and pass it. Of course reencoding of that kind of DER will + technically this is not valid DER encoding. But we allow and pass + it **by default**. Of course reencoding of that kind of DER will result in different binary representation (validly without - defaulted value inside). + defaulted value inside). You can enable strict defaulted values + existence validation by setting ``"strict_default_existence": + True`` :ref:`context ` option -- decoding process will raise + an exception if defaulted value is met. Two sequences are equal if they have equal specification (schema), implicit/explicit tagging and the same values. @@ -3900,9 +3906,15 @@ sub_offset += (value.expl_tlvlen if value.expled else value.tlvlen) v = v_tail if spec.default is not None and value == spec.default: - # Encoded default values are not valid in DER, - # but we allow that anyway - continue + if ctx.get("strict_default_existence", False): + raise DecodeError( + "DEFAULT value met", + klass=self.__class__, + decode_path=sub_decode_path, + offset=sub_offset, + ) + else: + continue values[name] = value spec_defines = getattr(spec, "defines", ()) diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index 65a0dc7211952b36e7c0697e3bd8733d7835e57234febd842a173f177b9f3a16..75f6b8412484967c4ce679ee4cebda1b33b6b0f851ac6378891e88c7ab27221f 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -5112,3 +5112,26 @@ self.assertSequenceEqual( abs_decode_path(decode_path, tuple([".."] * number_of_dots) + rel_path), decode_path[:-number_of_dots] + rel_path, ) + + +class TestStrictDefaultExistence(TestCase): + @given(data_strategy()) + def runTest(self, d): + count = d.draw(integers(min_value=1, max_value=10)) + chosen = d.draw(integers(min_value=0, max_value=count - 1)) + _schema = [ + ("int%d" % i, Integer(expl=tag_ctxc(i + 1))) + for i in range(count) + ] + + class Seq(Sequence): + schema = _schema + seq = Seq() + for i in range(count): + seq["int%d" % i] = Integer(123) + raw = seq.encode() + chosen = "int%d" % chosen + seq.specs[chosen] = seq.specs[chosen](default=123) + seq.decode(raw) + with assertRaisesRegex(self, DecodeError, "DEFAULT value met"): + seq.decode(raw, ctx={"strict_default_existence": True})