summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Matveev <stargrave@stargrave.org>2018-09-10 17:45:55 +0300
committerSergey Matveev <stargrave@stargrave.org>2018-09-10 21:27:45 +0300
commit2dc06a21fd4bd1e52bbea125ef744d58fc0d17bf (patch)
treeb129e50bd1a4189c418d17c0e403ef4f3fdc3a48
parentcb9ebe2012c619dea2633b00427898312801a840 (diff)
downloadpyderasn-2dc06a21fd4bd1e52bbea125ef744d58fc0d17bf.tar.xz
Defaulted values are checked by default
-rw-r--r--VERSION2
-rw-r--r--doc/news.rst11
-rwxr-xr-xpyderasn.py62
-rw-r--r--tests/test_pyderasn.py22
4 files changed, 56 insertions, 41 deletions
diff --git a/VERSION b/VERSION
index 93a848f..5186d07 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.15
+4.0
diff --git a/doc/news.rst b/doc/news.rst
index 4224b3d..d0f156f 100644
--- a/doc/news.rst
+++ b/doc/news.rst
@@ -1,11 +1,14 @@
News
====
-.. _release3.15:
+.. _release4.0:
-3.15
-----
-* DEFAULT-encoded value is checked also for Set-s, not for Sequences only
+4.0
+---
+* Default value is checked also for Sets, not for Sequences only
+* **Incompatible** change: defaulted values in Sequence/Set are always
+ strictly checked, unless ``allow_default_values`` context option is
+ set. ``strict_default_existence`` option disappeared
.. _release3.14:
diff --git a/pyderasn.py b/pyderasn.py
index 7edfc80..a773296 100755
--- a/pyderasn.py
+++ b/pyderasn.py
@@ -213,10 +213,10 @@ decoding process.
Currently available context options:
+* :ref:`allow_default_values <allow_default_values_ctx>`
* :ref:`allow_expl_oob <allow_expl_oob_ctx>`
* :ref:`bered <bered_ctx>`
* :ref:`defines_by_path <defines_by_path_ctx>`
-* :ref:`strict_default_existence <strict_default_existence_ctx>`
.. _pprinting:
@@ -383,7 +383,7 @@ constructed primitive types should be parsed successfully.
* If object is encoded in BER form (not the DER one), then ``bered``
attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
- STRING`` can contain it.
+ STRING``, ``SEQUENCE``, ``SET`` can contain it.
* If object has an indefinite length encoding, then its ``lenindef``
attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
@@ -4338,18 +4338,14 @@ class Sequence(Obj):
All defaulted values are always optional.
- .. _strict_default_existence_ctx:
+ .. _allow_default_values_ctx:
- .. warning::
-
- When decoded DER contains defaulted value inside, then
- technically this is not valid DER encoding. But we allow and pass
- it **by default**. Of course reencoding of that kind of DER will
- result in different binary representation (validly without
- defaulted value inside). You can enable strict defaulted values
- existence validation by setting ``"strict_default_existence":
- True`` :ref:`context <ctx>` option -- decoding process will raise
- an exception if defaulted value is met.
+ DER prohibits default value encoding and will raise an error if
+ default value is unexpectedly met during decode.
+ If :ref:`bered <bered_ctx>` context option is set, then no error
+ will be raised, but ``bered`` attribute set. You can disable strict
+ defaulted values existence validation by setting
+ ``"allow_default_values": True`` :ref:`context <ctx>` option.
Two sequences are equal if they have equal specification (schema),
implicit/explicit tagging and the same values.
@@ -4509,10 +4505,11 @@ class Sequence(Obj):
if tag_only:
return
lenindef = False
+ ctx_bered = ctx.get("bered", False)
try:
l, llen, v = len_decode(lv)
except LenIndefForm as err:
- if not ctx.get("bered", False):
+ if not ctx_bered:
raise err.__class__(
msg=err.msg,
klass=self.__class__,
@@ -4540,6 +4537,8 @@ class Sequence(Obj):
vlen = 0
sub_offset = offset + tlen + llen
values = {}
+ bered = False
+ ctx_allow_default_values = ctx.get("allow_default_values", False)
for name, spec in self.specs.items():
if spec.optional and (
(lenindef and v[:EOC_LEN].tobytes() == EOC) or
@@ -4612,15 +4611,15 @@ class Sequence(Obj):
sub_offset += value_len
v = v_tail
if spec.default is not None and value == spec.default:
- if ctx.get("strict_default_existence", False):
+ if ctx_bered or ctx_allow_default_values:
+ bered = True
+ else:
raise DecodeError(
"DEFAULT value met",
klass=self.__class__,
decode_path=sub_decode_path,
offset=sub_offset,
)
- else:
- continue
values[name] = value
spec_defines = getattr(spec, "defines", ())
@@ -4663,6 +4662,7 @@ class Sequence(Obj):
)
obj._value = values
obj.lenindef = lenindef
+ obj.bered = bered
return obj, tail
def __repr__(self):
@@ -4738,10 +4738,11 @@ class Set(Sequence):
if tag_only:
return
lenindef = False
+ ctx_bered = ctx.get("bered", False)
try:
l, llen, v = len_decode(lv)
except LenIndefForm as err:
- if not ctx.get("bered", False):
+ if not ctx_bered:
raise err.__class__(
msg=err.msg,
klass=self.__class__,
@@ -4768,6 +4769,8 @@ class Set(Sequence):
vlen = 0
sub_offset = offset + tlen + llen
values = {}
+ bered = False
+ ctx_allow_default_values = ctx.get("allow_default_values", False)
specs_items = self.specs.items
while len(v) > 0:
if lenindef and v[:EOC_LEN].tobytes() == EOC:
@@ -4803,18 +4806,18 @@ class Set(Sequence):
sub_offset += value_len
vlen += value_len
v = v_tail
- if spec.default is None:
- values[name] = value
+ if spec.default is None or value != spec.default:
+ pass
+ elif ctx_bered or ctx_allow_default_values:
+ bered = True
else:
- if value != spec.default:
- values[name] = value
- if ctx.get("strict_default_existence", False):
- raise DecodeError(
- "DEFAULT value met",
- klass=self.__class__,
- decode_path=sub_decode_path,
- offset=sub_offset,
- )
+ raise DecodeError(
+ "DEFAULT value met",
+ klass=self.__class__,
+ decode_path=sub_decode_path,
+ offset=sub_offset,
+ )
+ values[name] = value
obj = self.__class__(
schema=self.specs,
impl=self.tag,
@@ -4824,6 +4827,7 @@ class Set(Sequence):
_decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
)
obj._value = values
+ obj.bered = bered
if lenindef:
if v[:EOC_LEN].tobytes() != EOC:
raise DecodeError(
diff --git a/tests/test_pyderasn.py b/tests/test_pyderasn.py
index 7b397f2..c8321bb 100644
--- a/tests/test_pyderasn.py
+++ b/tests/test_pyderasn.py
@@ -4749,6 +4749,7 @@ class SeqMixing(object):
seq_encoded = seq.encode()
seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
self.assertFalse(seq_decoded.lenindef)
+ self.assertFalse(seq_decoded.bered)
t, _, lv = tag_strip(seq_encoded)
_, _, v = len_decode(lv)
@@ -4840,7 +4841,7 @@ class SeqMixing(object):
self.assertSequenceEqual(seq.encode(), empty_seq)
@given(data_strategy())
- def test_encoded_default_accepted(self, d):
+ def test_encoded_default_not_accepted(self, d):
_schema = list(d.draw(dictionaries(
text_letters(),
integers(),
@@ -4868,10 +4869,14 @@ class SeqMixing(object):
for (n, v), t in zip(_schema, tags)
]
seq_with_default = SeqWithDefault()
- seq_decoded, _ = seq_with_default.decode(seq_encoded)
- for name, value in _schema:
- self.assertEqual(seq_decoded[name], seq_with_default[name])
- self.assertEqual(seq_decoded[name], value)
+ with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
+ seq_with_default.decode(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.bered)
+ for name, value in _schema:
+ self.assertEqual(seq_decoded[name], seq_with_default[name])
+ self.assertEqual(seq_decoded[name], value)
@given(data_strategy())
def test_missing_from_spec(self, d):
@@ -5880,9 +5885,12 @@ class TestStrictDefaultExistence(TestCase):
raw = seq.encode()
chosen_choice = "int%d" % chosen
seq.specs[chosen_choice] = seq.specs[chosen_choice](default=123)
- seq.decode(raw)
with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
- seq.decode(raw, ctx={"strict_default_existence": True})
+ seq.decode(raw)
+ decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
+ self.assertTrue(decoded.bered)
+ decoded, _ = seq.decode(raw, ctx={"bered": True})
+ self.assertTrue(decoded.bered)
class TestX690PrefixedType(TestCase):