X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=tests%2Ftest_pyderasn.py;h=a07c495ebd5d838219b6b2be69cc011911f734cf;hb=3906f3ed9567496401ada4ba71a342215b8785f1;hp=4fc8a665bc6ca987b212fe5e46cc6daf765bae07;hpb=a5c6c3b3d379e8bdaf62603322caccf3aab35469;p=pyderasn.git diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py index 4fc8a66..a07c495 100644 --- a/tests/test_pyderasn.py +++ b/tests/test_pyderasn.py @@ -43,6 +43,7 @@ from hypothesis.strategies import sets from hypothesis.strategies import text from hypothesis.strategies import tuples from six import assertRaisesRegex +from six import binary_type from six import byte2int from six import indexbytes from six import int2byte @@ -62,6 +63,8 @@ from pyderasn import Choice from pyderasn import DecodeError from pyderasn import DecodePathDefBy from pyderasn import Enumerated +from pyderasn import EOC +from pyderasn import EOC_LEN from pyderasn import GeneralizedTime from pyderasn import GeneralString from pyderasn import GraphicString @@ -587,13 +590,71 @@ class TestBoolean(CommonMixin, TestCase): ))) @given(integers(min_value=0 + 1, max_value=255 - 1)) - def test_invalid_value(self, value): + def test_ber_value(self, value): with assertRaisesRegex(self, DecodeError, "unacceptable Boolean value"): Boolean().decode(b"".join(( Boolean.tag_default, len_encode(1), int2byte(value), ))) + obj, _ = Boolean().decode( + b"".join(( + Boolean.tag_default, + len_encode(1), + int2byte(value), + )), + ctx={"bered": True}, + ) + self.assertTrue(bool(obj)) + self.assertTrue(obj.bered) + self.assertFalse(obj.lenindef) + + @given( + integers(min_value=1).map(tag_ctxc), + lists( + booleans(), + min_size=1, + max_size=5, + ), + ) + def test_ber_expl(self, expl, values): + encoded = b"" + for value in values: + encoded += ( + expl + + b"\x80" + + Boolean(value).encode() + + EOC + ) + encoded = SequenceOf.tag_default + len_encode(len(encoded)) + encoded + + class SeqOf(SequenceOf): + schema = Boolean(expl=expl) + seqof, tail = SeqOf().decode(encoded, ctx={"bered": True}) + self.assertSequenceEqual(tail, b"") + self.assertSequenceEqual([bool(v) for v in seqof], values) + self.assertSetEqual( + set( + ( + v.tlvlen, + v.expl_tlvlen, + v.expl_tlen, + v.expl_llen, + v.bered, + v.lenindef, + v.expl_lenindef, + ) for v in seqof + ), + set((( + 3 + EOC_LEN, + len(expl) + 1 + 3 + EOC_LEN, + len(expl), + 1, + False, + False, + True, + ),)), + ) @composite @@ -1386,6 +1447,91 @@ class TestBitString(CommonMixin, TestCase): self.assertTrue(obj[9]) self.assertFalse(obj[17]) + @given( + integers(min_value=1, max_value=30), + lists( + one_of( + binary(min_size=1, max_size=5), + lists( + binary(min_size=1, max_size=5), + min_size=1, + max_size=3, + ), + ), + min_size=0, + max_size=3, + ), + lists(booleans(), min_size=1), + ) + def test_constructed(self, impl, chunk_inputs, chunk_last_bits): + def chunk_constructed(contents): + return ( + tag_encode(form=TagFormConstructed, num=3) + + b"\x80" + + b"".join(BitString(content).encode() for content in contents) + + EOC + ) + chunks = [] + payload_expected = b"" + bit_len_expected = 0 + for chunk_input in chunk_inputs: + if isinstance(chunk_input, binary_type): + chunks.append(BitString(chunk_input).encode()) + payload_expected += chunk_input + bit_len_expected += len(chunk_input) * 8 + else: + chunks.append(chunk_constructed(chunk_input)) + payload = b"".join(chunk_input) + payload_expected += payload + bit_len_expected += len(payload) * 8 + chunk_last = BitString("'%s'B" % "".join( + "1" if bit else "0" for bit in chunk_last_bits + )) + payload_expected += bytes(chunk_last) + bit_len_expected += chunk_last.bit_len + encoded_indefinite = ( + tag_encode(form=TagFormConstructed, num=impl) + + b"\x80" + + b"".join(chunks) + + chunk_last.encode() + + EOC + ) + encoded_definite = ( + tag_encode(form=TagFormConstructed, num=impl) + + len_encode(len(b"".join(chunks) + chunk_last.encode())) + + b"".join(chunks) + + chunk_last.encode() + ) + with assertRaisesRegex(self, DecodeError, "unallowed BER"): + BitString(impl=tag_encode(impl)).decode(encoded_indefinite) + for lenindef_expected, encoded in ( + (True, encoded_indefinite), + (False, encoded_definite), + ): + obj, tail = BitString(impl=tag_encode(impl)).decode( + encoded, ctx={"bered": True} + ) + self.assertSequenceEqual(tail, b"") + self.assertEqual(obj.bit_len, bit_len_expected) + self.assertSequenceEqual(bytes(obj), payload_expected) + self.assertTrue(obj.bered) + self.assertEqual(obj.lenindef, lenindef_expected) + self.assertEqual(len(encoded), obj.tlvlen) + + def test_x690_vector(self): + vector = BitString("'0A3B5F291CD'H") + obj, tail = BitString().decode(hexdec("0307040A3B5F291CD0")) + self.assertSequenceEqual(tail, b"") + self.assertEqual(obj, vector) + obj, tail = BitString().decode( + hexdec("23800303000A3B0305045F291CD00000"), + ctx={"bered": True}, + ) + self.assertSequenceEqual(tail, b"") + self.assertEqual(obj, vector) + self.assertTrue(obj.bered) + self.assertTrue(obj.lenindef) + @composite def octet_string_values_strategy(draw, do_expl=False): @@ -1697,6 +1843,65 @@ class TestOctetString(CommonMixin, TestCase): ) self.assertEqual(obj_decoded.expl_offset, offset) + @given( + integers(min_value=1, max_value=30), + lists( + one_of( + binary(min_size=1, max_size=5), + lists( + binary(min_size=1, max_size=5), + min_size=1, + max_size=3, + ), + ), + min_size=1, + max_size=3, + ), + ) + def test_constructed(self, impl, chunk_inputs): + def chunk_constructed(contents): + return ( + tag_encode(form=TagFormConstructed, num=4) + + b"\x80" + + b"".join(OctetString(content).encode() for content in contents) + + EOC + ) + chunks = [] + payload_expected = b"" + for chunk_input in chunk_inputs: + if isinstance(chunk_input, binary_type): + chunks.append(OctetString(chunk_input).encode()) + payload_expected += chunk_input + else: + chunks.append(chunk_constructed(chunk_input)) + payload = b"".join(chunk_input) + payload_expected += payload + encoded_indefinite = ( + tag_encode(form=TagFormConstructed, num=impl) + + b"\x80" + + b"".join(chunks) + + EOC + ) + encoded_definite = ( + tag_encode(form=TagFormConstructed, num=impl) + + len_encode(len(b"".join(chunks))) + + b"".join(chunks) + ) + with assertRaisesRegex(self, DecodeError, "unallowed BER"): + OctetString(impl=tag_encode(impl)).decode(encoded_indefinite) + for lenindef_expected, encoded in ( + (True, encoded_indefinite), + (False, encoded_definite), + ): + obj, tail = OctetString(impl=tag_encode(impl)).decode( + encoded, ctx={"bered": True} + ) + self.assertSequenceEqual(tail, b"") + self.assertSequenceEqual(bytes(obj), payload_expected) + self.assertTrue(obj.bered) + self.assertEqual(obj.lenindef, lenindef_expected) + self.assertEqual(len(encoded), obj.tlvlen) + @composite def null_values_strategy(draw, do_expl=False): @@ -2240,6 +2445,12 @@ class TestObjectIdentifier(CommonMixin, TestCase): data, ))) + def test_x690_vector(self): + self.assertEqual( + ObjectIdentifier().decode(hexdec("0603883703"))[0], + ObjectIdentifier((2, 999, 3)), + ) + @composite def enumerated_values_strategy(draw, schema=None, do_expl=False): @@ -2901,6 +3112,31 @@ class TestVisibleString( ): base_klass = VisibleString + def test_x690_vector(self): + obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573")) + self.assertSequenceEqual(tail, b"") + self.assertEqual(str(obj), "Jones") + self.assertFalse(obj.bered) + self.assertFalse(obj.lenindef) + + obj, tail = VisibleString().decode( + hexdec("3A0904034A6F6E04026573"), + ctx={"bered": True}, + ) + self.assertSequenceEqual(tail, b"") + self.assertEqual(str(obj), "Jones") + self.assertTrue(obj.bered) + self.assertFalse(obj.lenindef) + + obj, tail = VisibleString().decode( + hexdec("3A8004034A6F6E040265730000"), + ctx={"bered": True}, + ) + self.assertSequenceEqual(tail, b"") + self.assertEqual(str(obj), "Jones") + self.assertTrue(obj.bered) + self.assertTrue(obj.lenindef) + class TestGeneralString( UnicodeDecodeErrorMixin, @@ -4369,6 +4605,16 @@ class TestSequence(SeqMixing, CommonMixin, TestCase): seq[missing] = Boolean() repr(err.exception) + def test_x690_vector(self): + class Seq(Sequence): + schema = ( + ("name", IA5String()), + ("ok", Boolean()), + ) + seq = Seq().decode(hexdec("300A1605536d6974680101FF"))[0] + self.assertEqual(seq["name"], "Smith") + self.assertEqual(seq["ok"], True) + class TestSet(SeqMixing, CommonMixin, TestCase): base_klass = Set @@ -5285,3 +5531,42 @@ class TestStrictDefaultExistence(TestCase): seq.decode(raw) with assertRaisesRegex(self, DecodeError, "DEFAULT value met"): seq.decode(raw, ctx={"strict_default_existence": True}) + + +class TestX690PrefixedType(TestCase): + def runTest(self): + self.assertSequenceEqual( + VisibleString("Jones").encode(), + hexdec("1A054A6F6E6573"), + ) + self.assertSequenceEqual( + VisibleString( + "Jones", + impl=tag_encode(3, klass=TagClassApplication), + ).encode(), + hexdec("43054A6F6E6573"), + ) + self.assertSequenceEqual( + Any( + VisibleString( + "Jones", + impl=tag_encode(3, klass=TagClassApplication), + ), + expl=tag_ctxc(2), + ).encode(), + hexdec("A20743054A6F6E6573"), + ) + self.assertSequenceEqual( + OctetString( + VisibleString( + "Jones", + impl=tag_encode(3, klass=TagClassApplication), + ).encode(), + impl=tag_encode(7, form=TagFormConstructed, klass=TagClassApplication), + ).encode(), + hexdec("670743054A6F6E6573"), + ) + self.assertSequenceEqual( + VisibleString("Jones", impl=tag_ctxp(2)).encode(), + hexdec("82054A6F6E6573"), + )