#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
:ref:`context <ctx>` argument to True. Indefinite lengths and
constructed primitive types should be parsed successfully.
:ref:`context <ctx>` argument to True. Indefinite lengths and
constructed primitive types should be parsed successfully.
- STRING``, ``SEQUENCE``, ``SET`` can contain it.
+ STRING``, ``SEQUENCE``, ``SET``, ``SET OF`` 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
contain it.
* If object has an indefinite length encoded explicit tag, then
``expl_lenindef`` is set to True.
* 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
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.
.. autofunction:: pyderasn.hexenc
.. autofunction:: pyderasn.hexdec
.. autofunction:: pyderasn.tag_encode
.. autofunction:: pyderasn.hexenc
.. autofunction:: pyderasn.hexdec
.. autofunction:: pyderasn.tag_encode
from codecs import getencoder
from collections import namedtuple
from collections import OrderedDict
from codecs import getencoder
from collections import namedtuple
from collections import OrderedDict
def __init__(self, msg="", klass=None, decode_path=(), offset=0):
"""
:param str msg: reason of decode failing
def __init__(self, msg="", klass=None, decode_path=(), offset=0):
"""
:param str msg: reason of decode failing
def __init__(self, name):
super(ObjUnknown, self).__init__()
self.name = name
def __init__(self, name):
super(ObjUnknown, self).__init__()
self.name = name
def __init__(self, name):
super(ObjNotReady, self).__init__()
self.name = name
def __init__(self, name):
super(ObjNotReady, self).__init__()
self.name = name
def __init__(self, expected_types):
super(InvalidValueType, self).__init__()
self.expected_types = expected_types
def __init__(self, expected_types):
super(InvalidValueType, self).__init__()
self.expected_types = expected_types
def __init__(self, bound_min, value, bound_max):
super(BoundsError, self).__init__()
self.bound_min = bound_min
def __init__(self, bound_min, value, bound_max):
super(BoundsError, self).__init__()
self.bound_min = bound_min
:param int offset: initial data's offset
:param bool leavemm: do we need to leave memoryview of remaining
data as is, or convert it to bytes otherwise
:param int offset: initial data's offset
:param bool leavemm: do we need to leave memoryview of remaining
data as is, or convert it to bytes otherwise
:param tag_only: decode only the tag, without length and contents
(used only in Choice and Set structures, trying to
determine if tag satisfies the scheme)
:param tag_only: decode only the tag, without length and contents
(used only in Choice and Set structures, trying to
determine if tag satisfies the scheme)
return self.expl_tlvlen if self.expled else self.tlvlen
def pps_lenindef(self, decode_path):
return self.expl_tlvlen if self.expled else self.tlvlen
def pps_lenindef(self, decode_path):
- 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)
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))
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))
cols.append(_colourize("BER", "red", with_colours))
cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
if pp.value is not None:
cols.append(_colourize("BER", "red", with_colours))
cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
if pp.value is not None:
+ if pp.asn1_type_name == Integer.asn1_type_name:
+ hex_repr = hex(int(pp.obj._value))[2:].upper()
+ if len(hex_repr) % 2 != 0:
+ hex_repr = "0" + hex_repr
+ cols.append(_colourize(
+ "(%s)" % colonize_hex(hex_repr),
+ "green",
+ with_colours,
+ ))
if with_blob:
if isinstance(pp.blob, binary_type):
cols.append(hexenc(pp.blob))
if with_blob:
if isinstance(pp.blob, binary_type):
cols.append(hexenc(pp.blob))
decode_path_len = len(pp.decode_path) - decode_path_len_decrease
if decode_path_len > 0:
cols.append(" ." * (decode_path_len + 1))
decode_path_len = len(pp.decode_path) - decode_path_len_decrease
if decode_path_len > 0:
cols.append(" ." * (decode_path_len + 1))
blob = hexenc(pp.blob).upper()
for i in range(0, len(blob), 32):
chunk = blob[i:i + 32]
blob = hexenc(pp.blob).upper()
for i in range(0, len(blob), 32):
chunk = blob[i:i + 32]
elif isinstance(pp.blob, tuple):
yield " ".join(cols + [", ".join(pp.blob)])
elif isinstance(pp.blob, tuple):
yield " ".join(cols + [", ".join(pp.blob)])
if first_octet == 0:
value = False
elif first_octet == 0xFF:
value = True
elif ctx.get("bered", False):
value = True
if first_octet == 0:
value = False
elif first_octet == 0xFF:
value = True
elif ctx.get("bered", False):
value = True
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=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,
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,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=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,
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,
return
return self._decode_chunk(lv, offset, decode_path, ctx)
if t == self.tag_constructed:
return
return self._decode_chunk(lv, offset, decode_path, ctx)
if t == self.tag_constructed:
_decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
)
obj.lenindef = lenindef
_decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
)
obj.lenindef = lenindef
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=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,
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,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=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,
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,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=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,
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,
-class NumericString(CommonString):
+class AllowableCharsMixin(object):
+ @property
+ def allowable_chars(self):
+ if PY2:
+ return self._allowable_chars
+ return set(six_unichr(c) for c in self._allowable_chars)
+
+
+class NumericString(AllowableCharsMixin, CommonString):
- Its value is properly sanitized: only ASCII digits can be stored.
+ Its value is properly sanitized: only ASCII digits with spaces can
+ be stored.
+
+ >>> NumericString().allowable_chars
+ set(['3', '4', '7', '5', '1', '0', '8', '9', ' ', '6', '2'])
def _value_sanitize(self, value):
value = super(NumericString, self)._value_sanitize(value)
def _value_sanitize(self, value):
value = super(NumericString, self)._value_sanitize(value)
-class PrintableString(CommonString):
+class PrintableString(AllowableCharsMixin, CommonString):
+ """Printable string
+
+ Its value is properly sanitized: see X.680 41.4 table 10.
+
+ >>> PrintableString().allowable_chars
+ >>> set([' ', "'", ..., 'z'])
+ """
+ _allowable_chars = set(
+ (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
+ )
+
+ def _value_sanitize(self, value):
+ value = super(PrintableString, self)._value_sanitize(value)
+ if not set(value) <= self._allowable_chars:
+ raise DecodeError("non-printable value")
+ return value
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=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,
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,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
)
defined_by, defined = self.defined or (None, None)
if defined_by is not None:
)
defined_by, defined = self.defined or (None, None)
if defined_by is not None:
def abs_decode_path(decode_path, rel_path):
"""Create an absolute decode path from current and relative ones
def abs_decode_path(decode_path, rel_path):
"""Create an absolute decode path from current and relative ones
:param rel_path: relative path to ``decode_path``. Tuple of strings.
If first tuple's element is "/", then treat it as
an absolute path, ignoring ``decode_path`` as
:param rel_path: relative path to ``decode_path``. Tuple of strings.
If first tuple's element is "/", then treat it as
an absolute path, ignoring ``decode_path`` as
ctx_allow_default_values = ctx.get("allow_default_values", False)
for name, spec in self.specs.items():
if spec.optional and (
ctx_allow_default_values = ctx.get("allow_default_values", False)
for name, spec in self.specs.items():
if spec.optional and (
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
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])
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:
)
value_len = value.fulllen
if value_prev.tobytes() > v[:value_len].tobytes():
if ctx_bered or ctx_allow_unordered_set:
v = b"".join(self._encoded_values())
return b"".join((self.tag, len_encode(len(v)), v))
v = b"".join(self._encoded_values())
return b"".join((self.tag, len_encode(len(v)), v))
- def _decode(self, tlv, offset, decode_path, ctx, tag_only):
+ def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
try:
t, tlen, lv = tag_strip(tlv)
except DecodeError as err:
try:
t, tlen, lv = tag_strip(tlv)
except DecodeError as err:
try:
l, llen, v = len_decode(lv)
except LenIndefForm as err:
try:
l, llen, v = len_decode(lv)
except LenIndefForm as err:
+ if ordering_check:
+ if value_prev.tobytes() > v[:value_len].tobytes():
+ if ctx_bered or ctx_allow_unordered_set:
+ ber_encoded = True
+ else:
+ raise DecodeError(
+ "unordered " + self.asn1_type_name,
+ klass=self.__class__,
+ decode_path=sub_decode_path,
+ offset=sub_offset,
+ )
+ value_prev = v[:value_len]
+ _value.append(value)
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
asn1_type_name=self.asn1_type_name,
obj_name=self.__class__.__name__,
decode_path=decode_path,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
expl_vlen=self.expl_vlen if self.expled else None,
expl_lenindef=self.expl_lenindef,
lenindef=self.lenindef,
)
for i, value in enumerate(self._value):
yield value.pps(decode_path=decode_path + (str(i),))
)
for i, value in enumerate(self._value):
yield value.pps(decode_path=decode_path + (str(i),))
+ def _decode(self, tlv, offset, decode_path, ctx, tag_only):
+ return super(SetOf, self)._decode(
+ tlv,
+ offset,
+ decode_path,
+ ctx,
+ tag_only,
+ ordering_check=True,
+ )
+