VERSION | 2 +- doc/news.rst | 9 +++++++++ pyderasn.py | 34 +++++++++++++++++++++++++++++++++- tests/test_pyderasn.py | 10 ++++++++++ diff --git a/VERSION b/VERSION index 689be227785923138e58aebf707a186d2221631c29185af1e73a0414bac57e42..3b7677e103fc46d2868b01e7299d0134ae6411f16cdf5fe37bd4557f179b4ce4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.13 +3.14 diff --git a/doc/news.rst b/doc/news.rst index f08b250d10c0ecc6c2f5193c50eef4e3c3746d28c21ab40f8986fe55ebb46482..01c6e13286186ed1b48f2aaa521f983d58930298fd266c01d8c7d117a0261206 100644 --- a/doc/news.rst +++ b/doc/news.rst @@ -1,6 +1,15 @@ News ==== +.. _release3.14: + +3.14 +---- +* Additional encoding validness check: explicit tag must contain exactly + one object inside. Throw DecodeError otherwise +* ``allow_expl_oob`` context and command-line options allow skipping of + that check + .. _release3.13: 3.13 diff --git a/pyderasn.py b/pyderasn.py index 93b0ec529a758e702a93ba87ddbac73f1ad61dcc6656602b2548b6738ba3f633..05f5d411ca44d035e73e2ad46b0aa96e40efd4201d0bb38e22c391e721993d86 100755 --- a/pyderasn.py +++ b/pyderasn.py @@ -213,6 +213,7 @@ decoding process. Currently available context options: +* :ref:`allow_expl_oob ` * :ref:`bered ` * :ref:`defines_by_path ` * :ref:`strict_default_existence ` @@ -392,6 +393,22 @@ ``expl_lenindef`` is set to True. EOC (end-of-contents) token's length is taken in advance in object's value length. + +.. _allow_expl_oob_ctx: + +Allow explicit tag out-of-bound +------------------------------- + +Invalid BER encoding could contain ``EXPLICIT`` tag containing more than +one value, more than one object. If you set ``allow_expl_oob`` context +option to True, then no error will be raised and that invalid encoding +will be silently further processed. But pay attention that offsets and +lengths will be invalid in that case. + +.. warning:: + + This option should be used only for skipping some decode errors, just + to see the decoded structure somehow. Primitive types --------------- @@ -1092,6 +1109,13 @@ ) if tag_only: return obj, tail = result + if obj.tlvlen < l and not ctx.get("allow_expl_oob", False): + raise DecodeError( + "explicit tag out-of-bound, longer than data", + klass=self.__class__, + decode_path=decode_path, + offset=offset, + ) return obj, (tail if leavemm else tail.tobytes()) @property @@ -5247,6 +5271,11 @@ "--decode-path-only", help="Print only specified decode path", ) parser.add_argument( + "--allow-expl-oob", + action="store_true", + help="Allow explicit tag out-of-bound", + ) + parser.add_argument( "DERFile", type=argparse.FileType("rb"), help="Path to DER file you want to decode", @@ -5262,7 +5291,10 @@ from functools import partial pprinter = partial(pprint, big_blobs=True) else: schema, pprinter = generic_decoder() - ctx = {"bered": not args.nobered} + ctx = { + "bered": not args.nobered, + "allow_expl_oob": args.allow_expl_oob, + } if args.defines_by_path is not None: ctx["defines_by_path"] = obj_by_path(args.defines_by_path) obj, tail = schema().decode(der, ctx=ctx) diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index 81df2dfc862f1f7588024abd339c8f9a6aef8913963db52985aed7efeb031164..da98e5fb560dd4a2b312e8e379b10e879430818fed6a5f0a6781744e29b4d354 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -5922,3 +5922,13 @@ self.assertSequenceEqual( VisibleString("Jones", impl=tag_ctxp(2)).encode(), hexdec("82054A6F6E6573"), ) + + +class TestExplOOB(TestCase): + def runTest(self): + expl = tag_ctxc(123) + raw = Integer(123).encode() + Integer(234).encode() + raw = b"".join((expl, len_encode(len(raw)), raw)) + with assertRaisesRegex(self, DecodeError, "explicit tag out-of-bound"): + Integer(expl=expl).decode(raw) + Integer(expl=expl).decode(raw, ctx={"allow_expl_oob": True})