aboutsummaryrefslogtreecommitdiff
path: root/frozen_deps/ecdsa/test_der.py
diff options
context:
space:
mode:
Diffstat (limited to 'frozen_deps/ecdsa/test_der.py')
-rw-r--r--frozen_deps/ecdsa/test_der.py397
1 files changed, 397 insertions, 0 deletions
diff --git a/frozen_deps/ecdsa/test_der.py b/frozen_deps/ecdsa/test_der.py
new file mode 100644
index 0000000..746d927
--- /dev/null
+++ b/frozen_deps/ecdsa/test_der.py
@@ -0,0 +1,397 @@
+# compatibility with Python 2.6, for that we need unittest2 package,
+# which is not available on 3.3 or 3.4
+import warnings
+from binascii import hexlify
+
+try:
+ import unittest2 as unittest
+except ImportError:
+ import unittest
+from six import b
+import hypothesis.strategies as st
+from hypothesis import given, example
+import pytest
+from ._compat import str_idx_as_int
+from .curves import NIST256p, NIST224p
+from .der import (
+ remove_integer,
+ UnexpectedDER,
+ read_length,
+ encode_bitstring,
+ remove_bitstring,
+ remove_object,
+ encode_oid,
+)
+
+
+class TestRemoveInteger(unittest.TestCase):
+ # DER requires the integers to be 0-padded only if they would be
+ # interpreted as negative, check if those errors are detected
+ def test_non_minimal_encoding(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_integer(b("\x02\x02\x00\x01"))
+
+ def test_negative_with_high_bit_set(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_integer(b("\x02\x01\x80"))
+
+ def test_minimal_with_high_bit_set(self):
+ val, rem = remove_integer(b("\x02\x02\x00\x80"))
+
+ self.assertEqual(val, 0x80)
+ self.assertFalse(rem)
+
+ def test_two_zero_bytes_with_high_bit_set(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_integer(b("\x02\x03\x00\x00\xff"))
+
+ def test_zero_length_integer(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_integer(b("\x02\x00"))
+
+ def test_empty_string(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_integer(b(""))
+
+ def test_encoding_of_zero(self):
+ val, rem = remove_integer(b("\x02\x01\x00"))
+
+ self.assertEqual(val, 0)
+ self.assertFalse(rem)
+
+ def test_encoding_of_127(self):
+ val, rem = remove_integer(b("\x02\x01\x7f"))
+
+ self.assertEqual(val, 127)
+ self.assertFalse(rem)
+
+ def test_encoding_of_128(self):
+ val, rem = remove_integer(b("\x02\x02\x00\x80"))
+
+ self.assertEqual(val, 128)
+ self.assertFalse(rem)
+
+
+class TestReadLength(unittest.TestCase):
+ # DER requires the lengths between 0 and 127 to be encoded using the short
+ # form and lengths above that encoded with minimal number of bytes
+ # necessary
+ def test_zero_length(self):
+ self.assertEqual((0, 1), read_length(b("\x00")))
+
+ def test_two_byte_zero_length(self):
+ with self.assertRaises(UnexpectedDER):
+ read_length(b("\x81\x00"))
+
+ def test_two_byte_small_length(self):
+ with self.assertRaises(UnexpectedDER):
+ read_length(b("\x81\x7f"))
+
+ def test_long_form_with_zero_length(self):
+ with self.assertRaises(UnexpectedDER):
+ read_length(b("\x80"))
+
+ def test_smallest_two_byte_length(self):
+ self.assertEqual((128, 2), read_length(b("\x81\x80")))
+
+ def test_zero_padded_length(self):
+ with self.assertRaises(UnexpectedDER):
+ read_length(b("\x82\x00\x80"))
+
+ def test_two_three_byte_length(self):
+ self.assertEqual((256, 3), read_length(b"\x82\x01\x00"))
+
+ def test_empty_string(self):
+ with self.assertRaises(UnexpectedDER):
+ read_length(b(""))
+
+ def test_length_overflow(self):
+ with self.assertRaises(UnexpectedDER):
+ read_length(b("\x83\x01\x00"))
+
+
+class TestEncodeBitstring(unittest.TestCase):
+ # DER requires BIT STRINGS to include a number of padding bits in the
+ # encoded byte string, that padding must be between 0 and 7
+
+ def test_old_call_convention(self):
+ """This is the old way to use the function."""
+ warnings.simplefilter("always")
+ with pytest.warns(DeprecationWarning) as warns:
+ der = encode_bitstring(b"\x00\xff")
+
+ self.assertEqual(len(warns), 1)
+ self.assertIn(
+ "unused= needs to be specified", warns[0].message.args[0]
+ )
+
+ self.assertEqual(der, b"\x03\x02\x00\xff")
+
+ def test_new_call_convention(self):
+ """This is how it should be called now."""
+ warnings.simplefilter("always")
+ with pytest.warns(None) as warns:
+ der = encode_bitstring(b"\xff", 0)
+
+ # verify that new call convention doesn't raise Warnings
+ self.assertEqual(len(warns), 0)
+
+ self.assertEqual(der, b"\x03\x02\x00\xff")
+
+ def test_implicit_unused_bits(self):
+ """
+ Writing bit string with already included the number of unused bits.
+ """
+ warnings.simplefilter("always")
+ with pytest.warns(None) as warns:
+ der = encode_bitstring(b"\x00\xff", None)
+
+ # verify that new call convention doesn't raise Warnings
+ self.assertEqual(len(warns), 0)
+
+ self.assertEqual(der, b"\x03\x02\x00\xff")
+
+ def test_explicit_unused_bits(self):
+ der = encode_bitstring(b"\xff\xf0", 4)
+
+ self.assertEqual(der, b"\x03\x03\x04\xff\xf0")
+
+ def test_empty_string(self):
+ self.assertEqual(encode_bitstring(b"", 0), b"\x03\x01\x00")
+
+ def test_invalid_unused_count(self):
+ with self.assertRaises(ValueError):
+ encode_bitstring(b"\xff\x00", 8)
+
+ def test_invalid_unused_with_empty_string(self):
+ with self.assertRaises(ValueError):
+ encode_bitstring(b"", 1)
+
+ def test_non_zero_padding_bits(self):
+ with self.assertRaises(ValueError):
+ encode_bitstring(b"\xff", 2)
+
+
+class TestRemoveBitstring(unittest.TestCase):
+ def test_old_call_convention(self):
+ """This is the old way to call the function."""
+ warnings.simplefilter("always")
+ with pytest.warns(DeprecationWarning) as warns:
+ bits, rest = remove_bitstring(b"\x03\x02\x00\xff")
+
+ self.assertEqual(len(warns), 1)
+ self.assertIn(
+ "expect_unused= needs to be specified", warns[0].message.args[0]
+ )
+
+ self.assertEqual(bits, b"\x00\xff")
+ self.assertEqual(rest, b"")
+
+ def test_new_call_convention(self):
+ warnings.simplefilter("always")
+ with pytest.warns(None) as warns:
+ bits, rest = remove_bitstring(b"\x03\x02\x00\xff", 0)
+
+ self.assertEqual(len(warns), 0)
+
+ self.assertEqual(bits, b"\xff")
+ self.assertEqual(rest, b"")
+
+ def test_implicit_unexpected_unused(self):
+ warnings.simplefilter("always")
+ with pytest.warns(None) as warns:
+ bits, rest = remove_bitstring(b"\x03\x02\x00\xff", None)
+
+ self.assertEqual(len(warns), 0)
+
+ self.assertEqual(bits, (b"\xff", 0))
+ self.assertEqual(rest, b"")
+
+ def test_with_padding(self):
+ ret, rest = remove_bitstring(b"\x03\x02\x04\xf0", None)
+
+ self.assertEqual(ret, (b"\xf0", 4))
+ self.assertEqual(rest, b"")
+
+ def test_not_a_bitstring(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_bitstring(b"\x02\x02\x00\xff", None)
+
+ def test_empty_encoding(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_bitstring(b"\x03\x00", None)
+
+ def test_empty_string(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_bitstring(b"", None)
+
+ def test_no_length(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_bitstring(b"\x03", None)
+
+ def test_unexpected_number_of_unused_bits(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_bitstring(b"\x03\x02\x00\xff", 1)
+
+ def test_invalid_encoding_of_unused_bits(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_bitstring(b"\x03\x03\x08\xff\x00", None)
+
+ def test_invalid_encoding_of_empty_string(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_bitstring(b"\x03\x01\x01", None)
+
+ def test_invalid_padding_bits(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_bitstring(b"\x03\x02\x01\xff", None)
+
+
+class TestStrIdxAsInt(unittest.TestCase):
+ def test_str(self):
+ self.assertEqual(115, str_idx_as_int("str", 0))
+
+ def test_bytes(self):
+ self.assertEqual(115, str_idx_as_int(b"str", 0))
+
+ def test_bytearray(self):
+ self.assertEqual(115, str_idx_as_int(bytearray(b"str"), 0))
+
+
+class TestEncodeOid(unittest.TestCase):
+ def test_pub_key_oid(self):
+ oid_ecPublicKey = encode_oid(1, 2, 840, 10045, 2, 1)
+ self.assertEqual(hexlify(oid_ecPublicKey), b("06072a8648ce3d0201"))
+
+ def test_nist224p_oid(self):
+ self.assertEqual(hexlify(NIST224p.encoded_oid), b("06052b81040021"))
+
+ def test_nist256p_oid(self):
+ self.assertEqual(
+ hexlify(NIST256p.encoded_oid), b"06082a8648ce3d030107"
+ )
+
+ def test_large_second_subid(self):
+ # from X.690, section 8.19.5
+ oid = encode_oid(2, 999, 3)
+ self.assertEqual(oid, b"\x06\x03\x88\x37\x03")
+
+ def test_with_two_subids(self):
+ oid = encode_oid(2, 999)
+ self.assertEqual(oid, b"\x06\x02\x88\x37")
+
+ def test_zero_zero(self):
+ oid = encode_oid(0, 0)
+ self.assertEqual(oid, b"\x06\x01\x00")
+
+ def test_with_wrong_types(self):
+ with self.assertRaises((TypeError, AssertionError)):
+ encode_oid(0, None)
+
+ def test_with_small_first_large_second(self):
+ with self.assertRaises(AssertionError):
+ encode_oid(1, 40)
+
+ def test_small_first_max_second(self):
+ oid = encode_oid(1, 39)
+ self.assertEqual(oid, b"\x06\x01\x4f")
+
+ def test_with_invalid_first(self):
+ with self.assertRaises(AssertionError):
+ encode_oid(3, 39)
+
+
+class TestRemoveObject(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.oid_ecPublicKey = encode_oid(1, 2, 840, 10045, 2, 1)
+
+ def test_pub_key_oid(self):
+ oid, rest = remove_object(self.oid_ecPublicKey)
+ self.assertEqual(rest, b"")
+ self.assertEqual(oid, (1, 2, 840, 10045, 2, 1))
+
+ def test_with_extra_bytes(self):
+ oid, rest = remove_object(self.oid_ecPublicKey + b"more")
+ self.assertEqual(rest, b"more")
+ self.assertEqual(oid, (1, 2, 840, 10045, 2, 1))
+
+ def test_with_large_second_subid(self):
+ # from X.690, section 8.19.5
+ oid, rest = remove_object(b"\x06\x03\x88\x37\x03")
+ self.assertEqual(rest, b"")
+ self.assertEqual(oid, (2, 999, 3))
+
+ def test_with_padded_first_subid(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"\x06\x02\x80\x00")
+
+ def test_with_padded_second_subid(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"\x06\x04\x88\x37\x80\x01")
+
+ def test_with_missing_last_byte_of_multi_byte(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"\x06\x03\x88\x37\x83")
+
+ def test_with_two_subids(self):
+ oid, rest = remove_object(b"\x06\x02\x88\x37")
+ self.assertEqual(rest, b"")
+ self.assertEqual(oid, (2, 999))
+
+ def test_zero_zero(self):
+ oid, rest = remove_object(b"\x06\x01\x00")
+ self.assertEqual(rest, b"")
+ self.assertEqual(oid, (0, 0))
+
+ def test_empty_string(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"")
+
+ def test_missing_length(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"\x06")
+
+ def test_empty_oid(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"\x06\x00")
+
+ def test_empty_oid_overflow(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"\x06\x01")
+
+ def test_with_wrong_type(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"\x04\x02\x88\x37")
+
+ def test_with_too_long_length(self):
+ with self.assertRaises(UnexpectedDER):
+ remove_object(b"\x06\x03\x88\x37")
+
+
+@st.composite
+def st_oid(draw, max_value=2 ** 512, max_size=50):
+ """
+ Hypothesis strategy that returns valid OBJECT IDENTIFIERs as tuples
+
+ :param max_value: maximum value of any single sub-identifier
+ :param max_size: maximum length of the generated OID
+ """
+ first = draw(st.integers(min_value=0, max_value=2))
+ if first < 2:
+ second = draw(st.integers(min_value=0, max_value=39))
+ else:
+ second = draw(st.integers(min_value=0, max_value=max_value))
+ rest = draw(
+ st.lists(
+ st.integers(min_value=0, max_value=max_value), max_size=max_size
+ )
+ )
+ return (first, second) + tuple(rest)
+
+
+@given(st_oid())
+def test_oids(ids):
+ encoded_oid = encode_oid(*ids)
+ decoded_oid, rest = remove_object(encoded_oid)
+ assert rest == b""
+ assert decoded_oid == ids