::
- 52-2∞ [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
- ^ ^ ^ ^
- 12 13 9 10
+ 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
+ ^ ^ ^ ^ ^
+ 12 13 14 9 10
:0:
Offset of the object, where its DER/BER encoding begins.
Possible other flags like OPTIONAL and DEFAULT, if value equals to the
default one, specified in the schema.
:12:
- Only applicable to BER encoded data. Indefinite length encoding mark.
+ Shows does object contains any kind of BER encoded data (possibly
+ Sequence holding BER-encoded underlying value).
:13:
+ Only applicable to BER encoded data. Indefinite length encoding mark.
+:14:
Only applicable to BER encoded data. If object has BER-specific
encoding, then ``BER`` will be shown. It does not depend on indefinite
length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
News
====
+.. _release4.1:
+
+4.1
+---
+* ``bered`` attribute, meaning if object has BER-specific encoding, is
+ renamed to ``ber_encoded``
+* ``bered`` attribute is replace with property showing if any of
+ underlying values are BER-encoded. If value has length indefinite
+ encoded explicit tag, value, if value contains BER-related encoding,
+ or if it contains other objects that are ``bered``, then it is ``bered``
+
.. _release4.0:
4.0
:ref:`context <ctx>` argument to True. Indefinite lengths and
constructed primitive types should be parsed successfully.
-* If object is encoded in BER form (not the DER one), then ``bered``
+* If object is encoded in BER form (not the DER one), then ``ber_encoded``
attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
STRING``, ``SEQUENCE``, ``SET``, ``SET OF`` can contain it.
* If object has an indefinite length encoding, then its ``lenindef``
contain it.
* If object has an indefinite length encoded explicit tag, then
``expl_lenindef`` is set to True.
+* If object has either any of BER-related encoding (explicit tag
+ indefinite length, object's indefinite length, BER-encoding) or any
+ underlying component has that kind of encoding, then ``bered``
+ attribute is set to True. For example SignedData CMS can have
+ ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
+ ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
EOC (end-of-contents) token's length is taken in advance in object's
value length.
"vlen",
"expl_lenindef",
"lenindef",
- "bered",
+ "ber_encoded",
)
def __init__(
self.default = None
self.expl_lenindef = False
self.lenindef = False
- self.bered = False
+ self.ber_encoded = False
@property
def ready(self): # pragma: no cover
"""
raise NotImplementedError()
+ @property
+ def bered(self):
+ """Is either object or any elements inside is BER encoded?
+ """
+ return self.expl_lenindef or self.lenindef or self.ber_encoded
+
def _assert_ready(self):
if not self.ready:
raise ObjNotReady(self.__class__.__name__)
tlen=1,
llen=1,
vlen=0,
+ ber_encoded=True,
bered=True,
)
if self.expl_lenindef:
tlen=1,
llen=1,
vlen=0,
+ ber_encoded=True,
bered=True,
)
"expl_vlen",
"expl_lenindef",
"lenindef",
+ "ber_encoded",
"bered",
))
expl_vlen=None,
expl_lenindef=False,
lenindef=False,
+ ber_encoded=False,
bered=False,
):
return PP(
expl_vlen,
expl_lenindef,
lenindef,
+ ber_encoded,
bered,
)
),
LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
)
- cols.append(_colourize(col, "red", with_colours, ()))
+ col = _colourize(col, "red", with_colours, ())
+ col += _colourize("B", "red", with_colours) if pp.bered else " "
+ cols.append(col)
col = "[%d,%d,%4d]%s" % (
pp.tlen,
pp.llen,
cols.append(_colourize(col, "blue", with_colours))
if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
cols.append(_colourize(pp.obj_name, "magenta", with_colours))
- if pp.bered:
+ if pp.ber_encoded:
cols.append(_colourize("BER", "red", with_colours))
cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
if pp.value is not None:
def pp_console_blob(pp, decode_path_len_decrease=0):
- cols = [" " * len("XXXXXYYZ [X,X,XXXX]Z")]
+ cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
decode_path_len = len(pp.decode_path) - decode_path_len_decrease
if decode_path_len > 0:
cols.append(" ." * (decode_path_len + 1))
offset=offset,
)
first_octet = byte2int(v)
- bered = False
+ ber_encoded = False
if first_octet == 0:
value = False
elif first_octet == 0xFF:
value = True
elif ctx.get("bered", False):
value = True
- bered = True
+ ber_encoded = True
else:
raise DecodeError(
"unacceptable Boolean value",
optional=self.optional,
_decoded=(offset, 1, 1),
)
- obj.bered = bered
+ obj.ber_encoded = ber_encoded
return obj, v[1:]
def __repr__(self):
expl_llen=self.expl_llen if self.expled else None,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
+ ber_encoded=self.ber_encoded,
bered=self.bered,
)
for pp in self.pps_lenindef(decode_path):
expl_llen=self.expl_llen if self.expled else None,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
+ bered=self.bered,
)
for pp in self.pps_lenindef(decode_path):
yield pp
_decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
)
obj.lenindef = lenindef
- obj.bered = True
+ obj.ber_encoded = True
return obj, (v[EOC_LEN:] if lenindef else v)
raise TagMismatch(
klass=self.__class__,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
+ ber_encoded=self.ber_encoded,
bered=self.bered,
)
defined_by, defined = self.defined or (None, None)
offset=offset,
)
obj.lenindef = lenindef
- obj.bered = True
+ obj.ber_encoded = True
return obj, (v[EOC_LEN:] if lenindef else v)
raise TagMismatch(
klass=self.__class__,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
+ ber_encoded=self.ber_encoded,
bered=self.bered,
)
defined_by, defined = self.defined or (None, None)
expl_llen=self.expl_llen if self.expled else None,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
+ bered=self.bered,
)
for pp in self.pps_lenindef(decode_path):
yield pp
expl_llen=self.expl_llen if self.expled else None,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
+ bered=self.bered,
)
for pp in self.pps_lenindef(decode_path):
yield pp
expl_llen=self.expl_llen if self.expled else None,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
+ ber_encoded=self.ber_encoded,
+ bered=self.bered,
)
for pp in self.pps_lenindef(decode_path):
yield pp
expl_llen=self.expl_llen if self.expled else None,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
+ ber_encoded=self.ber_encoded,
+ bered=self.bered,
)
for pp in self.pps_lenindef(decode_path):
yield pp
def ready(self):
return self._value is not None and self._value[1].ready
+ @property
+ def bered(self):
+ return self.expl_lenindef or (
+ (self._value is not None) and
+ self._value[1].bered
+ )
+
def copy(self):
obj = self.__class__(schema=self.specs)
obj._expl = self._expl
)
obj._value = (choice, value)
obj.lenindef = value.lenindef
- obj.bered = value.bered
+ obj.ber_encoded = value.ber_encoded
return obj, tail
def __repr__(self):
vlen=self.vlen,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
+ ber_encoded=self.ber_encoded,
bered=self.bered,
)
if self.ready:
def ready(self):
return self._value is not None
+ @property
+ def bered(self):
+ if self.expl_lenindef or self.lenindef:
+ return True
+ if self.defined is None:
+ return False
+ return self.defined[1].bered
+
def copy(self):
obj = self.__class__()
obj._value = self._value
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
+ bered=self.bered,
)
defined_by, defined = self.defined or (None, None)
if defined_by is not None:
return False
return True
+ @property
+ def bered(self):
+ if self.expl_lenindef or self.lenindef or self.ber_encoded:
+ return True
+ return any(value.bered for value in self._value.values())
+
def copy(self):
obj = self.__class__(schema=self.specs)
obj.tag = self.tag
vlen = 0
sub_offset = offset + tlen + llen
values = {}
- bered = False
+ ber_encoded = False
ctx_allow_default_values = ctx.get("allow_default_values", False)
for name, spec in self.specs.items():
if spec.optional and (
v = v_tail
if spec.default is not None and value == spec.default:
if ctx_bered or ctx_allow_default_values:
- bered = True
+ ber_encoded = True
else:
raise DecodeError(
"DEFAULT value met",
)
obj._value = values
obj.lenindef = lenindef
- obj.bered = bered
+ obj.ber_encoded = ber_encoded
return obj, tail
def __repr__(self):
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
+ ber_encoded=self.ber_encoded,
+ bered=self.bered,
)
for name in self.specs:
value = self._value.get(name)
vlen = 0
sub_offset = offset + tlen + llen
values = {}
- bered = False
+ ber_encoded = False
ctx_allow_default_values = ctx.get("allow_default_values", False)
ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
value_prev = memoryview(v[:0])
value_len = value.fulllen
if value_prev.tobytes() > v[:value_len].tobytes():
if ctx_bered or ctx_allow_unordered_set:
- bered = True
+ ber_encoded = True
else:
raise DecodeError(
"unordered " + self.asn1_type_name,
if spec.default is None or value != spec.default:
pass
elif ctx_bered or ctx_allow_default_values:
- bered = True
+ ber_encoded = True
else:
raise DecodeError(
"DEFAULT value met",
decode_path=decode_path,
offset=offset,
)
- obj.bered = bered
+ obj.ber_encoded = ber_encoded
return obj, tail
def ready(self):
return all(v.ready for v in self._value)
+ @property
+ def bered(self):
+ if self.expl_lenindef or self.lenindef or self.ber_encoded:
+ return True
+ return any(v.bered for v in self._value)
+
def copy(self):
obj = self.__class__(schema=self.spec)
obj._bound_min = self._bound_min
_value = []
ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
value_prev = memoryview(v[:0])
- bered = False
+ ber_encoded = False
spec = self.spec
while len(v) > 0:
if lenindef and v[:EOC_LEN].tobytes() == EOC:
if ordering_check:
if value_prev.tobytes() > v[:value_len].tobytes():
if ctx_bered or ctx_allow_unordered_set:
- bered = True
+ ber_encoded = True
else:
raise DecodeError(
"unordered " + self.asn1_type_name,
)
obj.lenindef = True
tail = v[EOC_LEN:]
- obj.bered = bered
+ obj.ber_encoded = ber_encoded
return obj, tail
def __repr__(self):
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
+ ber_encoded=self.ber_encoded,
+ bered=self.bered,
)
for i, value in enumerate(self._value):
yield value.pps(decode_path=decode_path + (str(i),))
ctx={"bered": True},
)
self.assertTrue(bool(obj))
- self.assertTrue(obj.bered)
+ self.assertTrue(obj.ber_encoded)
self.assertFalse(obj.lenindef)
+ self.assertTrue(obj.bered)
@given(
integers(min_value=1).map(tag_ctxc),
ctx={"bered": True},
)
self.assertTrue(obj.expl_lenindef)
+ self.assertFalse(obj.lenindef)
+ self.assertFalse(obj.ber_encoded)
+ self.assertTrue(obj.bered)
self.assertSequenceEqual(tail, junk)
@given(
v.expl_tlvlen,
v.expl_tlen,
v.expl_llen,
- v.bered,
+ v.ber_encoded,
v.lenindef,
v.expl_lenindef,
+ v.bered,
) for v in seqof
),
set(((
False,
False,
True,
+ True,
),)),
)
self.assertSequenceEqual(tail, junk)
self.assertEqual(obj.bit_len, bit_len_expected)
self.assertSequenceEqual(bytes(obj), payload_expected)
- self.assertTrue(obj.bered)
+ self.assertTrue(obj.ber_encoded)
self.assertEqual(obj.lenindef, lenindef_expected)
+ self.assertTrue(obj.bered)
self.assertEqual(len(encoded), obj.tlvlen)
@given(
)
self.assertSequenceEqual(tail, b"")
self.assertEqual(obj, vector)
- self.assertTrue(obj.bered)
+ self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.lenindef)
+ self.assertTrue(obj.bered)
@composite
)
self.assertSequenceEqual(tail, junk)
self.assertSequenceEqual(bytes(obj), payload_expected)
- self.assertTrue(obj.bered)
+ self.assertTrue(obj.ber_encoded)
self.assertEqual(obj.lenindef, lenindef_expected)
+ self.assertTrue(obj.bered)
self.assertEqual(len(encoded), obj.tlvlen)
@given(
obj, tail = VisibleString().decode(hexdec("1A054A6F6E6573"))
self.assertSequenceEqual(tail, b"")
self.assertEqual(str(obj), "Jones")
- self.assertFalse(obj.bered)
+ self.assertFalse(obj.ber_encoded)
self.assertFalse(obj.lenindef)
+ self.assertFalse(obj.bered)
obj, tail = VisibleString().decode(
hexdec("3A0904034A6F6E04026573"),
)
self.assertSequenceEqual(tail, b"")
self.assertEqual(str(obj), "Jones")
- self.assertTrue(obj.bered)
+ self.assertTrue(obj.ber_encoded)
self.assertFalse(obj.lenindef)
+ self.assertTrue(obj.bered)
obj, tail = VisibleString().decode(
hexdec("3A8004034A6F6E040265730000"),
)
self.assertSequenceEqual(tail, b"")
self.assertEqual(str(obj), "Jones")
- self.assertTrue(obj.bered)
+ self.assertTrue(obj.ber_encoded)
self.assertTrue(obj.lenindef)
+ self.assertTrue(obj.bered)
class TestGeneralString(
self.assertSequenceEqual(tail, junk)
self.assertEqual(obj.offset, offset)
self.assertEqual(obj.tlvlen, len(encoded))
+ self.assertTrue(obj.lenindef)
+ self.assertFalse(obj.ber_encoded)
+ self.assertTrue(obj.bered)
with self.assertRaises(NotEnoughData) as err:
Any().decode(
encoded[:-1],
seq_encoded = seq.encode()
seq_decoded, tail = seq.decode(seq_encoded + tail_junk)
self.assertFalse(seq_decoded.lenindef)
+ self.assertFalse(seq_decoded.ber_encoded)
self.assertFalse(seq_decoded.bered)
t, _, lv = tag_strip(seq_encoded)
ctx={"bered": True},
)
self.assertTrue(seq_decoded_lenindef.lenindef)
+ self.assertTrue(seq_decoded_lenindef.bered)
with self.assertRaises(DecodeError):
seq.decode(seq_encoded_lenindef[:-1], ctx={"bered": True})
with self.assertRaises(DecodeError):
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.ber_encoded)
self.assertTrue(seq_decoded.bered)
for name, value in _schema:
self.assertEqual(seq_decoded[name], seq_with_default[name])
with self.assertRaises(TagMismatch):
seq_missing.decode(seq_encoded)
+ @given(data_strategy())
+ def test_bered(self, d):
+ class Seq(self.base_klass):
+ schema = (("underlying", Boolean()),)
+ encoded = Boolean.tag_default + len_encode(1) + b"\x01"
+ encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
+ decoded, _ = Seq().decode(encoded, ctx={"bered": True})
+ self.assertFalse(decoded.ber_encoded)
+ self.assertFalse(decoded.lenindef)
+ self.assertTrue(decoded.bered)
+
+ class Seq(self.base_klass):
+ schema = (("underlying", OctetString()),)
+ encoded = (
+ tag_encode(form=TagFormConstructed, num=4) +
+ LENINDEF +
+ OctetString(b"whatever").encode() +
+ EOC
+ )
+ encoded = Seq.tag_default + len_encode(len(encoded)) + encoded
+ decoded, _ = Seq().decode(encoded, ctx={"bered": True})
+ self.assertFalse(decoded.ber_encoded)
+ self.assertFalse(decoded.lenindef)
+ self.assertTrue(decoded.bered)
+
class TestSequence(SeqMixing, CommonMixin, TestCase):
base_klass = Sequence
seq.decode(seq_encoded)
for ctx in ({"bered": True}, {"allow_unordered_set": True}):
seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
+ self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
self.assertSequenceEqual(
[bytes(seq_decoded[str(i)]) for i, t in enumerate(tags)],
ctx={"bered": True},
)
self.assertTrue(obj_decoded_lenindef.lenindef)
+ self.assertTrue(obj_decoded_lenindef.bered)
repr(obj_decoded_lenindef)
pprint(obj_decoded_lenindef)
self.assertEqual(obj_decoded_lenindef.tlvlen, len(obj_encoded_lenindef))
with self.assertRaises(DecodeError):
obj.decode(obj_encoded_lenindef[:-2], ctx={"bered": True})
+ @given(data_strategy())
+ def test_bered(self, d):
+ class SeqOf(self.base_klass):
+ schema = Boolean()
+ encoded = Boolean(False).encode()
+ encoded += Boolean.tag_default + len_encode(1) + b"\x01"
+ encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
+ decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
+ self.assertFalse(decoded.ber_encoded)
+ self.assertFalse(decoded.lenindef)
+ self.assertTrue(decoded.bered)
+
+ class SeqOf(self.base_klass):
+ schema = OctetString()
+ encoded = OctetString(b"whatever").encode()
+ encoded += (
+ tag_encode(form=TagFormConstructed, num=4) +
+ LENINDEF +
+ OctetString(b"whatever").encode() +
+ EOC
+ )
+ encoded = SeqOf.tag_default + len_encode(len(encoded)) + encoded
+ decoded, _ = SeqOf().decode(encoded, ctx={"bered": True})
+ self.assertFalse(decoded.ber_encoded)
+ self.assertFalse(decoded.lenindef)
+ self.assertTrue(decoded.bered)
+
class TestSequenceOf(SeqOfMixing, CommonMixin, TestCase):
class SeqOf(SequenceOf):
for ctx in ({"bered": True}, {"allow_unordered_set": True}):
seq_decoded, _ = Seq().decode(seq_encoded, ctx=ctx)
+ self.assertTrue(seq_decoded.ber_encoded)
self.assertTrue(seq_decoded.bered)
self.assertSequenceEqual(
[obj.encode() for obj in seq_decoded],
with assertRaisesRegex(self, DecodeError, "DEFAULT value met"):
seq.decode(raw)
decoded, _ = seq.decode(raw, ctx={"allow_default_values": True})
+ self.assertTrue(decoded.ber_encoded)
self.assertTrue(decoded.bered)
decoded, _ = seq.decode(raw, ctx={"bered": True})
+ self.assertTrue(decoded.ber_encoded)
self.assertTrue(decoded.bered)