# coding: utf-8
# PyDERASN -- Python ASN.1 DER/CER/BER codec with abstract structures
-# Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
+# Copyright (C) 2017-2021 Sergey Matveev <stargrave@stargrave.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
from time import time
from unittest import TestCase
+from dateutil.tz import UTC
from hypothesis import assume
from hypothesis import given
from hypothesis import settings
with self.assertRaises(DecodeError):
len_decode(octets)
+ @given(tag_classes, tag_forms, integers(min_value=31))
+ def test_leading_zero_byte(self, klass, form, num):
+ raw = tag_encode(klass=klass, form=form, num=num)
+ raw = b"".join((raw[:1], b"\x80", raw[1:]))
+ with assertRaisesRegex(self, DecodeError, "leading zero byte"):
+ tag_strip(raw)
+
+ @given(tag_classes, tag_forms, integers(max_value=30, min_value=0))
+ def test_unexpected_long_form(self, klass, form, num):
+ raw = int2byte(klass | form | 31) + int2byte(num)
+ with assertRaisesRegex(self, DecodeError, "unexpected long form"):
+ tag_strip(raw)
+
class TestLenCoder(TestCase):
@settings(max_examples=LONG_TEST_MAX_EXAMPLES)
repr(obj)
list(obj.pps())
-
@given(integers(min_value=1))
def test_invalid_len(self, l):
with self.assertRaises(InvalidLength):
data,
)))
+ def test_go_non_minimal_encoding(self):
+ with self.assertRaises(DecodeError):
+ ObjectIdentifier().decode(hexdec("060a2a80864886f70d01010b"))
+
def test_x690_vector(self):
self.assertEqual(
ObjectIdentifier().decode(hexdec("0603883703"))[0],
repr(err.exception)
def text_alphabet(self):
- if self.base_klass.encoding in ("ascii", "iso-8859-1"):
- return printable + whitespace
- return None
+ return "".join(six_unichr(c) for c in six_xrange(256))
@given(booleans())
def test_optional(self, optional):
@given(text(alphabet=ascii_letters, min_size=1, max_size=5))
def test_non_numeric(self, non_numeric_text):
- with assertRaisesRegex(self, DecodeError, "non-numeric"):
+ with assertRaisesRegex(self, DecodeError, "alphabet value"):
self.base_klass(non_numeric_text)
@given(
@given(text(alphabet=sorted(set(whitespace) - set(" ")), min_size=1, max_size=5))
def test_non_printable(self, non_printable_text):
- with assertRaisesRegex(self, DecodeError, "non-printable"):
+ with assertRaisesRegex(self, DecodeError, "alphabet value"):
self.base_klass(non_printable_text)
@given(
for prop in kwargs.keys():
self.assertFalse(getattr(obj, prop))
s += c
- with assertRaisesRegex(self, DecodeError, "non-printable"):
+ with assertRaisesRegex(self, DecodeError, "alphabet value"):
self.base_klass(s)
self.base_klass(s, **kwargs)
klass = self.base_klass(**kwargs)
):
base_klass = IA5String
+ def text_alphabet(self):
+ return "".join(six_unichr(c) for c in six_xrange(128))
+
+ @given(integers(min_value=128, max_value=255))
+ def test_alphabet_bad(self, code):
+ with self.assertRaises(DecodeError):
+ self.base_klass().decod(
+ self.base_klass.tag_default +
+ len_encode(1) +
+ bytes(bytearray([code])),
+ )
+
class TestGraphicString(
UnicodeDecodeErrorMixin,
):
base_klass = VisibleString
+ def text_alphabet(self):
+ return " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
+
def test_x690_vector(self):
obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
self.assertSequenceEqual(tail, b"")
self.assertTrue(obj.lenindef)
self.assertTrue(obj.bered)
+ @given(one_of((
+ integers(min_value=0, max_value=ord(" ") - 1),
+ integers(min_value=ord("~") + 1, max_value=255),
+ )))
+ def test_alphabet_bad(self, code):
+ with self.assertRaises(DecodeError):
+ self.base_klass().decod(
+ self.base_klass.tag_default +
+ len_encode(1) +
+ bytes(bytearray([code])),
+ )
+
+ @given(
+ sets(integers(min_value=0, max_value=10), min_size=2, max_size=2),
+ integers(min_value=0),
+ decode_path_strat,
+ )
+ def test_invalid_bounds_while_decoding(self, ints, offset, decode_path):
+ value, bound_min = list(sorted(ints))
+
+ class String(self.base_klass):
+ bounds = (bound_min, bound_min)
+ with self.assertRaises(DecodeError) as err:
+ String().decode(
+ self.base_klass(b"1" * value).encode(),
+ offset=offset,
+ decode_path=decode_path,
+ )
+ repr(err.exception)
+ self.assertEqual(err.exception.offset, offset)
+ self.assertEqual(err.exception.decode_path, decode_path)
+
class TestGeneralString(
UnicodeDecodeErrorMixin,
mktime(obj.todatetime().timetuple()),
mktime(dt.timetuple()),
)
- elif not PY2:
- self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
+ else:
+ try:
+ obj.todatetime().timestamp()
+ except:
+ pass
+ else:
+ self.assertEqual(obj.todatetime().timestamp(), dt.timestamp())
self.assertEqual(obj.ber_encoded, not dered)
self.assertEqual(obj.bered, not dered)
self.assertEqual(obj.ber_raw, None if dered else data)
with self.assertRaises(DecodeError):
GeneralizedTime(data)
+ def test_aware(self):
+ with assertRaisesRegex(self, ValueError, "only naive"):
+ GeneralizedTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
+
class TestUTCTime(TimeMixin, CommonMixin, TestCase):
base_klass = UTCTime
junk
)
+ def test_aware(self):
+ with assertRaisesRegex(self, ValueError, "only naive"):
+ UTCTime(datetime(2000, 1, 1, 1, tzinfo=UTC))
+
@composite
def tlv_value_strategy(draw):
max_size=len(_schema),
))]
+ class Wahl(Choice):
+ schema = (("int", Integer()),)
+
class SeqWithoutDefault(self.base_klass):
schema = [
- (n, Integer(impl=t))
+ (n, Wahl(expl=t))
for (n, _), t in zip(_schema, tags)
]
seq_without_default = SeqWithoutDefault()
for name, value in _schema:
- seq_without_default[name] = Integer(value)
+ seq_without_default[name] = Wahl(("int", Integer(value)))
seq_encoded = seq_without_default.encode()
+ seq_without_default.decode(seq_encoded)
+ self.assertEqual(
+ len(list(seq_without_default.decode_evgen(seq_encoded))),
+ len(_schema) * 2 + 1,
+ )
class SeqWithDefault(self.base_klass):
schema = [
- (n, Integer(default=v, impl=t))
+ (n, Wahl(default=Wahl(("int", Integer(v))), expl=t))
for (n, v), t in zip(_schema, tags)
]
seq_with_default = SeqWithDefault()
with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
seq_with_default.decode(seq_encoded)
+ with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+ list(seq_with_default.decode_evgen(seq_encoded))
for ctx in ({"bered": True}, {"allow_default_values": True}):
seq_decoded, _ = seq_with_default.decode(seq_encoded, ctx=ctx)
self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
for name, value in _schema:
self.assertEqual(seq_decoded[name], seq_with_default[name])
- self.assertEqual(seq_decoded[name], value)
+ self.assertEqual(seq_decoded[name].value, value)
+ self.assertEqual(
+ len(list(seq_with_default.decode_evgen(seq_encoded, ctx=ctx))),
+ len(_schema) + 1,
+ )
+
+ seq_without_default = SeqWithoutDefault()
+ for name, value in _schema:
+ seq_without_default[name] = Wahl(("int", Integer(value + 1)))
+ seq_encoded = seq_without_default.encode()
+ seq_with_default.decode(seq_encoded)
+ self.assertEqual(
+ len(list(seq_with_default.decode_evgen(seq_encoded))),
+ len(_schema) + 1,
+ )
@given(data_strategy())
def test_missing_from_spec(self, d):
seq_missing = SeqMissing()
with self.assertRaises(TagMismatch):
seq_missing.decode(seq_encoded)
+ with self.assertRaises(TagMismatch):
+ list(seq_missing.decode_evgen(seq_encoded))
def test_bered(self):
class Seq(self.base_klass):
encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
with self.assertRaises(DecodeError):
Seq().decode(encoded)
+ with self.assertRaises(DecodeError):
+ list(Seq().decode_evgen(encoded))
+ list(Seq().decode_evgen(encoded, ctx={"bered": True}))
decoded, _ = Seq().decode(encoded, ctx={"bered": True})
self.assertFalse(decoded.ber_encoded)
self.assertFalse(decoded.lenindef)
schema = Integer()
bounds = (10, 20)
seqof = None
+
def gen(n):
for i in six_xrange(n):
yield Integer(i)
class SeqOf(SequenceOf):
schema = Integer()
bounds = (1, float("+inf"))
+
def gen():
for i in six_xrange(10):
yield Integer(i)
class SeqOf(SequenceOf):
schema = Integer()
bounds = (1, float("+inf"))
+
def gen():
for i in six_xrange(10):
yield Integer(i)
def test_remaining_data(self):
oid = ObjectIdentifier("1.2.3")
+
class Seq(Sequence):
schema = (
("oid", ObjectIdentifier(defines=((("tgt",), {
def test_remaining_data_seqof(self):
oid = ObjectIdentifier("1.2.3")
+
class SeqOf(SetOf):
schema = OctetString()