# 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 import sys import hypothesis.strategies as st from hypothesis import given, settings 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,
remove_constructed,
remove_implicit,
remove_octet_string,
remove_sequence,
encode_implicit,
)
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")
def test_wrong_tag(self): with self.assertRaises(UnexpectedDER) as e:
remove_integer(b"\x01\x02\x00\x80")
self.assertIn("wanted type 'integer'", str(e.exception))
def test_wrong_length(self): with self.assertRaises(UnexpectedDER) as e:
remove_integer(b"\x02\x03\x00\x80")
self.assertIn("Length longer", str(e.exception))
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_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.""" # make sure no warnings are raised with warnings.catch_warnings():
warnings.simplefilter("error")
der = encode_bitstring(b"\xff", 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. """ # make sure no warnings are raised with warnings.catch_warnings():
warnings.simplefilter("error")
der = encode_bitstring(b"\x00\xff", None)
self.assertEqual(der, b"\x03\x02\x00\xff")
def test_explicit_unused_bits(self):
der = encode_bitstring(b"\xff\xf0", 4)
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]
)
def test_new_call_convention(self): # make sure no warnings are raised with warnings.catch_warnings():
warnings.simplefilter("error")
bits, rest = remove_bitstring(b"\x03\x02\x00\xff", 0)
def test_implicit_unexpected_unused(self): # make sure no warnings are raised with warnings.catch_warnings():
warnings.simplefilter("error")
bits, rest = remove_bitstring(b"\x03\x02\x00\xff", None)
class TestRemoveImplicit(unittest.TestCase):
@classmethod def setUpClass(cls):
cls.exp_tag = 6
cls.exp_data = b"\x0a\x0b" # data with application tag class
cls.data_application = b"\x46\x02\x0a\x0b" # data with context-specific tag class
cls.data_context_specific = b"\x86\x02\x0a\x0b" # data with private tag class
cls.data_private = b"\xc6\x02\x0a\x0b"
class TestEncodeImplicit(unittest.TestCase):
@classmethod def setUpClass(cls):
cls.data = b"\x0a\x0b" # data with application tag class
cls.data_application = b"\x46\x02\x0a\x0b" # data with context-specific tag class
cls.data_context_specific = b"\x86\x02\x0a\x0b" # data with private tag class
cls.data_private = b"\xc6\x02\x0a\x0b"
def test_encode_with_default_class(self):
ret = encode_implicit(6, self.data)
self.assertEqual(ret, self.data_context_specific)
def test_encode_with_application_class(self):
ret = encode_implicit(6, self.data, "application")
self.assertEqual(ret, self.data_application)
def test_encode_with_context_specific_class(self):
ret = encode_implicit(6, self.data, "context-specific")
self.assertEqual(ret, self.data_context_specific)
def test_encode_with_private_class(self):
ret = encode_implicit(6, self.data, "private")
self.assertEqual(ret, self.data_private)
def test_encode_with_invalid_class(self): with self.assertRaises(ValueError) as e:
encode_implicit(6, self.data, "foobar")
self.assertIn("invalid tag class", str(e.exception))
def test_encode_with_too_large_tag(self): with self.assertRaises(ValueError) as e:
encode_implicit(32, self.data)
self.assertIn("Long tags not supported", str(e.exception))
class TestRemoveOctetString(unittest.TestCase): def test_simple(self):
data = b"\x04\x03\xaa\xbb\xcc"
body, rest = remove_octet_string(data)
self.assertEqual(body, b"\xaa\xbb\xcc")
self.assertEqual(rest, b"")
def test_with_malformed_tag(self):
data = b"\x03\x03\xaa\xbb\xcc" with self.assertRaises(UnexpectedDER) as e:
remove_octet_string(data)
self.assertIn("octetstring", str(e.exception))
class TestRemoveSequence(unittest.TestCase): def test_simple(self):
data = b"\x30\x02\xff\xaa"
body, rest = remove_sequence(data)
self.assertEqual(body, b"\xff\xaa")
self.assertEqual(rest, b"")
def test_with_empty_string(self): with self.assertRaises(UnexpectedDER) as e:
remove_sequence(b"")
self.assertIn("Empty string", str(e.exception))
def test_with_wrong_tag(self):
data = b"\x20\x02\xff\xaa"
with self.assertRaises(UnexpectedDER) as e:
remove_sequence(data)
self.assertIn("wanted type 'sequence'", str(e.exception))
def test_with_wrong_length(self):
data = b"\x30\x03\xff\xaa"
with self.assertRaises(UnexpectedDER) as e:
remove_sequence(data)
self.assertIn("Length longer", str(e.exception))
@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)
HYP_SETTINGS = {}
if"--fast"in sys.argv: # pragma: no cover
HYP_SETTINGS["max_examples"] = 2
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.