3 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
4 # Copyright (C) 2017-2018 Sergey Matveev <stargrave@stargrave.org>
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Lesser General Public License as
8 # published by the Free Software Foundation, either version 3 of the
9 # License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program. If not, see
18 # <http://www.gnu.org/licenses/>.
19 """Python ASN.1 DER/BER codec with abstract structures
21 This library allows you to marshal various structures in ASN.1 DER
22 format, unmarshal them in BER/CER/DER ones.
26 >>> Integer().decode(raw) == i
29 There are primitive types, holding single values
30 (:py:class:`pyderasn.BitString`,
31 :py:class:`pyderasn.Boolean`,
32 :py:class:`pyderasn.Enumerated`,
33 :py:class:`pyderasn.GeneralizedTime`,
34 :py:class:`pyderasn.Integer`,
35 :py:class:`pyderasn.Null`,
36 :py:class:`pyderasn.ObjectIdentifier`,
37 :py:class:`pyderasn.OctetString`,
38 :py:class:`pyderasn.UTCTime`,
39 :py:class:`various strings <pyderasn.CommonString>`
40 (:py:class:`pyderasn.BMPString`,
41 :py:class:`pyderasn.GeneralString`,
42 :py:class:`pyderasn.GraphicString`,
43 :py:class:`pyderasn.IA5String`,
44 :py:class:`pyderasn.ISO646String`,
45 :py:class:`pyderasn.NumericString`,
46 :py:class:`pyderasn.PrintableString`,
47 :py:class:`pyderasn.T61String`,
48 :py:class:`pyderasn.TeletexString`,
49 :py:class:`pyderasn.UniversalString`,
50 :py:class:`pyderasn.UTF8String`,
51 :py:class:`pyderasn.VideotexString`,
52 :py:class:`pyderasn.VisibleString`)),
53 constructed types, holding multiple primitive types
54 (:py:class:`pyderasn.Sequence`,
55 :py:class:`pyderasn.SequenceOf`,
56 :py:class:`pyderasn.Set`,
57 :py:class:`pyderasn.SetOf`),
58 and special types like
59 :py:class:`pyderasn.Any` and
60 :py:class:`pyderasn.Choice`.
68 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
69 the default tag used during coding process. You can override it with
70 either ``IMPLICIT`` (using ``impl`` keyword argument), or
71 ``EXPLICIT`` one (using ``expl`` keyword argument). Both arguments take
72 raw binary string, containing that tag. You can **not** set implicit and
73 explicit tags simultaneously.
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
78 number. Pay attention that explicit tags always have *constructed* tag
79 (``tag_ctxc``), but implicit tags for primitive types are primitive
84 >>> Integer(impl=tag_ctxp(1))
86 >>> Integer(expl=tag_ctxc(2))
89 Implicit tag is not explicitly shown.
91 Two objects of the same type, but with different implicit/explicit tags
94 You can get object's effective tag (either default or implicited) through
95 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
98 >>> tag_decode(tag_ctxc(123))
100 >>> klass, form, num = tag_decode(tag_ctxc(123))
101 >>> klass == TagClassContext
103 >>> form == TagFormConstructed
106 To determine if object has explicit tag, use ``expled`` boolean property
107 and ``expl_tag`` property, returning explicit tag's value.
112 Many objects in sequences could be ``OPTIONAL`` and could have
113 ``DEFAULT`` value. You can specify that object's property using
114 corresponding keyword arguments.
116 >>> Integer(optional=True, default=123)
117 INTEGER 123 OPTIONAL DEFAULT
119 Those specifications do not play any role in primitive value encoding,
120 but are taken into account when dealing with sequences holding them. For
121 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
124 class Version(Integer):
130 class TBSCertificate(Sequence):
132 ("version", Version(expl=tag_ctxc(0), default="v1")),
135 When default argument is used and value is not specified, then it equals
143 Some objects give ability to set value size constraints. This is either
144 possible integer value, or allowed length of various strings and
145 sequences. Constraints are set in the following way::
150 And values satisfaction is checked as: ``MIN <= X <= MAX``.
152 For simplicity you can also set bounds the following way::
154 bounded_x = X(bounds=(MIN, MAX))
156 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
162 All objects have ``ready`` boolean property, that tells if object is
163 ready to be encoded. If that kind of action is performed on unready
164 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
166 All objects have ``copy()`` method, that returns their copy, that can be
174 Decoding is performed using ``decode()`` method. ``offset`` optional
175 argument could be used to set initial object's offset in the binary
176 data, for convenience. It returns decoded object and remaining
177 unmarshalled data (tail). Internally all work is done on
178 ``memoryview(data)``, and you can leave returning tail as a memoryview,
179 by specifying ``leavemm=True`` argument.
181 When object is decoded, ``decoded`` property is true and you can safely
182 use following properties:
184 * ``offset`` -- position including initial offset where object's tag starts
185 * ``tlen`` -- length of object's tag
186 * ``llen`` -- length of object's length value
187 * ``vlen`` -- length of object's value
188 * ``tlvlen`` -- length of the whole object
190 Pay attention that those values do **not** include anything related to
191 explicit tag. If you want to know information about it, then use:
193 * ``expled`` -- to know if explicit tag is set
194 * ``expl_offset`` (it is lesser than ``offset``)
197 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
198 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
200 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
203 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
210 You can specify so called context keyword argument during ``decode()``
211 invocation. It is dictionary containing various options governing
214 Currently available context options:
216 * :ref:`allow_default_values <allow_default_values_ctx>`
217 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
218 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
219 * :ref:`bered <bered_ctx>`
220 * :ref:`defines_by_path <defines_by_path_ctx>`
227 All objects have ``pps()`` method, that is a generator of
228 :py:class:`pyderasn.PP` namedtuple, holding various raw information
229 about the object. If ``pps`` is called on sequences, then all underlying
230 ``PP`` will be yielded.
232 You can use :py:func:`pyderasn.pp_console_row` function, converting
233 those ``PP`` to human readable string. Actually exactly it is used for
234 all object ``repr``. But it is easy to write custom formatters.
236 >>> from pyderasn import pprint
237 >>> encoded = Integer(-12345).encode()
238 >>> obj, tail = Integer().decode(encoded)
239 >>> print(pprint(obj))
240 0 [1,1, 2] INTEGER -12345
247 ASN.1 structures often have ANY and OCTET STRING fields, that are
248 DEFINED BY some previously met ObjectIdentifier. This library provides
249 ability to specify mapping between some OID and field that must be
250 decoded with specific specification.
255 :py:class:`pyderasn.ObjectIdentifier` field inside
256 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
257 necessary for decoding structures. For example, CMS (:rfc:`5652`)
260 class ContentInfo(Sequence):
262 ("contentType", ContentType(defines=((("content",), {
263 id_digestedData: DigestedData(),
264 id_signedData: SignedData(),
266 ("content", Any(expl=tag_ctxc(0))),
269 ``contentType`` field tells that it defines that ``content`` must be
270 decoded with ``SignedData`` specification, if ``contentType`` equals to
271 ``id-signedData``. The same applies to ``DigestedData``. If
272 ``contentType`` contains unknown OID, then no automatic decoding is
275 You can specify multiple fields, that will be autodecoded -- that is why
276 ``defines`` kwarg is a sequence. You can specify defined field
277 relatively or absolutely to current decode path. For example ``defines``
278 for AlgorithmIdentifier of X.509's
279 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
283 id_ecPublicKey: ECParameters(),
284 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
286 (("..", "subjectPublicKey"), {
287 id_rsaEncryption: RSAPublicKey(),
288 id_GostR3410_2001: OctetString(),
292 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
293 autodecode its parameters inside SPKI's algorithm and its public key
296 Following types can be automatically decoded (DEFINED BY):
298 * :py:class:`pyderasn.Any`
299 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
300 * :py:class:`pyderasn.OctetString`
301 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
302 ``Any``/``BitString``/``OctetString``-s
304 When any of those fields is automatically decoded, then ``.defined``
305 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
306 was defined, ``value`` contains corresponding decoded value. For example
307 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
309 .. _defines_by_path_ctx:
311 defines_by_path context option
312 ______________________________
314 Sometimes you either can not or do not want to explicitly set *defines*
315 in the scheme. You can dynamically apply those definitions when calling
316 ``.decode()`` method.
318 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
319 value must be sequence of following tuples::
321 (decode_path, defines)
323 where ``decode_path`` is a tuple holding so-called decode path to the
324 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
325 ``defines``, holding exactly the same value as accepted in its keyword
328 For example, again for CMS, you want to automatically decode
329 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
330 structures it may hold. Also, automatically decode ``controlSequence``
333 content_info, tail = ContentInfo().decode(data, defines_by_path=(
336 ((("content",), {id_signedData: SignedData()}),),
341 DecodePathDefBy(id_signedData),
346 id_cct_PKIData: PKIData(),
347 id_cct_PKIResponse: PKIResponse(),
353 DecodePathDefBy(id_signedData),
356 DecodePathDefBy(id_cct_PKIResponse),
362 id_cmc_recipientNonce: RecipientNonce(),
363 id_cmc_senderNonce: SenderNonce(),
364 id_cmc_statusInfoV2: CMCStatusInfoV2(),
365 id_cmc_transactionId: TransactionId(),
370 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
371 First function is useful for path construction when some automatic
372 decoding is already done. ``any`` means literally any value it meet --
373 useful for SEQUENCE/SET OF-s.
380 By default PyDERASN accepts only DER encoded data. It always encodes to
381 DER. But you can optionally enable BER decoding with setting ``bered``
382 :ref:`context <ctx>` argument to True. Indefinite lengths and
383 constructed primitive types should be parsed successfully.
385 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
386 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
387 STRING``, ``SEQUENCE``, ``SET``, ``SET OF`` can contain it.
388 * If object has an indefinite length encoding, then its ``lenindef``
389 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
390 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
392 * If object has an indefinite length encoded explicit tag, then
393 ``expl_lenindef`` is set to True.
394 * If object has either any of BER-related encoding (explicit tag
395 indefinite length, object's indefinite length, BER-encoding) or any
396 underlying component has that kind of encoding, then ``bered``
397 attribute is set to True. For example SignedData CMS can have
398 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
399 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
401 EOC (end-of-contents) token's length is taken in advance in object's
404 .. _allow_expl_oob_ctx:
406 Allow explicit tag out-of-bound
407 -------------------------------
409 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
410 one value, more than one object. If you set ``allow_expl_oob`` context
411 option to True, then no error will be raised and that invalid encoding
412 will be silently further processed. But pay attention that offsets and
413 lengths will be invalid in that case.
417 This option should be used only for skipping some decode errors, just
418 to see the decoded structure somehow.
425 .. autoclass:: pyderasn.Boolean
430 .. autoclass:: pyderasn.Integer
435 .. autoclass:: pyderasn.BitString
440 .. autoclass:: pyderasn.OctetString
445 .. autoclass:: pyderasn.Null
450 .. autoclass:: pyderasn.ObjectIdentifier
455 .. autoclass:: pyderasn.Enumerated
459 .. autoclass:: pyderasn.CommonString
463 .. autoclass:: pyderasn.NumericString
467 .. autoclass:: pyderasn.UTCTime
468 :members: __init__, todatetime
472 .. autoclass:: pyderasn.GeneralizedTime
479 .. autoclass:: pyderasn.Choice
484 .. autoclass:: PrimitiveTypes
488 .. autoclass:: pyderasn.Any
496 .. autoclass:: pyderasn.Sequence
501 .. autoclass:: pyderasn.Set
506 .. autoclass:: pyderasn.SequenceOf
511 .. autoclass:: pyderasn.SetOf
517 .. autofunction:: pyderasn.abs_decode_path
518 .. autofunction:: pyderasn.hexenc
519 .. autofunction:: pyderasn.hexdec
520 .. autofunction:: pyderasn.tag_encode
521 .. autofunction:: pyderasn.tag_decode
522 .. autofunction:: pyderasn.tag_ctxp
523 .. autofunction:: pyderasn.tag_ctxc
524 .. autoclass:: pyderasn.Obj
525 .. autoclass:: pyderasn.DecodeError
527 .. autoclass:: pyderasn.NotEnoughData
528 .. autoclass:: pyderasn.LenIndefForm
529 .. autoclass:: pyderasn.TagMismatch
530 .. autoclass:: pyderasn.InvalidLength
531 .. autoclass:: pyderasn.InvalidOID
532 .. autoclass:: pyderasn.ObjUnknown
533 .. autoclass:: pyderasn.ObjNotReady
534 .. autoclass:: pyderasn.InvalidValueType
535 .. autoclass:: pyderasn.BoundsError
538 from codecs import getdecoder
539 from codecs import getencoder
540 from collections import namedtuple
541 from collections import OrderedDict
542 from datetime import datetime
543 from math import ceil
544 from os import environ
545 from string import ascii_letters
546 from string import digits
548 from six import add_metaclass
549 from six import binary_type
550 from six import byte2int
551 from six import indexbytes
552 from six import int2byte
553 from six import integer_types
554 from six import iterbytes
556 from six import string_types
557 from six import text_type
558 from six import unichr as six_unichr
559 from six.moves import xrange as six_xrange
563 from termcolor import colored
564 except ImportError: # pragma: no cover
565 def colored(what, *args):
609 "TagClassApplication",
613 "TagFormConstructed",
624 TagClassUniversal = 0
625 TagClassApplication = 1 << 6
626 TagClassContext = 1 << 7
627 TagClassPrivate = 1 << 6 | 1 << 7
629 TagFormConstructed = 1 << 5
632 TagClassApplication: "APPLICATION ",
633 TagClassPrivate: "PRIVATE ",
634 TagClassUniversal: "UNIV ",
638 LENINDEF = b"\x80" # length indefinite mark
639 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
642 ########################################################################
644 ########################################################################
646 class ASN1Error(ValueError):
649 class DecodeError(ASN1Error):
650 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
652 :param str msg: reason of decode failing
653 :param klass: optional exact DecodeError inherited class (like
654 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
655 :py:exc:`InvalidLength`)
656 :param decode_path: tuple of strings. It contains human
657 readable names of the fields through which
658 decoding process has passed
659 :param int offset: binary offset where failure happened
661 super(DecodeError, self).__init__()
664 self.decode_path = decode_path
670 "" if self.klass is None else self.klass.__name__,
672 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
673 if len(self.decode_path) > 0 else ""
675 ("(at %d)" % self.offset) if self.offset > 0 else "",
681 return "%s(%s)" % (self.__class__.__name__, self)
684 class NotEnoughData(DecodeError):
688 class LenIndefForm(DecodeError):
692 class TagMismatch(DecodeError):
696 class InvalidLength(DecodeError):
700 class InvalidOID(DecodeError):
704 class ObjUnknown(ASN1Error):
705 def __init__(self, name):
706 super(ObjUnknown, self).__init__()
710 return "object is unknown: %s" % self.name
713 return "%s(%s)" % (self.__class__.__name__, self)
716 class ObjNotReady(ASN1Error):
717 def __init__(self, name):
718 super(ObjNotReady, self).__init__()
722 return "object is not ready: %s" % self.name
725 return "%s(%s)" % (self.__class__.__name__, self)
728 class InvalidValueType(ASN1Error):
729 def __init__(self, expected_types):
730 super(InvalidValueType, self).__init__()
731 self.expected_types = expected_types
734 return "invalid value type, expected: %s" % ", ".join(
735 [repr(t) for t in self.expected_types]
739 return "%s(%s)" % (self.__class__.__name__, self)
742 class BoundsError(ASN1Error):
743 def __init__(self, bound_min, value, bound_max):
744 super(BoundsError, self).__init__()
745 self.bound_min = bound_min
747 self.bound_max = bound_max
750 return "unsatisfied bounds: %s <= %s <= %s" % (
757 return "%s(%s)" % (self.__class__.__name__, self)
760 ########################################################################
762 ########################################################################
764 _hexdecoder = getdecoder("hex")
765 _hexencoder = getencoder("hex")
769 """Binary data to hexadecimal string convert
771 return _hexdecoder(data)[0]
775 """Hexadecimal string to binary data convert
777 return _hexencoder(data)[0].decode("ascii")
780 def int_bytes_len(num, byte_len=8):
783 return int(ceil(float(num.bit_length()) / byte_len))
786 def zero_ended_encode(num):
787 octets = bytearray(int_bytes_len(num, 7))
789 octets[i] = num & 0x7F
793 octets[i] = 0x80 | (num & 0x7F)
799 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
800 """Encode tag to binary form
802 :param int num: tag's number
803 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
804 :py:data:`pyderasn.TagClassContext`,
805 :py:data:`pyderasn.TagClassApplication`,
806 :py:data:`pyderasn.TagClassPrivate`)
807 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
808 :py:data:`pyderasn.TagFormConstructed`)
812 return int2byte(klass | form | num)
813 # [XX|X|11111][1.......][1.......] ... [0.......]
814 return int2byte(klass | form | 31) + zero_ended_encode(num)
818 """Decode tag from binary form
822 No validation is performed, assuming that it has already passed.
824 It returns tuple with three integers, as
825 :py:func:`pyderasn.tag_encode` accepts.
827 first_octet = byte2int(tag)
828 klass = first_octet & 0xC0
829 form = first_octet & 0x20
830 if first_octet & 0x1F < 0x1F:
831 return (klass, form, first_octet & 0x1F)
833 for octet in iterbytes(tag[1:]):
836 return (klass, form, num)
840 """Create CONTEXT PRIMITIVE tag
842 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
846 """Create CONTEXT CONSTRUCTED tag
848 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
852 """Take off tag from the data
854 :returns: (encoded tag, tag length, remaining data)
857 raise NotEnoughData("no data at all")
858 if byte2int(data) & 0x1F < 31:
859 return data[:1], 1, data[1:]
864 raise DecodeError("unfinished tag")
865 if indexbytes(data, i) & 0x80 == 0:
868 return data[:i], i, data[i:]
874 octets = bytearray(int_bytes_len(l) + 1)
875 octets[0] = 0x80 | (len(octets) - 1)
876 for i in six_xrange(len(octets) - 1, 0, -1):
882 def len_decode(data):
885 :returns: (decoded length, length's length, remaining data)
886 :raises LenIndefForm: if indefinite form encoding is met
889 raise NotEnoughData("no data at all")
890 first_octet = byte2int(data)
891 if first_octet & 0x80 == 0:
892 return first_octet, 1, data[1:]
893 octets_num = first_octet & 0x7F
894 if octets_num + 1 > len(data):
895 raise NotEnoughData("encoded length is longer than data")
898 if byte2int(data[1:]) == 0:
899 raise DecodeError("leading zeros")
901 for v in iterbytes(data[1:1 + octets_num]):
904 raise DecodeError("long form instead of short one")
905 return l, 1 + octets_num, data[1 + octets_num:]
908 ########################################################################
910 ########################################################################
912 class AutoAddSlots(type):
913 def __new__(mcs, name, bases, _dict):
914 _dict["__slots__"] = _dict.get("__slots__", ())
915 return type.__new__(mcs, name, bases, _dict)
918 @add_metaclass(AutoAddSlots)
920 """Common ASN.1 object class
922 All ASN.1 types are inherited from it. It has metaclass that
923 automatically adds ``__slots__`` to all inherited classes.
947 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
948 self._expl = getattr(self, "expl", None) if expl is None else expl
949 if self.tag != self.tag_default and self._expl is not None:
950 raise ValueError("implicit and explicit tags can not be set simultaneously")
951 if default is not None:
953 self.optional = optional
954 self.offset, self.llen, self.vlen = _decoded
956 self.expl_lenindef = False
957 self.lenindef = False
958 self.ber_encoded = False
961 def ready(self): # pragma: no cover
962 """Is object ready to be encoded?
964 raise NotImplementedError()
966 def _assert_ready(self):
968 raise ObjNotReady(self.__class__.__name__)
972 """Is either object or any elements inside is BER encoded?
974 return self.expl_lenindef or self.lenindef or self.ber_encoded
978 """Is object decoded?
980 return (self.llen + self.vlen) > 0
982 def copy(self): # pragma: no cover
983 """Make a copy of object, safe to be mutated
985 raise NotImplementedError()
993 return self.tlen + self.llen + self.vlen
995 def __str__(self): # pragma: no cover
996 return self.__bytes__() if PY2 else self.__unicode__()
998 def __ne__(self, their):
999 return not(self == their)
1001 def __gt__(self, their): # pragma: no cover
1002 return not(self < their)
1004 def __le__(self, their): # pragma: no cover
1005 return (self == their) or (self < their)
1007 def __ge__(self, their): # pragma: no cover
1008 return (self == their) or (self > their)
1010 def _encode(self): # pragma: no cover
1011 raise NotImplementedError()
1013 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1014 raise NotImplementedError()
1017 raw = self._encode()
1018 if self._expl is None:
1020 return b"".join((self._expl, len_encode(len(raw)), raw))
1033 :param data: either binary or memoryview
1034 :param int offset: initial data's offset
1035 :param bool leavemm: do we need to leave memoryview of remaining
1036 data as is, or convert it to bytes otherwise
1037 :param ctx: optional :ref:`context <ctx>` governing decoding process.
1038 :param tag_only: decode only the tag, without length and contents
1039 (used only in Choice and Set structures, trying to
1040 determine if tag satisfies the scheme)
1041 :returns: (Obj, remaining data)
1045 tlv = memoryview(data)
1046 if self._expl is None:
1047 result = self._decode(
1050 decode_path=decode_path,
1059 t, tlen, lv = tag_strip(tlv)
1060 except DecodeError as err:
1061 raise err.__class__(
1063 klass=self.__class__,
1064 decode_path=decode_path,
1069 klass=self.__class__,
1070 decode_path=decode_path,
1074 l, llen, v = len_decode(lv)
1075 except LenIndefForm as err:
1076 if not ctx.get("bered", False):
1077 raise err.__class__(
1079 klass=self.__class__,
1080 decode_path=decode_path,
1084 offset += tlen + llen
1085 result = self._decode(
1088 decode_path=decode_path,
1092 if tag_only: # pragma: no cover
1095 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1096 if eoc_expected.tobytes() != EOC:
1099 klass=self.__class__,
1100 decode_path=decode_path,
1104 obj.expl_lenindef = True
1105 except DecodeError as err:
1106 raise err.__class__(
1108 klass=self.__class__,
1109 decode_path=decode_path,
1114 raise NotEnoughData(
1115 "encoded length is longer than data",
1116 klass=self.__class__,
1117 decode_path=decode_path,
1120 result = self._decode(
1122 offset=offset + tlen + llen,
1123 decode_path=decode_path,
1127 if tag_only: # pragma: no cover
1130 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1132 "explicit tag out-of-bound, longer than data",
1133 klass=self.__class__,
1134 decode_path=decode_path,
1137 return obj, (tail if leavemm else tail.tobytes())
1141 return self._expl is not None
1148 def expl_tlen(self):
1149 return len(self._expl)
1152 def expl_llen(self):
1153 if self.expl_lenindef:
1155 return len(len_encode(self.tlvlen))
1158 def expl_offset(self):
1159 return self.offset - self.expl_tlen - self.expl_llen
1162 def expl_vlen(self):
1166 def expl_tlvlen(self):
1167 return self.expl_tlen + self.expl_llen + self.expl_vlen
1170 def fulloffset(self):
1171 return self.expl_offset if self.expled else self.offset
1175 return self.expl_tlvlen if self.expled else self.tlvlen
1177 def pps_lenindef(self, decode_path):
1178 if self.lenindef and not (
1179 getattr(self, "defined", None) is not None and
1180 self.defined[1].lenindef
1183 asn1_type_name="EOC",
1185 decode_path=decode_path,
1187 self.offset + self.tlvlen -
1188 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1196 if self.expl_lenindef:
1198 asn1_type_name="EOC",
1199 obj_name="EXPLICIT",
1200 decode_path=decode_path,
1201 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1210 class DecodePathDefBy(object):
1211 """DEFINED BY representation inside decode path
1213 __slots__ = ("defined_by",)
1215 def __init__(self, defined_by):
1216 self.defined_by = defined_by
1218 def __ne__(self, their):
1219 return not(self == their)
1221 def __eq__(self, their):
1222 if not isinstance(their, self.__class__):
1224 return self.defined_by == their.defined_by
1227 return "DEFINED BY " + str(self.defined_by)
1230 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1233 ########################################################################
1235 ########################################################################
1237 PP = namedtuple("PP", (
1263 asn1_type_name="unknown",
1280 expl_lenindef=False,
1310 def _colourize(what, colour, with_colours, attrs=("bold",)):
1311 return colored(what, colour, attrs=attrs) if with_colours else what
1320 with_decode_path=False,
1321 decode_path_len_decrease=0,
1328 " " if pp.expl_offset is None else
1329 ("-%d" % (pp.offset - pp.expl_offset))
1331 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1333 col = _colourize(col, "red", with_colours, ())
1334 col += _colourize("B", "red", with_colours) if pp.bered else " "
1336 col = "[%d,%d,%4d]%s" % (
1340 LENINDEF_PP_CHAR if pp.lenindef else " "
1342 col = _colourize(col, "green", with_colours, ())
1344 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1345 if decode_path_len > 0:
1346 cols.append(" ." * decode_path_len)
1347 ent = pp.decode_path[-1]
1348 if isinstance(ent, DecodePathDefBy):
1349 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1350 value = str(ent.defined_by)
1352 oids is not None and
1353 ent.defined_by.asn1_type_name ==
1354 ObjectIdentifier.asn1_type_name and
1357 cols.append(_colourize("%s:" % oids[value], "green", with_colours))
1359 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1361 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1362 if pp.expl is not None:
1363 klass, _, num = pp.expl
1364 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1365 cols.append(_colourize(col, "blue", with_colours))
1366 if pp.impl is not None:
1367 klass, _, num = pp.impl
1368 col = "[%s%d]" % (TagClassReprs[klass], num)
1369 cols.append(_colourize(col, "blue", with_colours))
1370 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1371 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1373 cols.append(_colourize("BER", "red", with_colours))
1374 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1375 if pp.value is not None:
1377 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1379 oids is not None and
1380 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
1383 cols.append(_colourize("(%s)" % oids[value], "green", with_colours))
1385 if isinstance(pp.blob, binary_type):
1386 cols.append(hexenc(pp.blob))
1387 elif isinstance(pp.blob, tuple):
1388 cols.append(", ".join(pp.blob))
1390 cols.append(_colourize("OPTIONAL", "red", with_colours))
1392 cols.append(_colourize("DEFAULT", "red", with_colours))
1393 if with_decode_path:
1394 cols.append(_colourize(
1395 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1399 return " ".join(cols)
1402 def pp_console_blob(pp, decode_path_len_decrease=0):
1403 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1404 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1405 if decode_path_len > 0:
1406 cols.append(" ." * (decode_path_len + 1))
1407 if isinstance(pp.blob, binary_type):
1408 blob = hexenc(pp.blob).upper()
1409 for i in range(0, len(blob), 32):
1410 chunk = blob[i:i + 32]
1411 yield " ".join(cols + [":".join(
1412 chunk[j:j + 2] for j in range(0, len(chunk), 2)
1414 elif isinstance(pp.blob, tuple):
1415 yield " ".join(cols + [", ".join(pp.blob)])
1423 with_decode_path=False,
1424 decode_path_only=(),
1426 """Pretty print object
1428 :param Obj obj: object you want to pretty print
1429 :param oids: ``OID <-> humand readable string`` dictionary. When OID
1430 from it is met, then its humand readable form is printed
1431 :param big_blobs: if large binary objects are met (like OctetString
1432 values), do we need to print them too, on separate
1434 :param with_colours: colourize output, if ``termcolor`` library
1436 :param with_decode_path: print decode path
1437 :param decode_path_only: print only that specified decode path
1439 def _pprint_pps(pps):
1441 if hasattr(pp, "_fields"):
1443 decode_path_only != () and
1445 str(p) for p in pp.decode_path[:len(decode_path_only)]
1446 ) != decode_path_only
1450 yield pp_console_row(
1455 with_colours=with_colours,
1456 with_decode_path=with_decode_path,
1457 decode_path_len_decrease=len(decode_path_only),
1459 for row in pp_console_blob(
1461 decode_path_len_decrease=len(decode_path_only),
1465 yield pp_console_row(
1470 with_colours=with_colours,
1471 with_decode_path=with_decode_path,
1472 decode_path_len_decrease=len(decode_path_only),
1475 for row in _pprint_pps(pp):
1477 return "\n".join(_pprint_pps(obj.pps()))
1480 ########################################################################
1481 # ASN.1 primitive types
1482 ########################################################################
1485 """``BOOLEAN`` boolean type
1487 >>> b = Boolean(True)
1489 >>> b == Boolean(True)
1495 tag_default = tag_encode(1)
1496 asn1_type_name = "BOOLEAN"
1508 :param value: set the value. Either boolean type, or
1509 :py:class:`pyderasn.Boolean` object
1510 :param bytes impl: override default tag with ``IMPLICIT`` one
1511 :param bytes expl: override default tag with ``EXPLICIT`` one
1512 :param default: set default value. Type same as in ``value``
1513 :param bool optional: is object ``OPTIONAL`` in sequence
1515 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1516 self._value = None if value is None else self._value_sanitize(value)
1517 if default is not None:
1518 default = self._value_sanitize(default)
1519 self.default = self.__class__(
1525 self._value = default
1527 def _value_sanitize(self, value):
1528 if issubclass(value.__class__, Boolean):
1530 if isinstance(value, bool):
1532 raise InvalidValueType((self.__class__, bool))
1536 return self._value is not None
1539 obj = self.__class__()
1540 obj._value = self._value
1542 obj._expl = self._expl
1543 obj.default = self.default
1544 obj.optional = self.optional
1545 obj.offset = self.offset
1546 obj.llen = self.llen
1547 obj.vlen = self.vlen
1550 def __nonzero__(self):
1551 self._assert_ready()
1555 self._assert_ready()
1558 def __eq__(self, their):
1559 if isinstance(their, bool):
1560 return self._value == their
1561 if not issubclass(their.__class__, Boolean):
1564 self._value == their._value and
1565 self.tag == their.tag and
1566 self._expl == their._expl
1577 return self.__class__(
1579 impl=self.tag if impl is None else impl,
1580 expl=self._expl if expl is None else expl,
1581 default=self.default if default is None else default,
1582 optional=self.optional if optional is None else optional,
1586 self._assert_ready()
1590 (b"\xFF" if self._value else b"\x00"),
1593 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1595 t, _, lv = tag_strip(tlv)
1596 except DecodeError as err:
1597 raise err.__class__(
1599 klass=self.__class__,
1600 decode_path=decode_path,
1605 klass=self.__class__,
1606 decode_path=decode_path,
1612 l, _, v = len_decode(lv)
1613 except DecodeError as err:
1614 raise err.__class__(
1616 klass=self.__class__,
1617 decode_path=decode_path,
1621 raise InvalidLength(
1622 "Boolean's length must be equal to 1",
1623 klass=self.__class__,
1624 decode_path=decode_path,
1628 raise NotEnoughData(
1629 "encoded length is longer than data",
1630 klass=self.__class__,
1631 decode_path=decode_path,
1634 first_octet = byte2int(v)
1636 if first_octet == 0:
1638 elif first_octet == 0xFF:
1640 elif ctx.get("bered", False):
1645 "unacceptable Boolean value",
1646 klass=self.__class__,
1647 decode_path=decode_path,
1650 obj = self.__class__(
1654 default=self.default,
1655 optional=self.optional,
1656 _decoded=(offset, 1, 1),
1658 obj.ber_encoded = ber_encoded
1662 return pp_console_row(next(self.pps()))
1664 def pps(self, decode_path=()):
1666 asn1_type_name=self.asn1_type_name,
1667 obj_name=self.__class__.__name__,
1668 decode_path=decode_path,
1669 value=str(self._value) if self.ready else None,
1670 optional=self.optional,
1671 default=self == self.default,
1672 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1673 expl=None if self._expl is None else tag_decode(self._expl),
1678 expl_offset=self.expl_offset if self.expled else None,
1679 expl_tlen=self.expl_tlen if self.expled else None,
1680 expl_llen=self.expl_llen if self.expled else None,
1681 expl_vlen=self.expl_vlen if self.expled else None,
1682 expl_lenindef=self.expl_lenindef,
1683 ber_encoded=self.ber_encoded,
1686 for pp in self.pps_lenindef(decode_path):
1691 """``INTEGER`` integer type
1693 >>> b = Integer(-123)
1695 >>> b == Integer(-123)
1700 >>> Integer(2, bounds=(1, 3))
1702 >>> Integer(5, bounds=(1, 3))
1703 Traceback (most recent call last):
1704 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1708 class Version(Integer):
1715 >>> v = Version("v1")
1722 {'v3': 2, 'v1': 0, 'v2': 1}
1724 __slots__ = ("specs", "_bound_min", "_bound_max")
1725 tag_default = tag_encode(2)
1726 asn1_type_name = "INTEGER"
1740 :param value: set the value. Either integer type, named value
1741 (if ``schema`` is specified in the class), or
1742 :py:class:`pyderasn.Integer` object
1743 :param bounds: set ``(MIN, MAX)`` value constraint.
1744 (-inf, +inf) by default
1745 :param bytes impl: override default tag with ``IMPLICIT`` one
1746 :param bytes expl: override default tag with ``EXPLICIT`` one
1747 :param default: set default value. Type same as in ``value``
1748 :param bool optional: is object ``OPTIONAL`` in sequence
1750 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1752 specs = getattr(self, "schema", {}) if _specs is None else _specs
1753 self.specs = specs if isinstance(specs, dict) else dict(specs)
1754 self._bound_min, self._bound_max = getattr(
1757 (float("-inf"), float("+inf")),
1758 ) if bounds is None else bounds
1759 if value is not None:
1760 self._value = self._value_sanitize(value)
1761 if default is not None:
1762 default = self._value_sanitize(default)
1763 self.default = self.__class__(
1769 if self._value is None:
1770 self._value = default
1772 def _value_sanitize(self, value):
1773 if issubclass(value.__class__, Integer):
1774 value = value._value
1775 elif isinstance(value, integer_types):
1777 elif isinstance(value, str):
1778 value = self.specs.get(value)
1780 raise ObjUnknown("integer value: %s" % value)
1782 raise InvalidValueType((self.__class__, int, str))
1783 if not self._bound_min <= value <= self._bound_max:
1784 raise BoundsError(self._bound_min, value, self._bound_max)
1789 return self._value is not None
1792 obj = self.__class__(_specs=self.specs)
1793 obj._value = self._value
1794 obj._bound_min = self._bound_min
1795 obj._bound_max = self._bound_max
1797 obj._expl = self._expl
1798 obj.default = self.default
1799 obj.optional = self.optional
1800 obj.offset = self.offset
1801 obj.llen = self.llen
1802 obj.vlen = self.vlen
1806 self._assert_ready()
1807 return int(self._value)
1810 self._assert_ready()
1813 bytes(self._expl or b"") +
1814 str(self._value).encode("ascii"),
1817 def __eq__(self, their):
1818 if isinstance(their, integer_types):
1819 return self._value == their
1820 if not issubclass(their.__class__, Integer):
1823 self._value == their._value and
1824 self.tag == their.tag and
1825 self._expl == their._expl
1828 def __lt__(self, their):
1829 return self._value < their._value
1833 for name, value in self.specs.items():
1834 if value == self._value:
1846 return self.__class__(
1849 (self._bound_min, self._bound_max)
1850 if bounds is None else bounds
1852 impl=self.tag if impl is None else impl,
1853 expl=self._expl if expl is None else expl,
1854 default=self.default if default is None else default,
1855 optional=self.optional if optional is None else optional,
1860 self._assert_ready()
1864 octets = bytearray([0])
1868 octets = bytearray()
1870 octets.append((value & 0xFF) ^ 0xFF)
1872 if len(octets) == 0 or octets[-1] & 0x80 == 0:
1875 octets = bytearray()
1877 octets.append(value & 0xFF)
1879 if octets[-1] & 0x80 > 0:
1882 octets = bytes(octets)
1884 bytes_len = ceil(value.bit_length() / 8) or 1
1887 octets = value.to_bytes(
1892 except OverflowError:
1896 return b"".join((self.tag, len_encode(len(octets)), octets))
1898 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1900 t, _, lv = tag_strip(tlv)
1901 except DecodeError as err:
1902 raise err.__class__(
1904 klass=self.__class__,
1905 decode_path=decode_path,
1910 klass=self.__class__,
1911 decode_path=decode_path,
1917 l, llen, v = len_decode(lv)
1918 except DecodeError as err:
1919 raise err.__class__(
1921 klass=self.__class__,
1922 decode_path=decode_path,
1926 raise NotEnoughData(
1927 "encoded length is longer than data",
1928 klass=self.__class__,
1929 decode_path=decode_path,
1933 raise NotEnoughData(
1935 klass=self.__class__,
1936 decode_path=decode_path,
1939 v, tail = v[:l], v[l:]
1940 first_octet = byte2int(v)
1942 second_octet = byte2int(v[1:])
1944 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
1945 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
1948 "non normalized integer",
1949 klass=self.__class__,
1950 decode_path=decode_path,
1955 if first_octet & 0x80 > 0:
1956 octets = bytearray()
1957 for octet in bytearray(v):
1958 octets.append(octet ^ 0xFF)
1959 for octet in octets:
1960 value = (value << 8) | octet
1964 for octet in bytearray(v):
1965 value = (value << 8) | octet
1967 value = int.from_bytes(v, byteorder="big", signed=True)
1969 obj = self.__class__(
1971 bounds=(self._bound_min, self._bound_max),
1974 default=self.default,
1975 optional=self.optional,
1977 _decoded=(offset, llen, l),
1979 except BoundsError as err:
1982 klass=self.__class__,
1983 decode_path=decode_path,
1989 return pp_console_row(next(self.pps()))
1991 def pps(self, decode_path=()):
1993 asn1_type_name=self.asn1_type_name,
1994 obj_name=self.__class__.__name__,
1995 decode_path=decode_path,
1996 value=(self.named or str(self._value)) if self.ready else None,
1997 optional=self.optional,
1998 default=self == self.default,
1999 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2000 expl=None if self._expl is None else tag_decode(self._expl),
2005 expl_offset=self.expl_offset if self.expled else None,
2006 expl_tlen=self.expl_tlen if self.expled else None,
2007 expl_llen=self.expl_llen if self.expled else None,
2008 expl_vlen=self.expl_vlen if self.expled else None,
2009 expl_lenindef=self.expl_lenindef,
2012 for pp in self.pps_lenindef(decode_path):
2016 class BitString(Obj):
2017 """``BIT STRING`` bit string type
2019 >>> BitString(b"hello world")
2020 BIT STRING 88 bits 68656c6c6f20776f726c64
2023 >>> b == b"hello world"
2028 >>> BitString("'0A3B5F291CD'H")
2029 BIT STRING 44 bits 0a3b5f291cd0
2030 >>> b = BitString("'010110000000'B")
2031 BIT STRING 12 bits 5800
2034 >>> b[0], b[1], b[2], b[3]
2035 (False, True, False, True)
2039 [False, True, False, True, True, False, False, False, False, False, False, False]
2043 class KeyUsage(BitString):
2045 ("digitalSignature", 0),
2046 ("nonRepudiation", 1),
2047 ("keyEncipherment", 2),
2050 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2051 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2053 ['nonRepudiation', 'keyEncipherment']
2055 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2059 Pay attention that BIT STRING can be encoded both in primitive
2060 and constructed forms. Decoder always checks constructed form tag
2061 additionally to specified primitive one. If BER decoding is
2062 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2063 of DER restrictions.
2065 __slots__ = ("tag_constructed", "specs", "defined")
2066 tag_default = tag_encode(3)
2067 asn1_type_name = "BIT STRING"
2080 :param value: set the value. Either binary type, tuple of named
2081 values (if ``schema`` is specified in the class),
2082 string in ``'XXX...'B`` form, or
2083 :py:class:`pyderasn.BitString` object
2084 :param bytes impl: override default tag with ``IMPLICIT`` one
2085 :param bytes expl: override default tag with ``EXPLICIT`` one
2086 :param default: set default value. Type same as in ``value``
2087 :param bool optional: is object ``OPTIONAL`` in sequence
2089 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2090 specs = getattr(self, "schema", {}) if _specs is None else _specs
2091 self.specs = specs if isinstance(specs, dict) else dict(specs)
2092 self._value = None if value is None else self._value_sanitize(value)
2093 if default is not None:
2094 default = self._value_sanitize(default)
2095 self.default = self.__class__(
2101 self._value = default
2103 tag_klass, _, tag_num = tag_decode(self.tag)
2104 self.tag_constructed = tag_encode(
2106 form=TagFormConstructed,
2110 def _bits2octets(self, bits):
2111 if len(self.specs) > 0:
2112 bits = bits.rstrip("0")
2114 bits += "0" * ((8 - (bit_len % 8)) % 8)
2115 octets = bytearray(len(bits) // 8)
2116 for i in six_xrange(len(octets)):
2117 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2118 return bit_len, bytes(octets)
2120 def _value_sanitize(self, value):
2121 if issubclass(value.__class__, BitString):
2123 if isinstance(value, (string_types, binary_type)):
2125 isinstance(value, string_types) and
2126 value.startswith("'")
2128 if value.endswith("'B"):
2130 if not set(value) <= set(("0", "1")):
2131 raise ValueError("B's coding contains unacceptable chars")
2132 return self._bits2octets(value)
2133 elif value.endswith("'H"):
2137 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2139 if isinstance(value, binary_type):
2140 return (len(value) * 8, value)
2142 raise InvalidValueType((self.__class__, string_types, binary_type))
2143 if isinstance(value, tuple):
2146 isinstance(value[0], integer_types) and
2147 isinstance(value[1], binary_type)
2152 bit = self.specs.get(name)
2154 raise ObjUnknown("BitString value: %s" % name)
2157 return self._bits2octets("")
2159 return self._bits2octets("".join(
2160 ("1" if bit in bits else "0")
2161 for bit in six_xrange(max(bits) + 1)
2163 raise InvalidValueType((self.__class__, binary_type, string_types))
2167 return self._value is not None
2170 obj = self.__class__(_specs=self.specs)
2172 if value is not None:
2173 value = (value[0], value[1])
2176 obj._expl = self._expl
2177 obj.default = self.default
2178 obj.optional = self.optional
2179 obj.offset = self.offset
2180 obj.llen = self.llen
2181 obj.vlen = self.vlen
2185 self._assert_ready()
2186 for i in six_xrange(self._value[0]):
2191 self._assert_ready()
2192 return self._value[0]
2194 def __bytes__(self):
2195 self._assert_ready()
2196 return self._value[1]
2198 def __eq__(self, their):
2199 if isinstance(their, bytes):
2200 return self._value[1] == their
2201 if not issubclass(their.__class__, BitString):
2204 self._value == their._value and
2205 self.tag == their.tag and
2206 self._expl == their._expl
2211 return [name for name, bit in self.specs.items() if self[bit]]
2221 return self.__class__(
2223 impl=self.tag if impl is None else impl,
2224 expl=self._expl if expl is None else expl,
2225 default=self.default if default is None else default,
2226 optional=self.optional if optional is None else optional,
2230 def __getitem__(self, key):
2231 if isinstance(key, int):
2232 bit_len, octets = self._value
2236 byte2int(memoryview(octets)[key // 8:]) >>
2239 if isinstance(key, string_types):
2240 value = self.specs.get(key)
2242 raise ObjUnknown("BitString value: %s" % key)
2244 raise InvalidValueType((int, str))
2247 self._assert_ready()
2248 bit_len, octets = self._value
2251 len_encode(len(octets) + 1),
2252 int2byte((8 - bit_len % 8) % 8),
2256 def _decode_chunk(self, lv, offset, decode_path, ctx):
2258 l, llen, v = len_decode(lv)
2259 except DecodeError as err:
2260 raise err.__class__(
2262 klass=self.__class__,
2263 decode_path=decode_path,
2267 raise NotEnoughData(
2268 "encoded length is longer than data",
2269 klass=self.__class__,
2270 decode_path=decode_path,
2274 raise NotEnoughData(
2276 klass=self.__class__,
2277 decode_path=decode_path,
2280 pad_size = byte2int(v)
2281 if l == 1 and pad_size != 0:
2283 "invalid empty value",
2284 klass=self.__class__,
2285 decode_path=decode_path,
2291 klass=self.__class__,
2292 decode_path=decode_path,
2295 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2298 klass=self.__class__,
2299 decode_path=decode_path,
2302 v, tail = v[:l], v[l:]
2303 obj = self.__class__(
2304 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2307 default=self.default,
2308 optional=self.optional,
2310 _decoded=(offset, llen, l),
2314 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2316 t, tlen, lv = tag_strip(tlv)
2317 except DecodeError as err:
2318 raise err.__class__(
2320 klass=self.__class__,
2321 decode_path=decode_path,
2325 if tag_only: # pragma: no cover
2327 return self._decode_chunk(lv, offset, decode_path, ctx)
2328 if t == self.tag_constructed:
2329 if not ctx.get("bered", False):
2331 "unallowed BER constructed encoding",
2332 klass=self.__class__,
2333 decode_path=decode_path,
2336 if tag_only: # pragma: no cover
2340 l, llen, v = len_decode(lv)
2341 except LenIndefForm:
2342 llen, l, v = 1, 0, lv[1:]
2344 except DecodeError as err:
2345 raise err.__class__(
2347 klass=self.__class__,
2348 decode_path=decode_path,
2352 raise NotEnoughData(
2353 "encoded length is longer than data",
2354 klass=self.__class__,
2355 decode_path=decode_path,
2358 if not lenindef and l == 0:
2359 raise NotEnoughData(
2361 klass=self.__class__,
2362 decode_path=decode_path,
2366 sub_offset = offset + tlen + llen
2370 if v[:EOC_LEN].tobytes() == EOC:
2377 "chunk out of bounds",
2378 klass=self.__class__,
2379 decode_path=decode_path + (str(len(chunks) - 1),),
2380 offset=chunks[-1].offset,
2382 sub_decode_path = decode_path + (str(len(chunks)),)
2384 chunk, v_tail = BitString().decode(
2387 decode_path=sub_decode_path,
2393 "expected BitString encoded chunk",
2394 klass=self.__class__,
2395 decode_path=sub_decode_path,
2398 chunks.append(chunk)
2399 sub_offset += chunk.tlvlen
2400 vlen += chunk.tlvlen
2402 if len(chunks) == 0:
2405 klass=self.__class__,
2406 decode_path=decode_path,
2411 for chunk_i, chunk in enumerate(chunks[:-1]):
2412 if chunk.bit_len % 8 != 0:
2414 "BitString chunk is not multiple of 8 bits",
2415 klass=self.__class__,
2416 decode_path=decode_path + (str(chunk_i),),
2417 offset=chunk.offset,
2419 values.append(bytes(chunk))
2420 bit_len += chunk.bit_len
2421 chunk_last = chunks[-1]
2422 values.append(bytes(chunk_last))
2423 bit_len += chunk_last.bit_len
2424 obj = self.__class__(
2425 value=(bit_len, b"".join(values)),
2428 default=self.default,
2429 optional=self.optional,
2431 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2433 obj.lenindef = lenindef
2434 obj.ber_encoded = True
2435 return obj, (v[EOC_LEN:] if lenindef else v)
2437 klass=self.__class__,
2438 decode_path=decode_path,
2443 return pp_console_row(next(self.pps()))
2445 def pps(self, decode_path=()):
2449 bit_len, blob = self._value
2450 value = "%d bits" % bit_len
2451 if len(self.specs) > 0:
2452 blob = tuple(self.named)
2454 asn1_type_name=self.asn1_type_name,
2455 obj_name=self.__class__.__name__,
2456 decode_path=decode_path,
2459 optional=self.optional,
2460 default=self == self.default,
2461 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2462 expl=None if self._expl is None else tag_decode(self._expl),
2467 expl_offset=self.expl_offset if self.expled else None,
2468 expl_tlen=self.expl_tlen if self.expled else None,
2469 expl_llen=self.expl_llen if self.expled else None,
2470 expl_vlen=self.expl_vlen if self.expled else None,
2471 expl_lenindef=self.expl_lenindef,
2472 lenindef=self.lenindef,
2473 ber_encoded=self.ber_encoded,
2476 defined_by, defined = self.defined or (None, None)
2477 if defined_by is not None:
2479 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2481 for pp in self.pps_lenindef(decode_path):
2485 class OctetString(Obj):
2486 """``OCTET STRING`` binary string type
2488 >>> s = OctetString(b"hello world")
2489 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2490 >>> s == OctetString(b"hello world")
2495 >>> OctetString(b"hello", bounds=(4, 4))
2496 Traceback (most recent call last):
2497 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2498 >>> OctetString(b"hell", bounds=(4, 4))
2499 OCTET STRING 4 bytes 68656c6c
2503 Pay attention that OCTET STRING can be encoded both in primitive
2504 and constructed forms. Decoder always checks constructed form tag
2505 additionally to specified primitive one. If BER decoding is
2506 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2507 of DER restrictions.
2509 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2510 tag_default = tag_encode(4)
2511 asn1_type_name = "OCTET STRING"
2524 :param value: set the value. Either binary type, or
2525 :py:class:`pyderasn.OctetString` object
2526 :param bounds: set ``(MIN, MAX)`` value size constraint.
2527 (-inf, +inf) by default
2528 :param bytes impl: override default tag with ``IMPLICIT`` one
2529 :param bytes expl: override default tag with ``EXPLICIT`` one
2530 :param default: set default value. Type same as in ``value``
2531 :param bool optional: is object ``OPTIONAL`` in sequence
2533 super(OctetString, self).__init__(
2541 self._bound_min, self._bound_max = getattr(
2545 ) if bounds is None else bounds
2546 if value is not None:
2547 self._value = self._value_sanitize(value)
2548 if default is not None:
2549 default = self._value_sanitize(default)
2550 self.default = self.__class__(
2555 if self._value is None:
2556 self._value = default
2558 tag_klass, _, tag_num = tag_decode(self.tag)
2559 self.tag_constructed = tag_encode(
2561 form=TagFormConstructed,
2565 def _value_sanitize(self, value):
2566 if issubclass(value.__class__, OctetString):
2567 value = value._value
2568 elif isinstance(value, binary_type):
2571 raise InvalidValueType((self.__class__, bytes))
2572 if not self._bound_min <= len(value) <= self._bound_max:
2573 raise BoundsError(self._bound_min, len(value), self._bound_max)
2578 return self._value is not None
2581 obj = self.__class__()
2582 obj._value = self._value
2583 obj._bound_min = self._bound_min
2584 obj._bound_max = self._bound_max
2586 obj._expl = self._expl
2587 obj.default = self.default
2588 obj.optional = self.optional
2589 obj.offset = self.offset
2590 obj.llen = self.llen
2591 obj.vlen = self.vlen
2594 def __bytes__(self):
2595 self._assert_ready()
2598 def __eq__(self, their):
2599 if isinstance(their, binary_type):
2600 return self._value == their
2601 if not issubclass(their.__class__, OctetString):
2604 self._value == their._value and
2605 self.tag == their.tag and
2606 self._expl == their._expl
2609 def __lt__(self, their):
2610 return self._value < their._value
2621 return self.__class__(
2624 (self._bound_min, self._bound_max)
2625 if bounds is None else bounds
2627 impl=self.tag if impl is None else impl,
2628 expl=self._expl if expl is None else expl,
2629 default=self.default if default is None else default,
2630 optional=self.optional if optional is None else optional,
2634 self._assert_ready()
2637 len_encode(len(self._value)),
2641 def _decode_chunk(self, lv, offset, decode_path, ctx):
2643 l, llen, v = len_decode(lv)
2644 except DecodeError as err:
2645 raise err.__class__(
2647 klass=self.__class__,
2648 decode_path=decode_path,
2652 raise NotEnoughData(
2653 "encoded length is longer than data",
2654 klass=self.__class__,
2655 decode_path=decode_path,
2658 v, tail = v[:l], v[l:]
2660 obj = self.__class__(
2662 bounds=(self._bound_min, self._bound_max),
2665 default=self.default,
2666 optional=self.optional,
2667 _decoded=(offset, llen, l),
2669 except DecodeError as err:
2672 klass=self.__class__,
2673 decode_path=decode_path,
2676 except BoundsError as err:
2679 klass=self.__class__,
2680 decode_path=decode_path,
2685 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2687 t, tlen, lv = tag_strip(tlv)
2688 except DecodeError as err:
2689 raise err.__class__(
2691 klass=self.__class__,
2692 decode_path=decode_path,
2698 return self._decode_chunk(lv, offset, decode_path, ctx)
2699 if t == self.tag_constructed:
2700 if not ctx.get("bered", False):
2702 "unallowed BER constructed encoding",
2703 klass=self.__class__,
2704 decode_path=decode_path,
2711 l, llen, v = len_decode(lv)
2712 except LenIndefForm:
2713 llen, l, v = 1, 0, lv[1:]
2715 except DecodeError as err:
2716 raise err.__class__(
2718 klass=self.__class__,
2719 decode_path=decode_path,
2723 raise NotEnoughData(
2724 "encoded length is longer than data",
2725 klass=self.__class__,
2726 decode_path=decode_path,
2730 sub_offset = offset + tlen + llen
2734 if v[:EOC_LEN].tobytes() == EOC:
2741 "chunk out of bounds",
2742 klass=self.__class__,
2743 decode_path=decode_path + (str(len(chunks) - 1),),
2744 offset=chunks[-1].offset,
2746 sub_decode_path = decode_path + (str(len(chunks)),)
2748 chunk, v_tail = OctetString().decode(
2751 decode_path=sub_decode_path,
2757 "expected OctetString encoded chunk",
2758 klass=self.__class__,
2759 decode_path=sub_decode_path,
2762 chunks.append(chunk)
2763 sub_offset += chunk.tlvlen
2764 vlen += chunk.tlvlen
2767 obj = self.__class__(
2768 value=b"".join(bytes(chunk) for chunk in chunks),
2769 bounds=(self._bound_min, self._bound_max),
2772 default=self.default,
2773 optional=self.optional,
2774 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2776 except DecodeError as err:
2779 klass=self.__class__,
2780 decode_path=decode_path,
2783 except BoundsError as err:
2786 klass=self.__class__,
2787 decode_path=decode_path,
2790 obj.lenindef = lenindef
2791 obj.ber_encoded = True
2792 return obj, (v[EOC_LEN:] if lenindef else v)
2794 klass=self.__class__,
2795 decode_path=decode_path,
2800 return pp_console_row(next(self.pps()))
2802 def pps(self, decode_path=()):
2804 asn1_type_name=self.asn1_type_name,
2805 obj_name=self.__class__.__name__,
2806 decode_path=decode_path,
2807 value=("%d bytes" % len(self._value)) if self.ready else None,
2808 blob=self._value if self.ready else None,
2809 optional=self.optional,
2810 default=self == self.default,
2811 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2812 expl=None if self._expl is None else tag_decode(self._expl),
2817 expl_offset=self.expl_offset if self.expled else None,
2818 expl_tlen=self.expl_tlen if self.expled else None,
2819 expl_llen=self.expl_llen if self.expled else None,
2820 expl_vlen=self.expl_vlen if self.expled else None,
2821 expl_lenindef=self.expl_lenindef,
2822 lenindef=self.lenindef,
2823 ber_encoded=self.ber_encoded,
2826 defined_by, defined = self.defined or (None, None)
2827 if defined_by is not None:
2829 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2831 for pp in self.pps_lenindef(decode_path):
2836 """``NULL`` null object
2844 tag_default = tag_encode(5)
2845 asn1_type_name = "NULL"
2849 value=None, # unused, but Sequence passes it
2856 :param bytes impl: override default tag with ``IMPLICIT`` one
2857 :param bytes expl: override default tag with ``EXPLICIT`` one
2858 :param bool optional: is object ``OPTIONAL`` in sequence
2860 super(Null, self).__init__(impl, expl, None, optional, _decoded)
2868 obj = self.__class__()
2870 obj._expl = self._expl
2871 obj.default = self.default
2872 obj.optional = self.optional
2873 obj.offset = self.offset
2874 obj.llen = self.llen
2875 obj.vlen = self.vlen
2878 def __eq__(self, their):
2879 if not issubclass(their.__class__, Null):
2882 self.tag == their.tag and
2883 self._expl == their._expl
2893 return self.__class__(
2894 impl=self.tag if impl is None else impl,
2895 expl=self._expl if expl is None else expl,
2896 optional=self.optional if optional is None else optional,
2900 return self.tag + len_encode(0)
2902 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2904 t, _, lv = tag_strip(tlv)
2905 except DecodeError as err:
2906 raise err.__class__(
2908 klass=self.__class__,
2909 decode_path=decode_path,
2914 klass=self.__class__,
2915 decode_path=decode_path,
2918 if tag_only: # pragma: no cover
2921 l, _, v = len_decode(lv)
2922 except DecodeError as err:
2923 raise err.__class__(
2925 klass=self.__class__,
2926 decode_path=decode_path,
2930 raise InvalidLength(
2931 "Null must have zero length",
2932 klass=self.__class__,
2933 decode_path=decode_path,
2936 obj = self.__class__(
2939 optional=self.optional,
2940 _decoded=(offset, 1, 0),
2945 return pp_console_row(next(self.pps()))
2947 def pps(self, decode_path=()):
2949 asn1_type_name=self.asn1_type_name,
2950 obj_name=self.__class__.__name__,
2951 decode_path=decode_path,
2952 optional=self.optional,
2953 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2954 expl=None if self._expl is None else tag_decode(self._expl),
2959 expl_offset=self.expl_offset if self.expled else None,
2960 expl_tlen=self.expl_tlen if self.expled else None,
2961 expl_llen=self.expl_llen if self.expled else None,
2962 expl_vlen=self.expl_vlen if self.expled else None,
2963 expl_lenindef=self.expl_lenindef,
2966 for pp in self.pps_lenindef(decode_path):
2970 class ObjectIdentifier(Obj):
2971 """``OBJECT IDENTIFIER`` OID type
2973 >>> oid = ObjectIdentifier((1, 2, 3))
2974 OBJECT IDENTIFIER 1.2.3
2975 >>> oid == ObjectIdentifier("1.2.3")
2981 >>> oid + (4, 5) + ObjectIdentifier("1.7")
2982 OBJECT IDENTIFIER 1.2.3.4.5.1.7
2984 >>> str(ObjectIdentifier((3, 1)))
2985 Traceback (most recent call last):
2986 pyderasn.InvalidOID: unacceptable first arc value
2988 __slots__ = ("defines",)
2989 tag_default = tag_encode(6)
2990 asn1_type_name = "OBJECT IDENTIFIER"
3003 :param value: set the value. Either tuples of integers,
3004 string of "."-concatenated integers, or
3005 :py:class:`pyderasn.ObjectIdentifier` object
3006 :param defines: sequence of tuples. Each tuple has two elements.
3007 First one is relative to current one decode
3008 path, aiming to the field defined by that OID.
3009 Read about relative path in
3010 :py:func:`pyderasn.abs_decode_path`. Second
3011 tuple element is ``{OID: pyderasn.Obj()}``
3012 dictionary, mapping between current OID value
3013 and structure applied to defined field.
3014 :ref:`Read about DEFINED BY <definedby>`
3015 :param bytes impl: override default tag with ``IMPLICIT`` one
3016 :param bytes expl: override default tag with ``EXPLICIT`` one
3017 :param default: set default value. Type same as in ``value``
3018 :param bool optional: is object ``OPTIONAL`` in sequence
3020 super(ObjectIdentifier, self).__init__(
3028 if value is not None:
3029 self._value = self._value_sanitize(value)
3030 if default is not None:
3031 default = self._value_sanitize(default)
3032 self.default = self.__class__(
3037 if self._value is None:
3038 self._value = default
3039 self.defines = defines
3041 def __add__(self, their):
3042 if isinstance(their, self.__class__):
3043 return self.__class__(self._value + their._value)
3044 if isinstance(their, tuple):
3045 return self.__class__(self._value + their)
3046 raise InvalidValueType((self.__class__, tuple))
3048 def _value_sanitize(self, value):
3049 if issubclass(value.__class__, ObjectIdentifier):
3051 if isinstance(value, string_types):
3053 value = tuple(int(arc) for arc in value.split("."))
3055 raise InvalidOID("unacceptable arcs values")
3056 if isinstance(value, tuple):
3058 raise InvalidOID("less than 2 arcs")
3059 first_arc = value[0]
3060 if first_arc in (0, 1):
3061 if not (0 <= value[1] <= 39):
3062 raise InvalidOID("second arc is too wide")
3063 elif first_arc == 2:
3066 raise InvalidOID("unacceptable first arc value")
3068 raise InvalidValueType((self.__class__, str, tuple))
3072 return self._value is not None
3075 obj = self.__class__()
3076 obj._value = self._value
3077 obj.defines = self.defines
3079 obj._expl = self._expl
3080 obj.default = self.default
3081 obj.optional = self.optional
3082 obj.offset = self.offset
3083 obj.llen = self.llen
3084 obj.vlen = self.vlen
3088 self._assert_ready()
3089 return iter(self._value)
3092 return ".".join(str(arc) for arc in self._value or ())
3095 self._assert_ready()
3098 bytes(self._expl or b"") +
3099 str(self._value).encode("ascii"),
3102 def __eq__(self, their):
3103 if isinstance(their, tuple):
3104 return self._value == their
3105 if not issubclass(their.__class__, ObjectIdentifier):
3108 self.tag == their.tag and
3109 self._expl == their._expl and
3110 self._value == their._value
3113 def __lt__(self, their):
3114 return self._value < their._value
3125 return self.__class__(
3127 defines=self.defines if defines is None else defines,
3128 impl=self.tag if impl is None else impl,
3129 expl=self._expl if expl is None else expl,
3130 default=self.default if default is None else default,
3131 optional=self.optional if optional is None else optional,
3135 self._assert_ready()
3137 first_value = value[1]
3138 first_arc = value[0]
3141 elif first_arc == 1:
3143 elif first_arc == 2:
3145 else: # pragma: no cover
3146 raise RuntimeError("invalid arc is stored")
3147 octets = [zero_ended_encode(first_value)]
3148 for arc in value[2:]:
3149 octets.append(zero_ended_encode(arc))
3150 v = b"".join(octets)
3151 return b"".join((self.tag, len_encode(len(v)), v))
3153 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3155 t, _, lv = tag_strip(tlv)
3156 except DecodeError as err:
3157 raise err.__class__(
3159 klass=self.__class__,
3160 decode_path=decode_path,
3165 klass=self.__class__,
3166 decode_path=decode_path,
3169 if tag_only: # pragma: no cover
3172 l, llen, v = len_decode(lv)
3173 except DecodeError as err:
3174 raise err.__class__(
3176 klass=self.__class__,
3177 decode_path=decode_path,
3181 raise NotEnoughData(
3182 "encoded length is longer than data",
3183 klass=self.__class__,
3184 decode_path=decode_path,
3188 raise NotEnoughData(
3190 klass=self.__class__,
3191 decode_path=decode_path,
3194 v, tail = v[:l], v[l:]
3200 octet = indexbytes(v, i)
3201 arc = (arc << 7) | (octet & 0x7F)
3202 if octet & 0x80 == 0:
3210 klass=self.__class__,
3211 decode_path=decode_path,
3215 second_arc = arcs[0]
3216 if 0 <= second_arc <= 39:
3218 elif 40 <= second_arc <= 79:
3224 obj = self.__class__(
3225 value=tuple([first_arc, second_arc] + arcs[1:]),
3228 default=self.default,
3229 optional=self.optional,
3230 _decoded=(offset, llen, l),
3235 return pp_console_row(next(self.pps()))
3237 def pps(self, decode_path=()):
3239 asn1_type_name=self.asn1_type_name,
3240 obj_name=self.__class__.__name__,
3241 decode_path=decode_path,
3242 value=str(self) if self.ready else None,
3243 optional=self.optional,
3244 default=self == self.default,
3245 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3246 expl=None if self._expl is None else tag_decode(self._expl),
3251 expl_offset=self.expl_offset if self.expled else None,
3252 expl_tlen=self.expl_tlen if self.expled else None,
3253 expl_llen=self.expl_llen if self.expled else None,
3254 expl_vlen=self.expl_vlen if self.expled else None,
3255 expl_lenindef=self.expl_lenindef,
3258 for pp in self.pps_lenindef(decode_path):
3262 class Enumerated(Integer):
3263 """``ENUMERATED`` integer type
3265 This type is identical to :py:class:`pyderasn.Integer`, but requires
3266 schema to be specified and does not accept values missing from it.
3269 tag_default = tag_encode(10)
3270 asn1_type_name = "ENUMERATED"
3281 bounds=None, # dummy argument, workability for Integer.decode
3283 super(Enumerated, self).__init__(
3292 if len(self.specs) == 0:
3293 raise ValueError("schema must be specified")
3295 def _value_sanitize(self, value):
3296 if isinstance(value, self.__class__):
3297 value = value._value
3298 elif isinstance(value, integer_types):
3299 if value not in list(self.specs.values()):
3301 "unknown integer value: %s" % value,
3302 klass=self.__class__,
3304 elif isinstance(value, string_types):
3305 value = self.specs.get(value)
3307 raise ObjUnknown("integer value: %s" % value)
3309 raise InvalidValueType((self.__class__, int, str))
3313 obj = self.__class__(_specs=self.specs)
3314 obj._value = self._value
3315 obj._bound_min = self._bound_min
3316 obj._bound_max = self._bound_max
3318 obj._expl = self._expl
3319 obj.default = self.default
3320 obj.optional = self.optional
3321 obj.offset = self.offset
3322 obj.llen = self.llen
3323 obj.vlen = self.vlen
3335 return self.__class__(
3337 impl=self.tag if impl is None else impl,
3338 expl=self._expl if expl is None else expl,
3339 default=self.default if default is None else default,
3340 optional=self.optional if optional is None else optional,
3345 class CommonString(OctetString):
3346 """Common class for all strings
3348 Everything resembles :py:class:`pyderasn.OctetString`, except
3349 ability to deal with unicode text strings.
3351 >>> hexenc("привет мир".encode("utf-8"))
3352 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3353 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3355 >>> s = UTF8String("привет мир")
3356 UTF8String UTF8String привет мир
3358 'привет мир'
3359 >>> hexenc(bytes(s))
3360 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3362 >>> PrintableString("привет мир")
3363 Traceback (most recent call last):
3364 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3366 >>> BMPString("ада", bounds=(2, 2))
3367 Traceback (most recent call last):
3368 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3369 >>> s = BMPString("ад", bounds=(2, 2))
3372 >>> hexenc(bytes(s))
3380 * - :py:class:`pyderasn.UTF8String`
3382 * - :py:class:`pyderasn.NumericString`
3384 * - :py:class:`pyderasn.PrintableString`
3386 * - :py:class:`pyderasn.TeletexString`
3388 * - :py:class:`pyderasn.T61String`
3390 * - :py:class:`pyderasn.VideotexString`
3392 * - :py:class:`pyderasn.IA5String`
3394 * - :py:class:`pyderasn.GraphicString`
3396 * - :py:class:`pyderasn.VisibleString`
3398 * - :py:class:`pyderasn.ISO646String`
3400 * - :py:class:`pyderasn.GeneralString`
3402 * - :py:class:`pyderasn.UniversalString`
3404 * - :py:class:`pyderasn.BMPString`
3407 __slots__ = ("encoding",)
3409 def _value_sanitize(self, value):
3411 value_decoded = None
3412 if isinstance(value, self.__class__):
3413 value_raw = value._value
3414 elif isinstance(value, text_type):
3415 value_decoded = value
3416 elif isinstance(value, binary_type):
3419 raise InvalidValueType((self.__class__, text_type, binary_type))
3422 value_decoded.encode(self.encoding)
3423 if value_raw is None else value_raw
3426 value_raw.decode(self.encoding)
3427 if value_decoded is None else value_decoded
3429 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3430 raise DecodeError(str(err))
3431 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3439 def __eq__(self, their):
3440 if isinstance(their, binary_type):
3441 return self._value == their
3442 if isinstance(their, text_type):
3443 return self._value == their.encode(self.encoding)
3444 if not isinstance(their, self.__class__):
3447 self._value == their._value and
3448 self.tag == their.tag and
3449 self._expl == their._expl
3452 def __unicode__(self):
3454 return self._value.decode(self.encoding)
3455 return text_type(self._value)
3458 return pp_console_row(next(self.pps(no_unicode=PY2)))
3460 def pps(self, decode_path=(), no_unicode=False):
3463 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
3465 asn1_type_name=self.asn1_type_name,
3466 obj_name=self.__class__.__name__,
3467 decode_path=decode_path,
3469 optional=self.optional,
3470 default=self == self.default,
3471 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3472 expl=None if self._expl is None else tag_decode(self._expl),
3477 expl_offset=self.expl_offset if self.expled else None,
3478 expl_tlen=self.expl_tlen if self.expled else None,
3479 expl_llen=self.expl_llen if self.expled else None,
3480 expl_vlen=self.expl_vlen if self.expled else None,
3481 expl_lenindef=self.expl_lenindef,
3482 ber_encoded=self.ber_encoded,
3485 for pp in self.pps_lenindef(decode_path):
3489 class UTF8String(CommonString):
3491 tag_default = tag_encode(12)
3493 asn1_type_name = "UTF8String"
3496 class AllowableCharsMixin(object):
3498 def allowable_chars(self):
3500 return self._allowable_chars
3501 return set(six_unichr(c) for c in self._allowable_chars)
3504 class NumericString(AllowableCharsMixin, CommonString):
3507 Its value is properly sanitized: only ASCII digits with spaces can
3510 >>> NumericString().allowable_chars
3511 set(['3', '4', '7', '5', '1', '0', '8', '9', ' ', '6', '2'])
3514 tag_default = tag_encode(18)
3516 asn1_type_name = "NumericString"
3517 _allowable_chars = set(digits.encode("ascii") + b" ")
3519 def _value_sanitize(self, value):
3520 value = super(NumericString, self)._value_sanitize(value)
3521 if not set(value) <= self._allowable_chars:
3522 raise DecodeError("non-numeric value")
3526 class PrintableString(AllowableCharsMixin, CommonString):
3529 Its value is properly sanitized: see X.680 41.4 table 10.
3531 >>> PrintableString().allowable_chars
3532 >>> set([' ', "'", ..., 'z'])
3535 tag_default = tag_encode(19)
3537 asn1_type_name = "PrintableString"
3538 _allowable_chars = set(
3539 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3542 def _value_sanitize(self, value):
3543 value = super(PrintableString, self)._value_sanitize(value)
3544 if not set(value) <= self._allowable_chars:
3545 raise DecodeError("non-printable value")
3549 class TeletexString(CommonString):
3551 tag_default = tag_encode(20)
3553 asn1_type_name = "TeletexString"
3556 class T61String(TeletexString):
3558 asn1_type_name = "T61String"
3561 class VideotexString(CommonString):
3563 tag_default = tag_encode(21)
3564 encoding = "iso-8859-1"
3565 asn1_type_name = "VideotexString"
3568 class IA5String(CommonString):
3570 tag_default = tag_encode(22)
3572 asn1_type_name = "IA5"
3575 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3576 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3577 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3580 class UTCTime(CommonString):
3581 """``UTCTime`` datetime type
3583 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3584 UTCTime UTCTime 2017-09-30T22:07:50
3590 datetime.datetime(2017, 9, 30, 22, 7, 50)
3591 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3592 datetime.datetime(1957, 9, 30, 22, 7, 50)
3595 tag_default = tag_encode(23)
3597 asn1_type_name = "UTCTime"
3599 fmt = "%y%m%d%H%M%SZ"
3609 bounds=None, # dummy argument, workability for OctetString.decode
3612 :param value: set the value. Either datetime type, or
3613 :py:class:`pyderasn.UTCTime` object
3614 :param bytes impl: override default tag with ``IMPLICIT`` one
3615 :param bytes expl: override default tag with ``EXPLICIT`` one
3616 :param default: set default value. Type same as in ``value``
3617 :param bool optional: is object ``OPTIONAL`` in sequence
3619 super(UTCTime, self).__init__(
3627 if value is not None:
3628 self._value = self._value_sanitize(value)
3629 if default is not None:
3630 default = self._value_sanitize(default)
3631 self.default = self.__class__(
3636 if self._value is None:
3637 self._value = default
3639 def _value_sanitize(self, value):
3640 if isinstance(value, self.__class__):
3642 if isinstance(value, datetime):
3643 return value.strftime(self.fmt).encode("ascii")
3644 if isinstance(value, binary_type):
3646 value_decoded = value.decode("ascii")
3647 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3648 raise DecodeError("invalid UTCTime encoding")
3649 if len(value_decoded) == LEN_YYMMDDHHMMSSZ:
3651 datetime.strptime(value_decoded, self.fmt)
3652 except (TypeError, ValueError):
3653 raise DecodeError("invalid UTCTime format")
3656 raise DecodeError("invalid UTCTime length")
3657 raise InvalidValueType((self.__class__, datetime))
3659 def __eq__(self, their):
3660 if isinstance(their, binary_type):
3661 return self._value == their
3662 if isinstance(their, datetime):
3663 return self.todatetime() == their
3664 if not isinstance(their, self.__class__):
3667 self._value == their._value and
3668 self.tag == their.tag and
3669 self._expl == their._expl
3672 def todatetime(self):
3673 """Convert to datetime
3677 Pay attention that UTCTime can not hold full year, so all years
3678 having < 50 years are treated as 20xx, 19xx otherwise, according
3679 to X.509 recomendation.
3681 value = datetime.strptime(self._value.decode("ascii"), self.fmt)
3682 year = value.year % 100
3684 year=(2000 + year) if year < 50 else (1900 + year),
3688 minute=value.minute,
3689 second=value.second,
3693 return pp_console_row(next(self.pps()))
3695 def pps(self, decode_path=()):
3697 asn1_type_name=self.asn1_type_name,
3698 obj_name=self.__class__.__name__,
3699 decode_path=decode_path,
3700 value=self.todatetime().isoformat() if self.ready else None,
3701 optional=self.optional,
3702 default=self == self.default,
3703 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3704 expl=None if self._expl is None else tag_decode(self._expl),
3709 expl_offset=self.expl_offset if self.expled else None,
3710 expl_tlen=self.expl_tlen if self.expled else None,
3711 expl_llen=self.expl_llen if self.expled else None,
3712 expl_vlen=self.expl_vlen if self.expled else None,
3713 expl_lenindef=self.expl_lenindef,
3714 ber_encoded=self.ber_encoded,
3717 for pp in self.pps_lenindef(decode_path):
3721 class GeneralizedTime(UTCTime):
3722 """``GeneralizedTime`` datetime type
3724 This type is similar to :py:class:`pyderasn.UTCTime`.
3726 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3727 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3729 '20170930220750.000123Z'
3730 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3731 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3734 tag_default = tag_encode(24)
3735 asn1_type_name = "GeneralizedTime"
3737 fmt = "%Y%m%d%H%M%SZ"
3738 fmt_ms = "%Y%m%d%H%M%S.%fZ"
3740 def _value_sanitize(self, value):
3741 if isinstance(value, self.__class__):
3743 if isinstance(value, datetime):
3744 return value.strftime(
3745 self.fmt_ms if value.microsecond > 0 else self.fmt
3747 if isinstance(value, binary_type):
3749 value_decoded = value.decode("ascii")
3750 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3751 raise DecodeError("invalid GeneralizedTime encoding")
3752 if len(value_decoded) == LEN_YYYYMMDDHHMMSSZ:
3754 datetime.strptime(value_decoded, self.fmt)
3755 except (TypeError, ValueError):
3757 "invalid GeneralizedTime (without ms) format",
3760 elif len(value_decoded) >= LEN_YYYYMMDDHHMMSSDMZ:
3762 datetime.strptime(value_decoded, self.fmt_ms)
3763 except (TypeError, ValueError):
3765 "invalid GeneralizedTime (with ms) format",
3770 "invalid GeneralizedTime length",
3771 klass=self.__class__,
3773 raise InvalidValueType((self.__class__, datetime))
3775 def todatetime(self):
3776 value = self._value.decode("ascii")
3777 if len(value) == LEN_YYYYMMDDHHMMSSZ:
3778 return datetime.strptime(value, self.fmt)
3779 return datetime.strptime(value, self.fmt_ms)
3782 class GraphicString(CommonString):
3784 tag_default = tag_encode(25)
3785 encoding = "iso-8859-1"
3786 asn1_type_name = "GraphicString"
3789 class VisibleString(CommonString):
3791 tag_default = tag_encode(26)
3793 asn1_type_name = "VisibleString"
3796 class ISO646String(VisibleString):
3798 asn1_type_name = "ISO646String"
3801 class GeneralString(CommonString):
3803 tag_default = tag_encode(27)
3804 encoding = "iso-8859-1"
3805 asn1_type_name = "GeneralString"
3808 class UniversalString(CommonString):
3810 tag_default = tag_encode(28)
3811 encoding = "utf-32-be"
3812 asn1_type_name = "UniversalString"
3815 class BMPString(CommonString):
3817 tag_default = tag_encode(30)
3818 encoding = "utf-16-be"
3819 asn1_type_name = "BMPString"
3823 """``CHOICE`` special type
3827 class GeneralName(Choice):
3829 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
3830 ("dNSName", IA5String(impl=tag_ctxp(2))),
3833 >>> gn = GeneralName()
3835 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
3836 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3837 >>> gn["dNSName"] = IA5String("bar.baz")
3838 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
3839 >>> gn["rfc822Name"]
3842 [2] IA5String IA5 bar.baz
3845 >>> gn.value == gn["dNSName"]
3848 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
3850 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
3851 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3853 __slots__ = ("specs",)
3855 asn1_type_name = "CHOICE"
3868 :param value: set the value. Either ``(choice, value)`` tuple, or
3869 :py:class:`pyderasn.Choice` object
3870 :param bytes impl: can not be set, do **not** use it
3871 :param bytes expl: override default tag with ``EXPLICIT`` one
3872 :param default: set default value. Type same as in ``value``
3873 :param bool optional: is object ``OPTIONAL`` in sequence
3875 if impl is not None:
3876 raise ValueError("no implicit tag allowed for CHOICE")
3877 super(Choice, self).__init__(None, expl, default, optional, _decoded)
3879 schema = getattr(self, "schema", ())
3880 if len(schema) == 0:
3881 raise ValueError("schema must be specified")
3883 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3886 if value is not None:
3887 self._value = self._value_sanitize(value)
3888 if default is not None:
3889 default_value = self._value_sanitize(default)
3890 default_obj = self.__class__(impl=self.tag, expl=self._expl)
3891 default_obj.specs = self.specs
3892 default_obj._value = default_value
3893 self.default = default_obj
3895 self._value = default_obj.copy()._value
3897 def _value_sanitize(self, value):
3898 if isinstance(value, self.__class__):
3900 if isinstance(value, tuple) and len(value) == 2:
3902 spec = self.specs.get(choice)
3904 raise ObjUnknown(choice)
3905 if not isinstance(obj, spec.__class__):
3906 raise InvalidValueType((spec,))
3907 return (choice, spec(obj))
3908 raise InvalidValueType((self.__class__, tuple))
3912 return self._value is not None and self._value[1].ready
3916 return self.expl_lenindef or (
3917 (self._value is not None) and
3918 self._value[1].bered
3922 obj = self.__class__(schema=self.specs)
3923 obj._expl = self._expl
3924 obj.default = self.default
3925 obj.optional = self.optional
3926 obj.offset = self.offset
3927 obj.llen = self.llen
3928 obj.vlen = self.vlen
3930 if value is not None:
3931 obj._value = (value[0], value[1].copy())
3934 def __eq__(self, their):
3935 if isinstance(their, tuple) and len(their) == 2:
3936 return self._value == their
3937 if not isinstance(their, self.__class__):
3940 self.specs == their.specs and
3941 self._value == their._value
3951 return self.__class__(
3954 expl=self._expl if expl is None else expl,
3955 default=self.default if default is None else default,
3956 optional=self.optional if optional is None else optional,
3961 self._assert_ready()
3962 return self._value[0]
3966 self._assert_ready()
3967 return self._value[1]
3969 def __getitem__(self, key):
3970 if key not in self.specs:
3971 raise ObjUnknown(key)
3972 if self._value is None:
3974 choice, value = self._value
3979 def __setitem__(self, key, value):
3980 spec = self.specs.get(key)
3982 raise ObjUnknown(key)
3983 if not isinstance(value, spec.__class__):
3984 raise InvalidValueType((spec.__class__,))
3985 self._value = (key, spec(value))
3993 return self._value[1].decoded if self.ready else False
3996 self._assert_ready()
3997 return self._value[1].encode()
3999 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4000 for choice, spec in self.specs.items():
4001 sub_decode_path = decode_path + (choice,)
4007 decode_path=sub_decode_path,
4016 klass=self.__class__,
4017 decode_path=decode_path,
4020 if tag_only: # pragma: no cover
4022 value, tail = spec.decode(
4026 decode_path=sub_decode_path,
4029 obj = self.__class__(
4032 default=self.default,
4033 optional=self.optional,
4034 _decoded=(offset, 0, value.fulllen),
4036 obj._value = (choice, value)
4040 value = pp_console_row(next(self.pps()))
4042 value = "%s[%r]" % (value, self.value)
4045 def pps(self, decode_path=()):
4047 asn1_type_name=self.asn1_type_name,
4048 obj_name=self.__class__.__name__,
4049 decode_path=decode_path,
4050 value=self.choice if self.ready else None,
4051 optional=self.optional,
4052 default=self == self.default,
4053 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4054 expl=None if self._expl is None else tag_decode(self._expl),
4059 expl_lenindef=self.expl_lenindef,
4063 yield self.value.pps(decode_path=decode_path + (self.choice,))
4064 for pp in self.pps_lenindef(decode_path):
4068 class PrimitiveTypes(Choice):
4069 """Predefined ``CHOICE`` for all generic primitive types
4071 It could be useful for general decoding of some unspecified values:
4073 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4074 OCTET STRING 3 bytes 666f6f
4075 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4079 schema = tuple((klass.__name__, klass()) for klass in (
4104 """``ANY`` special type
4106 >>> Any(Integer(-123))
4108 >>> a = Any(OctetString(b"hello world").encode())
4109 ANY 040b68656c6c6f20776f726c64
4110 >>> hexenc(bytes(a))
4111 b'0x040x0bhello world'
4113 __slots__ = ("defined",)
4114 tag_default = tag_encode(0)
4115 asn1_type_name = "ANY"
4125 :param value: set the value. Either any kind of pyderasn's
4126 **ready** object, or bytes. Pay attention that
4127 **no** validation is performed is raw binary value
4129 :param bytes expl: override default tag with ``EXPLICIT`` one
4130 :param bool optional: is object ``OPTIONAL`` in sequence
4132 super(Any, self).__init__(None, expl, None, optional, _decoded)
4133 self._value = None if value is None else self._value_sanitize(value)
4136 def _value_sanitize(self, value):
4137 if isinstance(value, self.__class__):
4139 if isinstance(value, Obj):
4140 return value.encode()
4141 if isinstance(value, binary_type):
4143 raise InvalidValueType((self.__class__, Obj, binary_type))
4147 return self._value is not None
4151 if self.expl_lenindef or self.lenindef:
4153 if self.defined is None:
4155 return self.defined[1].bered
4158 obj = self.__class__()
4159 obj._value = self._value
4161 obj._expl = self._expl
4162 obj.optional = self.optional
4163 obj.offset = self.offset
4164 obj.llen = self.llen
4165 obj.vlen = self.vlen
4168 def __eq__(self, their):
4169 if isinstance(their, binary_type):
4170 return self._value == their
4171 if issubclass(their.__class__, Any):
4172 return self._value == their._value
4181 return self.__class__(
4183 expl=self._expl if expl is None else expl,
4184 optional=self.optional if optional is None else optional,
4187 def __bytes__(self):
4188 self._assert_ready()
4196 self._assert_ready()
4199 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4201 t, tlen, lv = tag_strip(tlv)
4202 except DecodeError as err:
4203 raise err.__class__(
4205 klass=self.__class__,
4206 decode_path=decode_path,
4210 l, llen, v = len_decode(lv)
4211 except LenIndefForm as err:
4212 if not ctx.get("bered", False):
4213 raise err.__class__(
4215 klass=self.__class__,
4216 decode_path=decode_path,
4219 llen, vlen, v = 1, 0, lv[1:]
4220 sub_offset = offset + tlen + llen
4222 while v[:EOC_LEN].tobytes() != EOC:
4223 chunk, v = Any().decode(
4226 decode_path=decode_path + (str(chunk_i),),
4230 vlen += chunk.tlvlen
4231 sub_offset += chunk.tlvlen
4233 tlvlen = tlen + llen + vlen + EOC_LEN
4234 obj = self.__class__(
4235 value=tlv[:tlvlen].tobytes(),
4237 optional=self.optional,
4238 _decoded=(offset, 0, tlvlen),
4242 return obj, v[EOC_LEN:]
4243 except DecodeError as err:
4244 raise err.__class__(
4246 klass=self.__class__,
4247 decode_path=decode_path,
4251 raise NotEnoughData(
4252 "encoded length is longer than data",
4253 klass=self.__class__,
4254 decode_path=decode_path,
4257 tlvlen = tlen + llen + l
4258 v, tail = tlv[:tlvlen], v[l:]
4259 obj = self.__class__(
4262 optional=self.optional,
4263 _decoded=(offset, 0, tlvlen),
4269 return pp_console_row(next(self.pps()))
4271 def pps(self, decode_path=()):
4273 asn1_type_name=self.asn1_type_name,
4274 obj_name=self.__class__.__name__,
4275 decode_path=decode_path,
4276 blob=self._value if self.ready else None,
4277 optional=self.optional,
4278 default=self == self.default,
4279 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4280 expl=None if self._expl is None else tag_decode(self._expl),
4285 expl_offset=self.expl_offset if self.expled else None,
4286 expl_tlen=self.expl_tlen if self.expled else None,
4287 expl_llen=self.expl_llen if self.expled else None,
4288 expl_vlen=self.expl_vlen if self.expled else None,
4289 expl_lenindef=self.expl_lenindef,
4290 lenindef=self.lenindef,
4293 defined_by, defined = self.defined or (None, None)
4294 if defined_by is not None:
4296 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4298 for pp in self.pps_lenindef(decode_path):
4302 ########################################################################
4303 # ASN.1 constructed types
4304 ########################################################################
4306 def get_def_by_path(defines_by_path, sub_decode_path):
4307 """Get define by decode path
4309 for path, define in defines_by_path:
4310 if len(path) != len(sub_decode_path):
4312 for p1, p2 in zip(path, sub_decode_path):
4313 if (p1 != any) and (p1 != p2):
4319 def abs_decode_path(decode_path, rel_path):
4320 """Create an absolute decode path from current and relative ones
4322 :param decode_path: current decode path, starting point.
4324 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4325 If first tuple's element is "/", then treat it as
4326 an absolute path, ignoring ``decode_path`` as
4327 starting point. Also this tuple can contain ".."
4328 elements, stripping the leading element from
4331 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4332 ("foo", "bar", "baz", "whatever")
4333 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4335 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4338 if rel_path[0] == "/":
4340 if rel_path[0] == "..":
4341 return abs_decode_path(decode_path[:-1], rel_path[1:])
4342 return decode_path + rel_path
4345 class Sequence(Obj):
4346 """``SEQUENCE`` structure type
4348 You have to make specification of sequence::
4350 class Extension(Sequence):
4352 ("extnID", ObjectIdentifier()),
4353 ("critical", Boolean(default=False)),
4354 ("extnValue", OctetString()),
4357 Then, you can work with it as with dictionary.
4359 >>> ext = Extension()
4360 >>> Extension().specs
4362 ('extnID', OBJECT IDENTIFIER),
4363 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4364 ('extnValue', OCTET STRING),
4366 >>> ext["extnID"] = "1.2.3"
4367 Traceback (most recent call last):
4368 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4369 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4371 You can determine if sequence is ready to be encoded:
4376 Traceback (most recent call last):
4377 pyderasn.ObjNotReady: object is not ready: extnValue
4378 >>> ext["extnValue"] = OctetString(b"foobar")
4382 Value you want to assign, must have the same **type** as in
4383 corresponding specification, but it can have different tags,
4384 optional/default attributes -- they will be taken from specification
4387 class TBSCertificate(Sequence):
4389 ("version", Version(expl=tag_ctxc(0), default="v1")),
4392 >>> tbs = TBSCertificate()
4393 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4395 Assign ``None`` to remove value from sequence.
4397 You can set values in Sequence during its initialization:
4399 >>> AlgorithmIdentifier((
4400 ("algorithm", ObjectIdentifier("1.2.3")),
4401 ("parameters", Any(Null()))
4403 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4405 You can determine if value exists/set in the sequence and take its value:
4407 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4410 OBJECT IDENTIFIER 1.2.3
4412 But pay attention that if value has default, then it won't be (not
4413 in) in the sequence (because ``DEFAULT`` must not be encoded in
4414 DER), but you can read its value:
4416 >>> "critical" in ext, ext["critical"]
4417 (False, BOOLEAN False)
4418 >>> ext["critical"] = Boolean(True)
4419 >>> "critical" in ext, ext["critical"]
4420 (True, BOOLEAN True)
4422 All defaulted values are always optional.
4424 .. _allow_default_values_ctx:
4426 DER prohibits default value encoding and will raise an error if
4427 default value is unexpectedly met during decode.
4428 If :ref:`bered <bered_ctx>` context option is set, then no error
4429 will be raised, but ``bered`` attribute set. You can disable strict
4430 defaulted values existence validation by setting
4431 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4433 Two sequences are equal if they have equal specification (schema),
4434 implicit/explicit tagging and the same values.
4436 __slots__ = ("specs",)
4437 tag_default = tag_encode(form=TagFormConstructed, num=16)
4438 asn1_type_name = "SEQUENCE"
4450 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4452 schema = getattr(self, "schema", ())
4454 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4457 if value is not None:
4458 if issubclass(value.__class__, Sequence):
4459 self._value = value._value
4460 elif hasattr(value, "__iter__"):
4461 for seq_key, seq_value in value:
4462 self[seq_key] = seq_value
4464 raise InvalidValueType((Sequence,))
4465 if default is not None:
4466 if not issubclass(default.__class__, Sequence):
4467 raise InvalidValueType((Sequence,))
4468 default_value = default._value
4469 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4470 default_obj.specs = self.specs
4471 default_obj._value = default_value
4472 self.default = default_obj
4474 self._value = default_obj.copy()._value
4478 for name, spec in self.specs.items():
4479 value = self._value.get(name)
4491 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4493 return any(value.bered for value in self._value.values())
4496 obj = self.__class__(schema=self.specs)
4498 obj._expl = self._expl
4499 obj.default = self.default
4500 obj.optional = self.optional
4501 obj.offset = self.offset
4502 obj.llen = self.llen
4503 obj.vlen = self.vlen
4504 obj._value = {k: v.copy() for k, v in self._value.items()}
4507 def __eq__(self, their):
4508 if not isinstance(their, self.__class__):
4511 self.specs == their.specs and
4512 self.tag == their.tag and
4513 self._expl == their._expl and
4514 self._value == their._value
4525 return self.__class__(
4528 impl=self.tag if impl is None else impl,
4529 expl=self._expl if expl is None else expl,
4530 default=self.default if default is None else default,
4531 optional=self.optional if optional is None else optional,
4534 def __contains__(self, key):
4535 return key in self._value
4537 def __setitem__(self, key, value):
4538 spec = self.specs.get(key)
4540 raise ObjUnknown(key)
4542 self._value.pop(key, None)
4544 if not isinstance(value, spec.__class__):
4545 raise InvalidValueType((spec.__class__,))
4546 value = spec(value=value)
4547 if spec.default is not None and value == spec.default:
4548 self._value.pop(key, None)
4550 self._value[key] = value
4552 def __getitem__(self, key):
4553 value = self._value.get(key)
4554 if value is not None:
4556 spec = self.specs.get(key)
4558 raise ObjUnknown(key)
4559 if spec.default is not None:
4563 def _encoded_values(self):
4565 for name, spec in self.specs.items():
4566 value = self._value.get(name)
4570 raise ObjNotReady(name)
4571 raws.append(value.encode())
4575 v = b"".join(self._encoded_values())
4576 return b"".join((self.tag, len_encode(len(v)), v))
4578 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4580 t, tlen, lv = tag_strip(tlv)
4581 except DecodeError as err:
4582 raise err.__class__(
4584 klass=self.__class__,
4585 decode_path=decode_path,
4590 klass=self.__class__,
4591 decode_path=decode_path,
4594 if tag_only: # pragma: no cover
4597 ctx_bered = ctx.get("bered", False)
4599 l, llen, v = len_decode(lv)
4600 except LenIndefForm as err:
4602 raise err.__class__(
4604 klass=self.__class__,
4605 decode_path=decode_path,
4608 l, llen, v = 0, 1, lv[1:]
4610 except DecodeError as err:
4611 raise err.__class__(
4613 klass=self.__class__,
4614 decode_path=decode_path,
4618 raise NotEnoughData(
4619 "encoded length is longer than data",
4620 klass=self.__class__,
4621 decode_path=decode_path,
4625 v, tail = v[:l], v[l:]
4627 sub_offset = offset + tlen + llen
4630 ctx_allow_default_values = ctx.get("allow_default_values", False)
4631 for name, spec in self.specs.items():
4632 if spec.optional and (
4633 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4637 sub_decode_path = decode_path + (name,)
4639 value, v_tail = spec.decode(
4643 decode_path=sub_decode_path,
4651 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4652 if defined is not None:
4653 defined_by, defined_spec = defined
4654 if issubclass(value.__class__, SequenceOf):
4655 for i, _value in enumerate(value):
4656 sub_sub_decode_path = sub_decode_path + (
4658 DecodePathDefBy(defined_by),
4660 defined_value, defined_tail = defined_spec.decode(
4661 memoryview(bytes(_value)),
4663 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4664 if value.expled else (value.tlen + value.llen)
4667 decode_path=sub_sub_decode_path,
4670 if len(defined_tail) > 0:
4673 klass=self.__class__,
4674 decode_path=sub_sub_decode_path,
4677 _value.defined = (defined_by, defined_value)
4679 defined_value, defined_tail = defined_spec.decode(
4680 memoryview(bytes(value)),
4682 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4683 if value.expled else (value.tlen + value.llen)
4686 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4689 if len(defined_tail) > 0:
4692 klass=self.__class__,
4693 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4696 value.defined = (defined_by, defined_value)
4698 value_len = value.fulllen
4700 sub_offset += value_len
4702 if spec.default is not None and value == spec.default:
4703 if ctx_bered or ctx_allow_default_values:
4707 "DEFAULT value met",
4708 klass=self.__class__,
4709 decode_path=sub_decode_path,
4712 values[name] = value
4714 spec_defines = getattr(spec, "defines", ())
4715 if len(spec_defines) == 0:
4716 defines_by_path = ctx.get("defines_by_path", ())
4717 if len(defines_by_path) > 0:
4718 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4719 if spec_defines is not None and len(spec_defines) > 0:
4720 for rel_path, schema in spec_defines:
4721 defined = schema.get(value, None)
4722 if defined is not None:
4723 ctx.setdefault("_defines", []).append((
4724 abs_decode_path(sub_decode_path[:-1], rel_path),
4728 if v[:EOC_LEN].tobytes() != EOC:
4731 klass=self.__class__,
4732 decode_path=decode_path,
4740 klass=self.__class__,
4741 decode_path=decode_path,
4744 obj = self.__class__(
4748 default=self.default,
4749 optional=self.optional,
4750 _decoded=(offset, llen, vlen),
4753 obj.lenindef = lenindef
4754 obj.ber_encoded = ber_encoded
4758 value = pp_console_row(next(self.pps()))
4760 for name in self.specs:
4761 _value = self._value.get(name)
4764 cols.append("%s: %s" % (name, repr(_value)))
4765 return "%s[%s]" % (value, "; ".join(cols))
4767 def pps(self, decode_path=()):
4769 asn1_type_name=self.asn1_type_name,
4770 obj_name=self.__class__.__name__,
4771 decode_path=decode_path,
4772 optional=self.optional,
4773 default=self == self.default,
4774 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4775 expl=None if self._expl is None else tag_decode(self._expl),
4780 expl_offset=self.expl_offset if self.expled else None,
4781 expl_tlen=self.expl_tlen if self.expled else None,
4782 expl_llen=self.expl_llen if self.expled else None,
4783 expl_vlen=self.expl_vlen if self.expled else None,
4784 expl_lenindef=self.expl_lenindef,
4785 lenindef=self.lenindef,
4786 ber_encoded=self.ber_encoded,
4789 for name in self.specs:
4790 value = self._value.get(name)
4793 yield value.pps(decode_path=decode_path + (name,))
4794 for pp in self.pps_lenindef(decode_path):
4798 class Set(Sequence):
4799 """``SET`` structure type
4801 Its usage is identical to :py:class:`pyderasn.Sequence`.
4803 .. _allow_unordered_set_ctx:
4805 DER prohibits unordered values encoding and will raise an error
4806 during decode. If If :ref:`bered <bered_ctx>` context option is set,
4807 then no error will occure. Also you can disable strict values
4808 ordering check by setting ``"allow_unordered_set": True``
4809 :ref:`context <ctx>` option.
4812 tag_default = tag_encode(form=TagFormConstructed, num=17)
4813 asn1_type_name = "SET"
4816 raws = self._encoded_values()
4819 return b"".join((self.tag, len_encode(len(v)), v))
4821 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4823 t, tlen, lv = tag_strip(tlv)
4824 except DecodeError as err:
4825 raise err.__class__(
4827 klass=self.__class__,
4828 decode_path=decode_path,
4833 klass=self.__class__,
4834 decode_path=decode_path,
4840 ctx_bered = ctx.get("bered", False)
4842 l, llen, v = len_decode(lv)
4843 except LenIndefForm as err:
4845 raise err.__class__(
4847 klass=self.__class__,
4848 decode_path=decode_path,
4851 l, llen, v = 0, 1, lv[1:]
4853 except DecodeError as err:
4854 raise err.__class__(
4856 klass=self.__class__,
4857 decode_path=decode_path,
4861 raise NotEnoughData(
4862 "encoded length is longer than data",
4863 klass=self.__class__,
4867 v, tail = v[:l], v[l:]
4869 sub_offset = offset + tlen + llen
4872 ctx_allow_default_values = ctx.get("allow_default_values", False)
4873 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
4874 value_prev = memoryview(v[:0])
4875 specs_items = self.specs.items
4877 if lenindef and v[:EOC_LEN].tobytes() == EOC:
4879 for name, spec in specs_items():
4880 sub_decode_path = decode_path + (name,)
4886 decode_path=sub_decode_path,
4895 klass=self.__class__,
4896 decode_path=decode_path,
4899 value, v_tail = spec.decode(
4903 decode_path=sub_decode_path,
4906 value_len = value.fulllen
4907 if value_prev.tobytes() > v[:value_len].tobytes():
4908 if ctx_bered or ctx_allow_unordered_set:
4912 "unordered " + self.asn1_type_name,
4913 klass=self.__class__,
4914 decode_path=sub_decode_path,
4917 if spec.default is None or value != spec.default:
4919 elif ctx_bered or ctx_allow_default_values:
4923 "DEFAULT value met",
4924 klass=self.__class__,
4925 decode_path=sub_decode_path,
4928 values[name] = value
4929 value_prev = v[:value_len]
4930 sub_offset += value_len
4933 obj = self.__class__(
4937 default=self.default,
4938 optional=self.optional,
4939 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
4942 if v[:EOC_LEN].tobytes() != EOC:
4945 klass=self.__class__,
4946 decode_path=decode_path,
4954 "not all values are ready",
4955 klass=self.__class__,
4956 decode_path=decode_path,
4959 obj.ber_encoded = ber_encoded
4963 class SequenceOf(Obj):
4964 """``SEQUENCE OF`` sequence type
4966 For that kind of type you must specify the object it will carry on
4967 (bounds are for example here, not required)::
4969 class Ints(SequenceOf):
4974 >>> ints.append(Integer(123))
4975 >>> ints.append(Integer(234))
4977 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
4978 >>> [int(i) for i in ints]
4980 >>> ints.append(Integer(345))
4981 Traceback (most recent call last):
4982 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
4985 >>> ints[1] = Integer(345)
4987 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
4989 Also you can initialize sequence with preinitialized values:
4991 >>> ints = Ints([Integer(123), Integer(234)])
4993 __slots__ = ("spec", "_bound_min", "_bound_max")
4994 tag_default = tag_encode(form=TagFormConstructed, num=16)
4995 asn1_type_name = "SEQUENCE OF"
5008 super(SequenceOf, self).__init__(
5016 schema = getattr(self, "schema", None)
5018 raise ValueError("schema must be specified")
5020 self._bound_min, self._bound_max = getattr(
5024 ) if bounds is None else bounds
5026 if value is not None:
5027 self._value = self._value_sanitize(value)
5028 if default is not None:
5029 default_value = self._value_sanitize(default)
5030 default_obj = self.__class__(
5035 default_obj._value = default_value
5036 self.default = default_obj
5038 self._value = default_obj.copy()._value
5040 def _value_sanitize(self, value):
5041 if issubclass(value.__class__, SequenceOf):
5042 value = value._value
5043 elif hasattr(value, "__iter__"):
5046 raise InvalidValueType((self.__class__, iter))
5047 if not self._bound_min <= len(value) <= self._bound_max:
5048 raise BoundsError(self._bound_min, len(value), self._bound_max)
5050 if not isinstance(v, self.spec.__class__):
5051 raise InvalidValueType((self.spec.__class__,))
5056 return all(v.ready for v in self._value)
5060 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5062 return any(v.bered for v in self._value)
5065 obj = self.__class__(schema=self.spec)
5066 obj._bound_min = self._bound_min
5067 obj._bound_max = self._bound_max
5069 obj._expl = self._expl
5070 obj.default = self.default
5071 obj.optional = self.optional
5072 obj.offset = self.offset
5073 obj.llen = self.llen
5074 obj.vlen = self.vlen
5075 obj._value = [v.copy() for v in self._value]
5078 def __eq__(self, their):
5079 if isinstance(their, self.__class__):
5081 self.spec == their.spec and
5082 self.tag == their.tag and
5083 self._expl == their._expl and
5084 self._value == their._value
5086 if hasattr(their, "__iter__"):
5087 return self._value == list(their)
5099 return self.__class__(
5103 (self._bound_min, self._bound_max)
5104 if bounds is None else bounds
5106 impl=self.tag if impl is None else impl,
5107 expl=self._expl if expl is None else expl,
5108 default=self.default if default is None else default,
5109 optional=self.optional if optional is None else optional,
5112 def __contains__(self, key):
5113 return key in self._value
5115 def append(self, value):
5116 if not isinstance(value, self.spec.__class__):
5117 raise InvalidValueType((self.spec.__class__,))
5118 if len(self._value) + 1 > self._bound_max:
5121 len(self._value) + 1,
5124 self._value.append(value)
5127 self._assert_ready()
5128 return iter(self._value)
5131 self._assert_ready()
5132 return len(self._value)
5134 def __setitem__(self, key, value):
5135 if not isinstance(value, self.spec.__class__):
5136 raise InvalidValueType((self.spec.__class__,))
5137 self._value[key] = self.spec(value=value)
5139 def __getitem__(self, key):
5140 return self._value[key]
5142 def _encoded_values(self):
5143 return [v.encode() for v in self._value]
5146 v = b"".join(self._encoded_values())
5147 return b"".join((self.tag, len_encode(len(v)), v))
5149 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5151 t, tlen, lv = tag_strip(tlv)
5152 except DecodeError as err:
5153 raise err.__class__(
5155 klass=self.__class__,
5156 decode_path=decode_path,
5161 klass=self.__class__,
5162 decode_path=decode_path,
5168 ctx_bered = ctx.get("bered", False)
5170 l, llen, v = len_decode(lv)
5171 except LenIndefForm as err:
5173 raise err.__class__(
5175 klass=self.__class__,
5176 decode_path=decode_path,
5179 l, llen, v = 0, 1, lv[1:]
5181 except DecodeError as err:
5182 raise err.__class__(
5184 klass=self.__class__,
5185 decode_path=decode_path,
5189 raise NotEnoughData(
5190 "encoded length is longer than data",
5191 klass=self.__class__,
5192 decode_path=decode_path,
5196 v, tail = v[:l], v[l:]
5198 sub_offset = offset + tlen + llen
5200 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5201 value_prev = memoryview(v[:0])
5205 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5207 sub_decode_path = decode_path + (str(len(_value)),)
5208 value, v_tail = spec.decode(
5212 decode_path=sub_decode_path,
5215 value_len = value.fulllen
5217 if value_prev.tobytes() > v[:value_len].tobytes():
5218 if ctx_bered or ctx_allow_unordered_set:
5222 "unordered " + self.asn1_type_name,
5223 klass=self.__class__,
5224 decode_path=sub_decode_path,
5227 value_prev = v[:value_len]
5228 _value.append(value)
5229 sub_offset += value_len
5233 obj = self.__class__(
5236 bounds=(self._bound_min, self._bound_max),
5239 default=self.default,
5240 optional=self.optional,
5241 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5243 except BoundsError as err:
5246 klass=self.__class__,
5247 decode_path=decode_path,
5251 if v[:EOC_LEN].tobytes() != EOC:
5254 klass=self.__class__,
5255 decode_path=decode_path,
5260 obj.ber_encoded = ber_encoded
5265 pp_console_row(next(self.pps())),
5266 ", ".join(repr(v) for v in self._value),
5269 def pps(self, decode_path=()):
5271 asn1_type_name=self.asn1_type_name,
5272 obj_name=self.__class__.__name__,
5273 decode_path=decode_path,
5274 optional=self.optional,
5275 default=self == self.default,
5276 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5277 expl=None if self._expl is None else tag_decode(self._expl),
5282 expl_offset=self.expl_offset if self.expled else None,
5283 expl_tlen=self.expl_tlen if self.expled else None,
5284 expl_llen=self.expl_llen if self.expled else None,
5285 expl_vlen=self.expl_vlen if self.expled else None,
5286 expl_lenindef=self.expl_lenindef,
5287 lenindef=self.lenindef,
5288 ber_encoded=self.ber_encoded,
5291 for i, value in enumerate(self._value):
5292 yield value.pps(decode_path=decode_path + (str(i),))
5293 for pp in self.pps_lenindef(decode_path):
5297 class SetOf(SequenceOf):
5298 """``SET OF`` sequence type
5300 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5303 tag_default = tag_encode(form=TagFormConstructed, num=17)
5304 asn1_type_name = "SET OF"
5307 raws = self._encoded_values()
5310 return b"".join((self.tag, len_encode(len(v)), v))
5312 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5313 return super(SetOf, self)._decode(
5319 ordering_check=True,
5323 def obj_by_path(pypath): # pragma: no cover
5324 """Import object specified as string Python path
5326 Modules must be separated from classes/functions with ``:``.
5328 >>> obj_by_path("foo.bar:Baz")
5329 <class 'foo.bar.Baz'>
5330 >>> obj_by_path("foo.bar:Baz.boo")
5331 <classmethod 'foo.bar.Baz.boo'>
5333 mod, objs = pypath.rsplit(":", 1)
5334 from importlib import import_module
5335 obj = import_module(mod)
5336 for obj_name in objs.split("."):
5337 obj = getattr(obj, obj_name)
5341 def generic_decoder(): # pragma: no cover
5342 # All of this below is a big hack with self references
5343 choice = PrimitiveTypes()
5344 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5345 choice.specs["SetOf"] = SetOf(schema=choice)
5347 choice.specs["SequenceOf%d" % i] = SequenceOf(
5351 choice.specs["Any"] = Any()
5353 # Class name equals to type name, to omit it from output
5354 class SEQUENCEOF(SequenceOf):
5362 with_decode_path=False,
5363 decode_path_only=(),
5365 def _pprint_pps(pps):
5367 if hasattr(pp, "_fields"):
5369 decode_path_only != () and
5370 pp.decode_path[:len(decode_path_only)] != decode_path_only
5373 if pp.asn1_type_name == Choice.asn1_type_name:
5375 pp_kwargs = pp._asdict()
5376 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5377 pp = _pp(**pp_kwargs)
5378 yield pp_console_row(
5383 with_colours=with_colours,
5384 with_decode_path=with_decode_path,
5385 decode_path_len_decrease=len(decode_path_only),
5387 for row in pp_console_blob(
5389 decode_path_len_decrease=len(decode_path_only),
5393 for row in _pprint_pps(pp):
5395 return "\n".join(_pprint_pps(obj.pps()))
5396 return SEQUENCEOF(), pprint_any
5399 def main(): # pragma: no cover
5401 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5402 parser.add_argument(
5406 help="Skip that number of bytes from the beginning",
5408 parser.add_argument(
5410 help="Python path to dictionary with OIDs",
5412 parser.add_argument(
5414 help="Python path to schema definition to use",
5416 parser.add_argument(
5417 "--defines-by-path",
5418 help="Python path to decoder's defines_by_path",
5420 parser.add_argument(
5422 action="store_true",
5423 help="Disallow BER encoding",
5425 parser.add_argument(
5426 "--print-decode-path",
5427 action="store_true",
5428 help="Print decode paths",
5430 parser.add_argument(
5431 "--decode-path-only",
5432 help="Print only specified decode path",
5434 parser.add_argument(
5436 action="store_true",
5437 help="Allow explicit tag out-of-bound",
5439 parser.add_argument(
5441 type=argparse.FileType("rb"),
5442 help="Path to DER file you want to decode",
5444 args = parser.parse_args()
5445 args.DERFile.seek(args.skip)
5446 der = memoryview(args.DERFile.read())
5447 args.DERFile.close()
5448 oids = obj_by_path(args.oids) if args.oids else {}
5450 schema = obj_by_path(args.schema)
5451 from functools import partial
5452 pprinter = partial(pprint, big_blobs=True)
5454 schema, pprinter = generic_decoder()
5456 "bered": not args.nobered,
5457 "allow_expl_oob": args.allow_expl_oob,
5459 if args.defines_by_path is not None:
5460 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5461 obj, tail = schema().decode(der, ctx=ctx)
5465 with_colours=True if environ.get("NO_COLOR") is None else False,
5466 with_decode_path=args.print_decode_path,
5468 () if args.decode_path_only is None else
5469 tuple(args.decode_path_only.split(":"))
5473 print("\nTrailing data: %s" % hexenc(tail))
5476 if __name__ == "__main__":