]> Cypherpunks.ru repositories - pyderasn.git/commitdiff
COMPLI: ASN.1:2008 compliance test suite
authorSergey Matveev <stargrave@stargrave.org>
Sat, 29 Dec 2018 20:20:40 +0000 (23:20 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sat, 29 Dec 2018 22:13:06 +0000 (01:13 +0300)
.gitmodules [new file with mode: 0644]
MANIFEST.in
VERSION
doc/features.rst
doc/news.rst
tests/compli_test_suite [new submodule]
tests/test_compli.py [new file with mode: 0644]

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..5131e37
--- /dev/null
@@ -0,0 +1,3 @@
+[submodule "tests/compli_test_suite"]
+       path = tests/compli_test_suite
+       url = https://github.com/YuryStrozhevsky/asn1-test-suite.git
index fe88f57f8bf5217480dc4abc729486a36c4c79d7..4ee37acadaeeff427cfb310b1ef6648c03fcf9b3 100644 (file)
@@ -22,6 +22,11 @@ include pip-requirements.txt
 include PUBKEY.asc
 include README
 include tests/__init__.py
+include tests/compli_test_suite/LICENSE
+include tests/compli_test_suite/pdf/free_asn1_testsuite.pdf
+include tests/compli_test_suite/README.md
+include tests/compli_test_suite/suite/tc*.ber
+include tests/test_compli.py
 include tests/test_crts.py
 include tests/test_pyderasn.py
 include THANKS
diff --git a/VERSION b/VERSION
index 4caecc733e6bc437e8afacd9a27cd84edd18a5bc..b3d791d7525d40f365fab7fb6d7b34448af4aeb8 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.5
+4.6
index 5476b6f7e6d5d1f70b2f1ed0a8fc416882695bd9..c18c83d9720c56ad8cd66d774ee3d61adc4ceda1 100644 (file)
@@ -9,6 +9,7 @@ Features
 * Working with sequences as high level data objects with ability to
   (un)marshall them
 * Python 2.7/3.5/3.6 compatibility
+* Aimed to be complaint with `X.690-201508 <https://www.itu.int/rec/T-REC-X.690-201508-I/en>`__
 
 Why yet another library? `pyasn1 <http://snmplabs.com/pyasn1/>`__
 had all of this a long time ago. PyDERASN resembles it in many ways. In
index f36fd83de780cd702be58bdacfb8feed5d4dffe1..90bf903e9c757c6bce741a750abe91ce97b38efd 100644 (file)
@@ -1,6 +1,14 @@
 News
 ====
 
+.. _release4.6:
+
+4.6
+---
+* Added `COMPLI <https://github.com/YuryStrozhevsky/asn1-test-suite>`__
+  ASN.1:2008 test suite. PyDERASN passes it (except for REAL values),
+  but it is more strict sometimes and aimed to be compliant with X.690-201508
+
 .. _release4.5:
 
 4.5
diff --git a/tests/compli_test_suite b/tests/compli_test_suite
new file mode 160000 (submodule)
index 0000000..d027021
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit d0270215a6d25802e585d6153659d20c080f9d4b
diff --git a/tests/test_compli.py b/tests/test_compli.py
new file mode 100644 (file)
index 0000000..8e0ff82
--- /dev/null
@@ -0,0 +1,290 @@
+"""COMPLI ASN.1:2008 compliance test suite
+
+COMPLI is a collection of BER-encoded examples that must behave in
+strictly defined way. All of them are to be valid ASN.1 encodings,
+however some of them do not comply with X.690-201508, so PyDERASN
+behaves differently in some tests. PyDERASN does not support REAL
+values too.
+"""
+
+from os import path
+from unittest import skip
+from unittest import TestCase
+
+from six import assertRaisesRegex
+
+from pyderasn import BitString
+from pyderasn import Boolean
+from pyderasn import DecodeError
+from pyderasn import Integer
+from pyderasn import InvalidLength
+from pyderasn import len_decode
+from pyderasn import LenIndefForm
+from pyderasn import NotEnoughData
+from pyderasn import Null
+from pyderasn import ObjectIdentifier
+from pyderasn import OctetString
+from pyderasn import tag_decode
+from pyderasn import tag_strip
+
+
+test_suite_path = path.join(
+    path.dirname(path.abspath(__file__)),
+    "compli_test_suite",
+    "suite",
+)
+
+
+def load_tc(num):
+    with open(path.join(test_suite_path, ("tc%d.ber" % num)), "rb") as fd:
+        return fd.read()
+
+
+class TestTestSuite(TestCase):
+    def test_tc1(self):
+        data = load_tc(1)
+        tag_strip(data)
+        tag_decode(data)
+
+    def test_tc2(self):
+        data = load_tc(2)
+        with assertRaisesRegex(self, DecodeError, "unfinished tag"):
+            tag_strip(data)
+
+    def test_tc3(self):
+        data = load_tc(3)
+        t, _, _ = tag_strip(data)
+        with self.assertRaises(NotEnoughData):
+            OctetString(impl=t).decode(data)
+
+    def test_tc4(self):
+        data = load_tc(4)
+        t, _, lv = tag_strip(data)
+        with self.assertRaises(NotEnoughData):
+            len_decode(lv)
+
+    def test_tc5(self):
+        data = load_tc(5)
+        t, _, lv = tag_strip(data)
+        with assertRaisesRegex(self, DecodeError, "long form instead of"):
+            len_decode(lv)
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc6(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc7(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc8(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc9(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc10(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc11(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc12(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc13(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc14(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc15(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc16(self):
+        pass
+
+    @skip("PyDERASN does not support REAL")
+    def test_tc17(self):
+        pass
+
+    def test_tc18(self):
+        data = load_tc(18)
+        with assertRaisesRegex(self, DecodeError, "non normalized"):
+            Integer().decode(data)
+
+    def test_tc19(self):
+        data = load_tc(19)
+        with self.assertRaises(NotEnoughData):
+            Integer().decode(data)
+
+    def test_tc20(self):
+        data = load_tc(20)
+        Integer().decode(data)
+
+    def test_tc21(self):
+        data = load_tc(21)
+        with assertRaisesRegex(self, DecodeError, "non normalized"):
+            ObjectIdentifier().decode(data)
+        ObjectIdentifier().decode(data, ctx={"bered": True})
+
+    def test_tc22(self):
+        data = load_tc(22)
+        ObjectIdentifier().decode(data)
+
+    def test_tc23(self):
+        data = load_tc(23)
+        with self.assertRaises(NotEnoughData):
+            ObjectIdentifier().decode(data)
+
+    def test_tc24(self):
+        data = load_tc(24)
+        ObjectIdentifier().decode(data)
+
+    def test_tc25(self):
+        # X.690-201508 8.2.1: The encoding of a boolean value shall be
+        # primitive. The contents octets shall consist of a single octet.
+        data = load_tc(25)
+        with self.assertRaises(InvalidLength):
+            Boolean().decode(data)
+        with self.assertRaises(InvalidLength):
+            Boolean().decode(data, ctx={"bered": True})
+
+    def test_tc26(self):
+        # X.690-201508 8.2.1: The encoding of a boolean value shall be
+        # primitive. The contents octets shall consist of a single octet.
+        data = load_tc(26)
+        with self.assertRaises(InvalidLength):
+            Boolean().decode(data)
+        with self.assertRaises(InvalidLength):
+            Boolean().decode(data, ctx={"bered": True})
+
+    def test_tc27(self):
+        data = load_tc(27)
+        with self.assertRaises(InvalidLength):
+            Boolean().decode(data)
+
+    def test_tc28(self):
+        data = load_tc(28)
+        self.assertTrue(bool(Boolean().decode(data)[0]))
+
+    def test_tc29(self):
+        data = load_tc(29)
+        self.assertFalse(bool(Boolean().decode(data)[0]))
+
+    def test_tc30(self):
+        data = load_tc(30)
+        with self.assertRaises(InvalidLength):
+            Null().decode(data)
+
+    def test_tc31(self):
+        data = load_tc(31)
+        with self.assertRaises(InvalidLength):
+            Null().decode(data)
+
+    def test_tc32(self):
+        data = load_tc(32)
+        Null().decode(data)
+
+    def test_tc33(self):
+        data = load_tc(33)
+        with assertRaisesRegex(self, DecodeError, "too big pad"):
+            BitString().decode(data)
+        with assertRaisesRegex(self, DecodeError, "too big pad"):
+            BitString().decode(data, ctx={"bered": True})
+
+    def test_tc34(self):
+        data = load_tc(34)
+        with self.assertRaises(NotEnoughData):
+            BitString().decode(data)
+
+    def test_tc35(self):
+        data = load_tc(35)
+        with assertRaisesRegex(self, DecodeError, "expected BitString encoded chunk"):
+            BitString().decode(data, ctx={"bered": True})
+
+    def test_tc36(self):
+        data = load_tc(36)
+        with assertRaisesRegex(self, DecodeError, "invalid pad"):
+            BitString().decode(data, ctx={"bered": True})
+
+    def test_tc37(self):
+        # X.690-201508 8.6.4: To encode a bitstring value in this way,
+        # it is segmented. Each segment shall consist of a series of
+        # consecutive bits of the value, and with the possible exception
+        # of the last, shall contain a number of bits which is a
+        # multiple of eight.
+        data = load_tc(37)
+        with assertRaisesRegex(self, DecodeError, "invalid pad"):
+            BitString().decode(data, ctx={"bered": True})
+
+    def test_tc38(self):
+        data = load_tc(38)
+        BitString().decode(data, ctx={"bered": True})
+
+    def test_tc39(self):
+        # X.690-201508 8.6.2: The contents octets for the primitive
+        # encoding shall contain an initial octet followed by zero, one
+        # or more subsequent octets.
+        # X.690-201508 8.6.2.3: If the bitstring is empty, there shall
+        # be no subsequent octets, and the initial octet shall be zero.
+        data = load_tc(39)
+        with self.assertRaises(NotEnoughData):
+            BitString().decode(data, ctx={"bered": True})
+
+    def test_tc40(self):
+        # X.690-201508 8.6.2: The contents octets for the primitive
+        # encoding shall contain an initial octet followed by zero, one
+        # or more subsequent octets.
+        # X.690-201508 8.6.2.3: If the bitstring is empty, there shall
+        # be no subsequent octets, and the initial octet shall be zero.
+        data = load_tc(40)
+        with self.assertRaises(NotEnoughData):
+            BitString().decode(data, ctx={"bered": True})
+
+    def test_tc41(self):
+        data = load_tc(41)
+        with assertRaisesRegex(self, DecodeError, "expected OctetString encoded chunk"):
+            OctetString().decode(data, ctx={"bered": True})
+
+    def test_tc42(self):
+        data = load_tc(42)
+        with self.assertRaises(NotEnoughData):
+            OctetString().decode(data, ctx={"bered": True})
+
+    def test_tc43(self):
+        data = load_tc(43)
+        with self.assertRaises(NotEnoughData):
+            OctetString().decode(data, ctx={"bered": True})
+
+    def test_tc44(self):
+        data = load_tc(44)
+        OctetString().decode(data)
+
+    def test_tc45(self):
+        data = load_tc(45)
+        OctetString().decode(data, ctx={"bered": True})
+
+    def test_tc46(self):
+        data = load_tc(46)
+        with self.assertRaises(LenIndefForm):
+            BitString().decode(data, ctx={"bered": True})
+
+    def test_tc47(self):
+        data = load_tc(47)
+        with assertRaisesRegex(self, DecodeError, "expected BitString encoded chunk"):
+            BitString().decode(data, ctx={"bered": True})
+
+    def test_tc48(self):
+        data = load_tc(48)
+        with assertRaisesRegex(self, DecodeError, "too big pad"):
+            BitString().decode(data, ctx={"bered": True})