BER encoding
------------
-.. warning::
-
- Currently BER support is not extensively tested.
-
By default PyDERASN accepts only DER encoded data. It always encodes to
DER. But you can optionally enable BER decoding with setting ``bered``
:ref:`context <ctx>` argument to True. Indefinite lengths and
self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
self._expl = getattr(self, "expl", None) if expl is None else expl
if self.tag != self.tag_default and self._expl is not None:
- raise ValueError(
- "implicit and explicit tags can not be set simultaneously"
- )
+ raise ValueError("implicit and explicit tags can not be set simultaneously")
if default is not None:
optional = True
self.optional = optional
eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
if eoc_expected.tobytes() != EOC:
raise DecodeError(
- msg="no EOC",
+ "no EOC",
+ klass=self.__class__,
decode_path=decode_path,
offset=offset,
)
len(value) * 4,
hexdec(value + ("" if len(value) % 2 == 0 else "0")),
)
- else:
- raise InvalidValueType((self.__class__, string_types, binary_type))
- elif isinstance(value, binary_type):
+ if isinstance(value, binary_type):
return (len(value) * 8, value)
else:
raise InvalidValueType((self.__class__, string_types, binary_type))
if t == self.tag_constructed:
if not ctx.get("bered", False):
raise DecodeError(
- msg="unallowed BER constructed encoding",
+ "unallowed BER constructed encoding",
+ klass=self.__class__,
decode_path=decode_path,
offset=offset,
)
decode_path=decode_path,
offset=offset,
)
- if l > 0 and l > len(v):
+ if l > len(v):
raise NotEnoughData(
"encoded length is longer than data",
klass=self.__class__,
break
if vlen > l:
raise DecodeError(
- msg="chunk out of bounds",
- decode_path=len(chunks) - 1,
+ "chunk out of bounds",
+ klass=self.__class__,
+ decode_path=decode_path + (str(len(chunks) - 1),),
offset=chunks[-1].offset,
)
sub_decode_path = decode_path + (str(len(chunks)),)
)
except TagMismatch:
raise DecodeError(
- msg="expected BitString encoded chunk",
+ "expected BitString encoded chunk",
+ klass=self.__class__,
decode_path=sub_decode_path,
offset=sub_offset,
)
v = v_tail
if len(chunks) == 0:
raise DecodeError(
- msg="no chunks",
+ "no chunks",
+ klass=self.__class__,
decode_path=decode_path,
offset=offset,
)
for chunk_i, chunk in enumerate(chunks[:-1]):
if chunk.bit_len % 8 != 0:
raise DecodeError(
- msg="BitString chunk is not multiple of 8 bit",
+ "BitString chunk is not multiple of 8 bits",
+ klass=self.__class__,
decode_path=decode_path + (str(chunk_i),),
offset=chunk.offset,
)
if t == self.tag_constructed:
if not ctx.get("bered", False):
raise DecodeError(
- msg="unallowed BER constructed encoding",
+ "unallowed BER constructed encoding",
+ klass=self.__class__,
decode_path=decode_path,
offset=offset,
)
decode_path=decode_path,
offset=offset,
)
- if l > 0 and l > len(v):
+ if l > len(v):
raise NotEnoughData(
"encoded length is longer than data",
klass=self.__class__,
decode_path=decode_path,
offset=offset,
)
- if not lenindef and l == 0:
- raise NotEnoughData(
- "zero length",
- klass=self.__class__,
- decode_path=decode_path,
- offset=offset,
- )
chunks = []
sub_offset = offset + tlen + llen
vlen = 0
break
if vlen > l:
raise DecodeError(
- msg="chunk out of bounds",
- decode_path=len(chunks) - 1,
+ "chunk out of bounds",
+ klass=self.__class__,
+ decode_path=decode_path + (str(len(chunks) - 1),),
offset=chunks[-1].offset,
)
sub_decode_path = decode_path + (str(len(chunks)),)
)
except TagMismatch:
raise DecodeError(
- msg="expected OctetString encoded chunk",
+ "expected OctetString encoded chunk",
+ klass=self.__class__,
decode_path=sub_decode_path,
offset=sub_offset,
)
sub_offset += chunk.tlvlen
vlen += chunk.tlvlen
v = v_tail
- if len(chunks) == 0:
- raise DecodeError(
- msg="no chunks",
- decode_path=decode_path,
- offset=offset,
- )
try:
obj = self.__class__(
value=b"".join(bytes(chunk) for chunk in chunks),
llen, vlen, v = 1, 0, lv[1:]
sub_offset = offset + tlen + llen
chunk_i = 0
- while True:
- if v[:EOC_LEN].tobytes() == EOC:
- tlvlen = tlen + llen + vlen + EOC_LEN
- obj = self.__class__(
- value=tlv[:tlvlen].tobytes(),
- expl=self._expl,
- optional=self.optional,
- _decoded=(offset, 0, tlvlen),
- )
- obj.lenindef = True
- obj.tag = t
- return obj, v[EOC_LEN:]
- else:
- chunk, v = Any().decode(
- v,
- offset=sub_offset,
- decode_path=decode_path + (str(chunk_i),),
- leavemm=True,
- ctx=ctx,
- )
- vlen += chunk.tlvlen
- sub_offset += chunk.tlvlen
- chunk_i += 1
+ while v[:EOC_LEN].tobytes() != EOC:
+ chunk, v = Any().decode(
+ v,
+ offset=sub_offset,
+ decode_path=decode_path + (str(chunk_i),),
+ leavemm=True,
+ ctx=ctx,
+ )
+ vlen += chunk.tlvlen
+ sub_offset += chunk.tlvlen
+ chunk_i += 1
+ tlvlen = tlen + llen + vlen + EOC_LEN
+ obj = self.__class__(
+ value=tlv[:tlvlen].tobytes(),
+ expl=self._expl,
+ optional=self.optional,
+ _decoded=(offset, 0, tlvlen),
+ )
+ obj.lenindef = True
+ obj.tag = t
+ return obj, v[EOC_LEN:]
except DecodeError as err:
raise err.__class__(
msg=err.msg,
_decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
)
obj._value = values
+ if lenindef:
+ if v[:EOC_LEN].tobytes() != EOC:
+ raise DecodeError(
+ "no EOC",
+ klass=self.__class__,
+ decode_path=decode_path,
+ offset=offset,
+ )
+ tail = v[EOC_LEN:]
+ obj.lenindef = True
if not obj.ready:
raise DecodeError(
- msg="not all values are ready",
+ "not all values are ready",
klass=self.__class__,
decode_path=decode_path,
offset=offset,
)
- obj.lenindef = lenindef
- return obj, (v[EOC_LEN:] if lenindef else tail)
+ return obj, tail
class SequenceOf(Obj):
expl=self._expl,
default=self.default,
optional=self.optional,
- _decoded=(offset, llen, vlen),
+ _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
)
- obj.lenindef = lenindef
- return obj, (v[EOC_LEN:] if lenindef else tail)
+ if lenindef:
+ if v[:EOC_LEN].tobytes() != EOC:
+ raise DecodeError(
+ "no EOC",
+ klass=self.__class__,
+ decode_path=decode_path,
+ offset=offset,
+ )
+ obj.lenindef = True
+ tail = v[EOC_LEN:]
+ return obj, tail
def __repr__(self):
return "%s[%s]" % (