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. Tuple of strings
4323 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4324 If first tuple's element is "/", then treat it as
4325 an absolute path, ignoring ``decode_path`` as
4326 starting point. Also this tuple can contain ".."
4327 elements, stripping the leading element from
4330 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4331 ("foo", "bar", "baz", "whatever")
4332 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4334 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4337 if rel_path[0] == "/":
4339 if rel_path[0] == "..":
4340 return abs_decode_path(decode_path[:-1], rel_path[1:])
4341 return decode_path + rel_path
4344 class Sequence(Obj):
4345 """``SEQUENCE`` structure type
4347 You have to make specification of sequence::
4349 class Extension(Sequence):
4351 ("extnID", ObjectIdentifier()),
4352 ("critical", Boolean(default=False)),
4353 ("extnValue", OctetString()),
4356 Then, you can work with it as with dictionary.
4358 >>> ext = Extension()
4359 >>> Extension().specs
4361 ('extnID', OBJECT IDENTIFIER),
4362 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4363 ('extnValue', OCTET STRING),
4365 >>> ext["extnID"] = "1.2.3"
4366 Traceback (most recent call last):
4367 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4368 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4370 You can determine if sequence is ready to be encoded:
4375 Traceback (most recent call last):
4376 pyderasn.ObjNotReady: object is not ready: extnValue
4377 >>> ext["extnValue"] = OctetString(b"foobar")
4381 Value you want to assign, must have the same **type** as in
4382 corresponding specification, but it can have different tags,
4383 optional/default attributes -- they will be taken from specification
4386 class TBSCertificate(Sequence):
4388 ("version", Version(expl=tag_ctxc(0), default="v1")),
4391 >>> tbs = TBSCertificate()
4392 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4394 Assign ``None`` to remove value from sequence.
4396 You can set values in Sequence during its initialization:
4398 >>> AlgorithmIdentifier((
4399 ("algorithm", ObjectIdentifier("1.2.3")),
4400 ("parameters", Any(Null()))
4402 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4404 You can determine if value exists/set in the sequence and take its value:
4406 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4409 OBJECT IDENTIFIER 1.2.3
4411 But pay attention that if value has default, then it won't be (not
4412 in) in the sequence (because ``DEFAULT`` must not be encoded in
4413 DER), but you can read its value:
4415 >>> "critical" in ext, ext["critical"]
4416 (False, BOOLEAN False)
4417 >>> ext["critical"] = Boolean(True)
4418 >>> "critical" in ext, ext["critical"]
4419 (True, BOOLEAN True)
4421 All defaulted values are always optional.
4423 .. _allow_default_values_ctx:
4425 DER prohibits default value encoding and will raise an error if
4426 default value is unexpectedly met during decode.
4427 If :ref:`bered <bered_ctx>` context option is set, then no error
4428 will be raised, but ``bered`` attribute set. You can disable strict
4429 defaulted values existence validation by setting
4430 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4432 Two sequences are equal if they have equal specification (schema),
4433 implicit/explicit tagging and the same values.
4435 __slots__ = ("specs",)
4436 tag_default = tag_encode(form=TagFormConstructed, num=16)
4437 asn1_type_name = "SEQUENCE"
4449 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4451 schema = getattr(self, "schema", ())
4453 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4456 if value is not None:
4457 if issubclass(value.__class__, Sequence):
4458 self._value = value._value
4459 elif hasattr(value, "__iter__"):
4460 for seq_key, seq_value in value:
4461 self[seq_key] = seq_value
4463 raise InvalidValueType((Sequence,))
4464 if default is not None:
4465 if not issubclass(default.__class__, Sequence):
4466 raise InvalidValueType((Sequence,))
4467 default_value = default._value
4468 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4469 default_obj.specs = self.specs
4470 default_obj._value = default_value
4471 self.default = default_obj
4473 self._value = default_obj.copy()._value
4477 for name, spec in self.specs.items():
4478 value = self._value.get(name)
4490 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4492 return any(value.bered for value in self._value.values())
4495 obj = self.__class__(schema=self.specs)
4497 obj._expl = self._expl
4498 obj.default = self.default
4499 obj.optional = self.optional
4500 obj.offset = self.offset
4501 obj.llen = self.llen
4502 obj.vlen = self.vlen
4503 obj._value = {k: v.copy() for k, v in self._value.items()}
4506 def __eq__(self, their):
4507 if not isinstance(their, self.__class__):
4510 self.specs == their.specs and
4511 self.tag == their.tag and
4512 self._expl == their._expl and
4513 self._value == their._value
4524 return self.__class__(
4527 impl=self.tag if impl is None else impl,
4528 expl=self._expl if expl is None else expl,
4529 default=self.default if default is None else default,
4530 optional=self.optional if optional is None else optional,
4533 def __contains__(self, key):
4534 return key in self._value
4536 def __setitem__(self, key, value):
4537 spec = self.specs.get(key)
4539 raise ObjUnknown(key)
4541 self._value.pop(key, None)
4543 if not isinstance(value, spec.__class__):
4544 raise InvalidValueType((spec.__class__,))
4545 value = spec(value=value)
4546 if spec.default is not None and value == spec.default:
4547 self._value.pop(key, None)
4549 self._value[key] = value
4551 def __getitem__(self, key):
4552 value = self._value.get(key)
4553 if value is not None:
4555 spec = self.specs.get(key)
4557 raise ObjUnknown(key)
4558 if spec.default is not None:
4562 def _encoded_values(self):
4564 for name, spec in self.specs.items():
4565 value = self._value.get(name)
4569 raise ObjNotReady(name)
4570 raws.append(value.encode())
4574 v = b"".join(self._encoded_values())
4575 return b"".join((self.tag, len_encode(len(v)), v))
4577 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4579 t, tlen, lv = tag_strip(tlv)
4580 except DecodeError as err:
4581 raise err.__class__(
4583 klass=self.__class__,
4584 decode_path=decode_path,
4589 klass=self.__class__,
4590 decode_path=decode_path,
4593 if tag_only: # pragma: no cover
4596 ctx_bered = ctx.get("bered", False)
4598 l, llen, v = len_decode(lv)
4599 except LenIndefForm as err:
4601 raise err.__class__(
4603 klass=self.__class__,
4604 decode_path=decode_path,
4607 l, llen, v = 0, 1, lv[1:]
4609 except DecodeError as err:
4610 raise err.__class__(
4612 klass=self.__class__,
4613 decode_path=decode_path,
4617 raise NotEnoughData(
4618 "encoded length is longer than data",
4619 klass=self.__class__,
4620 decode_path=decode_path,
4624 v, tail = v[:l], v[l:]
4626 sub_offset = offset + tlen + llen
4629 ctx_allow_default_values = ctx.get("allow_default_values", False)
4630 for name, spec in self.specs.items():
4631 if spec.optional and (
4632 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4636 sub_decode_path = decode_path + (name,)
4638 value, v_tail = spec.decode(
4642 decode_path=sub_decode_path,
4650 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4651 if defined is not None:
4652 defined_by, defined_spec = defined
4653 if issubclass(value.__class__, SequenceOf):
4654 for i, _value in enumerate(value):
4655 sub_sub_decode_path = sub_decode_path + (
4657 DecodePathDefBy(defined_by),
4659 defined_value, defined_tail = defined_spec.decode(
4660 memoryview(bytes(_value)),
4662 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4663 if value.expled else (value.tlen + value.llen)
4666 decode_path=sub_sub_decode_path,
4669 if len(defined_tail) > 0:
4672 klass=self.__class__,
4673 decode_path=sub_sub_decode_path,
4676 _value.defined = (defined_by, defined_value)
4678 defined_value, defined_tail = defined_spec.decode(
4679 memoryview(bytes(value)),
4681 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4682 if value.expled else (value.tlen + value.llen)
4685 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4688 if len(defined_tail) > 0:
4691 klass=self.__class__,
4692 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4695 value.defined = (defined_by, defined_value)
4697 value_len = value.fulllen
4699 sub_offset += value_len
4701 if spec.default is not None and value == spec.default:
4702 if ctx_bered or ctx_allow_default_values:
4706 "DEFAULT value met",
4707 klass=self.__class__,
4708 decode_path=sub_decode_path,
4711 values[name] = value
4713 spec_defines = getattr(spec, "defines", ())
4714 if len(spec_defines) == 0:
4715 defines_by_path = ctx.get("defines_by_path", ())
4716 if len(defines_by_path) > 0:
4717 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4718 if spec_defines is not None and len(spec_defines) > 0:
4719 for rel_path, schema in spec_defines:
4720 defined = schema.get(value, None)
4721 if defined is not None:
4722 ctx.setdefault("_defines", []).append((
4723 abs_decode_path(sub_decode_path[:-1], rel_path),
4727 if v[:EOC_LEN].tobytes() != EOC:
4730 klass=self.__class__,
4731 decode_path=decode_path,
4739 klass=self.__class__,
4740 decode_path=decode_path,
4743 obj = self.__class__(
4747 default=self.default,
4748 optional=self.optional,
4749 _decoded=(offset, llen, vlen),
4752 obj.lenindef = lenindef
4753 obj.ber_encoded = ber_encoded
4757 value = pp_console_row(next(self.pps()))
4759 for name in self.specs:
4760 _value = self._value.get(name)
4763 cols.append("%s: %s" % (name, repr(_value)))
4764 return "%s[%s]" % (value, "; ".join(cols))
4766 def pps(self, decode_path=()):
4768 asn1_type_name=self.asn1_type_name,
4769 obj_name=self.__class__.__name__,
4770 decode_path=decode_path,
4771 optional=self.optional,
4772 default=self == self.default,
4773 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4774 expl=None if self._expl is None else tag_decode(self._expl),
4779 expl_offset=self.expl_offset if self.expled else None,
4780 expl_tlen=self.expl_tlen if self.expled else None,
4781 expl_llen=self.expl_llen if self.expled else None,
4782 expl_vlen=self.expl_vlen if self.expled else None,
4783 expl_lenindef=self.expl_lenindef,
4784 lenindef=self.lenindef,
4785 ber_encoded=self.ber_encoded,
4788 for name in self.specs:
4789 value = self._value.get(name)
4792 yield value.pps(decode_path=decode_path + (name,))
4793 for pp in self.pps_lenindef(decode_path):
4797 class Set(Sequence):
4798 """``SET`` structure type
4800 Its usage is identical to :py:class:`pyderasn.Sequence`.
4802 .. _allow_unordered_set_ctx:
4804 DER prohibits unordered values encoding and will raise an error
4805 during decode. If If :ref:`bered <bered_ctx>` context option is set,
4806 then no error will occure. Also you can disable strict values
4807 ordering check by setting ``"allow_unordered_set": True``
4808 :ref:`context <ctx>` option.
4811 tag_default = tag_encode(form=TagFormConstructed, num=17)
4812 asn1_type_name = "SET"
4815 raws = self._encoded_values()
4818 return b"".join((self.tag, len_encode(len(v)), v))
4820 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4822 t, tlen, lv = tag_strip(tlv)
4823 except DecodeError as err:
4824 raise err.__class__(
4826 klass=self.__class__,
4827 decode_path=decode_path,
4832 klass=self.__class__,
4833 decode_path=decode_path,
4839 ctx_bered = ctx.get("bered", False)
4841 l, llen, v = len_decode(lv)
4842 except LenIndefForm as err:
4844 raise err.__class__(
4846 klass=self.__class__,
4847 decode_path=decode_path,
4850 l, llen, v = 0, 1, lv[1:]
4852 except DecodeError as err:
4853 raise err.__class__(
4855 klass=self.__class__,
4856 decode_path=decode_path,
4860 raise NotEnoughData(
4861 "encoded length is longer than data",
4862 klass=self.__class__,
4866 v, tail = v[:l], v[l:]
4868 sub_offset = offset + tlen + llen
4871 ctx_allow_default_values = ctx.get("allow_default_values", False)
4872 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
4873 value_prev = memoryview(v[:0])
4874 specs_items = self.specs.items
4876 if lenindef and v[:EOC_LEN].tobytes() == EOC:
4878 for name, spec in specs_items():
4879 sub_decode_path = decode_path + (name,)
4885 decode_path=sub_decode_path,
4894 klass=self.__class__,
4895 decode_path=decode_path,
4898 value, v_tail = spec.decode(
4902 decode_path=sub_decode_path,
4905 value_len = value.fulllen
4906 if value_prev.tobytes() > v[:value_len].tobytes():
4907 if ctx_bered or ctx_allow_unordered_set:
4911 "unordered " + self.asn1_type_name,
4912 klass=self.__class__,
4913 decode_path=sub_decode_path,
4916 if spec.default is None or value != spec.default:
4918 elif ctx_bered or ctx_allow_default_values:
4922 "DEFAULT value met",
4923 klass=self.__class__,
4924 decode_path=sub_decode_path,
4927 values[name] = value
4928 value_prev = v[:value_len]
4929 sub_offset += value_len
4932 obj = self.__class__(
4936 default=self.default,
4937 optional=self.optional,
4938 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
4941 if v[:EOC_LEN].tobytes() != EOC:
4944 klass=self.__class__,
4945 decode_path=decode_path,
4953 "not all values are ready",
4954 klass=self.__class__,
4955 decode_path=decode_path,
4958 obj.ber_encoded = ber_encoded
4962 class SequenceOf(Obj):
4963 """``SEQUENCE OF`` sequence type
4965 For that kind of type you must specify the object it will carry on
4966 (bounds are for example here, not required)::
4968 class Ints(SequenceOf):
4973 >>> ints.append(Integer(123))
4974 >>> ints.append(Integer(234))
4976 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
4977 >>> [int(i) for i in ints]
4979 >>> ints.append(Integer(345))
4980 Traceback (most recent call last):
4981 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
4984 >>> ints[1] = Integer(345)
4986 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
4988 Also you can initialize sequence with preinitialized values:
4990 >>> ints = Ints([Integer(123), Integer(234)])
4992 __slots__ = ("spec", "_bound_min", "_bound_max")
4993 tag_default = tag_encode(form=TagFormConstructed, num=16)
4994 asn1_type_name = "SEQUENCE OF"
5007 super(SequenceOf, self).__init__(
5015 schema = getattr(self, "schema", None)
5017 raise ValueError("schema must be specified")
5019 self._bound_min, self._bound_max = getattr(
5023 ) if bounds is None else bounds
5025 if value is not None:
5026 self._value = self._value_sanitize(value)
5027 if default is not None:
5028 default_value = self._value_sanitize(default)
5029 default_obj = self.__class__(
5034 default_obj._value = default_value
5035 self.default = default_obj
5037 self._value = default_obj.copy()._value
5039 def _value_sanitize(self, value):
5040 if issubclass(value.__class__, SequenceOf):
5041 value = value._value
5042 elif hasattr(value, "__iter__"):
5045 raise InvalidValueType((self.__class__, iter))
5046 if not self._bound_min <= len(value) <= self._bound_max:
5047 raise BoundsError(self._bound_min, len(value), self._bound_max)
5049 if not isinstance(v, self.spec.__class__):
5050 raise InvalidValueType((self.spec.__class__,))
5055 return all(v.ready for v in self._value)
5059 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5061 return any(v.bered for v in self._value)
5064 obj = self.__class__(schema=self.spec)
5065 obj._bound_min = self._bound_min
5066 obj._bound_max = self._bound_max
5068 obj._expl = self._expl
5069 obj.default = self.default
5070 obj.optional = self.optional
5071 obj.offset = self.offset
5072 obj.llen = self.llen
5073 obj.vlen = self.vlen
5074 obj._value = [v.copy() for v in self._value]
5077 def __eq__(self, their):
5078 if isinstance(their, self.__class__):
5080 self.spec == their.spec and
5081 self.tag == their.tag and
5082 self._expl == their._expl and
5083 self._value == their._value
5085 if hasattr(their, "__iter__"):
5086 return self._value == list(their)
5098 return self.__class__(
5102 (self._bound_min, self._bound_max)
5103 if bounds is None else bounds
5105 impl=self.tag if impl is None else impl,
5106 expl=self._expl if expl is None else expl,
5107 default=self.default if default is None else default,
5108 optional=self.optional if optional is None else optional,
5111 def __contains__(self, key):
5112 return key in self._value
5114 def append(self, value):
5115 if not isinstance(value, self.spec.__class__):
5116 raise InvalidValueType((self.spec.__class__,))
5117 if len(self._value) + 1 > self._bound_max:
5120 len(self._value) + 1,
5123 self._value.append(value)
5126 self._assert_ready()
5127 return iter(self._value)
5130 self._assert_ready()
5131 return len(self._value)
5133 def __setitem__(self, key, value):
5134 if not isinstance(value, self.spec.__class__):
5135 raise InvalidValueType((self.spec.__class__,))
5136 self._value[key] = self.spec(value=value)
5138 def __getitem__(self, key):
5139 return self._value[key]
5141 def _encoded_values(self):
5142 return [v.encode() for v in self._value]
5145 v = b"".join(self._encoded_values())
5146 return b"".join((self.tag, len_encode(len(v)), v))
5148 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5150 t, tlen, lv = tag_strip(tlv)
5151 except DecodeError as err:
5152 raise err.__class__(
5154 klass=self.__class__,
5155 decode_path=decode_path,
5160 klass=self.__class__,
5161 decode_path=decode_path,
5167 ctx_bered = ctx.get("bered", False)
5169 l, llen, v = len_decode(lv)
5170 except LenIndefForm as err:
5172 raise err.__class__(
5174 klass=self.__class__,
5175 decode_path=decode_path,
5178 l, llen, v = 0, 1, lv[1:]
5180 except DecodeError as err:
5181 raise err.__class__(
5183 klass=self.__class__,
5184 decode_path=decode_path,
5188 raise NotEnoughData(
5189 "encoded length is longer than data",
5190 klass=self.__class__,
5191 decode_path=decode_path,
5195 v, tail = v[:l], v[l:]
5197 sub_offset = offset + tlen + llen
5199 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5200 value_prev = memoryview(v[:0])
5204 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5206 sub_decode_path = decode_path + (str(len(_value)),)
5207 value, v_tail = spec.decode(
5211 decode_path=sub_decode_path,
5214 value_len = value.fulllen
5216 if value_prev.tobytes() > v[:value_len].tobytes():
5217 if ctx_bered or ctx_allow_unordered_set:
5221 "unordered " + self.asn1_type_name,
5222 klass=self.__class__,
5223 decode_path=sub_decode_path,
5226 value_prev = v[:value_len]
5227 _value.append(value)
5228 sub_offset += value_len
5232 obj = self.__class__(
5235 bounds=(self._bound_min, self._bound_max),
5238 default=self.default,
5239 optional=self.optional,
5240 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5242 except BoundsError as err:
5245 klass=self.__class__,
5246 decode_path=decode_path,
5250 if v[:EOC_LEN].tobytes() != EOC:
5253 klass=self.__class__,
5254 decode_path=decode_path,
5259 obj.ber_encoded = ber_encoded
5264 pp_console_row(next(self.pps())),
5265 ", ".join(repr(v) for v in self._value),
5268 def pps(self, decode_path=()):
5270 asn1_type_name=self.asn1_type_name,
5271 obj_name=self.__class__.__name__,
5272 decode_path=decode_path,
5273 optional=self.optional,
5274 default=self == self.default,
5275 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5276 expl=None if self._expl is None else tag_decode(self._expl),
5281 expl_offset=self.expl_offset if self.expled else None,
5282 expl_tlen=self.expl_tlen if self.expled else None,
5283 expl_llen=self.expl_llen if self.expled else None,
5284 expl_vlen=self.expl_vlen if self.expled else None,
5285 expl_lenindef=self.expl_lenindef,
5286 lenindef=self.lenindef,
5287 ber_encoded=self.ber_encoded,
5290 for i, value in enumerate(self._value):
5291 yield value.pps(decode_path=decode_path + (str(i),))
5292 for pp in self.pps_lenindef(decode_path):
5296 class SetOf(SequenceOf):
5297 """``SET OF`` sequence type
5299 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5302 tag_default = tag_encode(form=TagFormConstructed, num=17)
5303 asn1_type_name = "SET OF"
5306 raws = self._encoded_values()
5309 return b"".join((self.tag, len_encode(len(v)), v))
5311 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5312 return super(SetOf, self)._decode(
5318 ordering_check=True,
5322 def obj_by_path(pypath): # pragma: no cover
5323 """Import object specified as string Python path
5325 Modules must be separated from classes/functions with ``:``.
5327 >>> obj_by_path("foo.bar:Baz")
5328 <class 'foo.bar.Baz'>
5329 >>> obj_by_path("foo.bar:Baz.boo")
5330 <classmethod 'foo.bar.Baz.boo'>
5332 mod, objs = pypath.rsplit(":", 1)
5333 from importlib import import_module
5334 obj = import_module(mod)
5335 for obj_name in objs.split("."):
5336 obj = getattr(obj, obj_name)
5340 def generic_decoder(): # pragma: no cover
5341 # All of this below is a big hack with self references
5342 choice = PrimitiveTypes()
5343 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5344 choice.specs["SetOf"] = SetOf(schema=choice)
5346 choice.specs["SequenceOf%d" % i] = SequenceOf(
5350 choice.specs["Any"] = Any()
5352 # Class name equals to type name, to omit it from output
5353 class SEQUENCEOF(SequenceOf):
5361 with_decode_path=False,
5362 decode_path_only=(),
5364 def _pprint_pps(pps):
5366 if hasattr(pp, "_fields"):
5368 decode_path_only != () and
5369 pp.decode_path[:len(decode_path_only)] != decode_path_only
5372 if pp.asn1_type_name == Choice.asn1_type_name:
5374 pp_kwargs = pp._asdict()
5375 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5376 pp = _pp(**pp_kwargs)
5377 yield pp_console_row(
5382 with_colours=with_colours,
5383 with_decode_path=with_decode_path,
5384 decode_path_len_decrease=len(decode_path_only),
5386 for row in pp_console_blob(
5388 decode_path_len_decrease=len(decode_path_only),
5392 for row in _pprint_pps(pp):
5394 return "\n".join(_pprint_pps(obj.pps()))
5395 return SEQUENCEOF(), pprint_any
5398 def main(): # pragma: no cover
5400 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5401 parser.add_argument(
5405 help="Skip that number of bytes from the beginning",
5407 parser.add_argument(
5409 help="Python path to dictionary with OIDs",
5411 parser.add_argument(
5413 help="Python path to schema definition to use",
5415 parser.add_argument(
5416 "--defines-by-path",
5417 help="Python path to decoder's defines_by_path",
5419 parser.add_argument(
5421 action="store_true",
5422 help="Disallow BER encoding",
5424 parser.add_argument(
5425 "--print-decode-path",
5426 action="store_true",
5427 help="Print decode paths",
5429 parser.add_argument(
5430 "--decode-path-only",
5431 help="Print only specified decode path",
5433 parser.add_argument(
5435 action="store_true",
5436 help="Allow explicit tag out-of-bound",
5438 parser.add_argument(
5440 type=argparse.FileType("rb"),
5441 help="Path to DER file you want to decode",
5443 args = parser.parse_args()
5444 args.DERFile.seek(args.skip)
5445 der = memoryview(args.DERFile.read())
5446 args.DERFile.close()
5447 oids = obj_by_path(args.oids) if args.oids else {}
5449 schema = obj_by_path(args.schema)
5450 from functools import partial
5451 pprinter = partial(pprint, big_blobs=True)
5453 schema, pprinter = generic_decoder()
5455 "bered": not args.nobered,
5456 "allow_expl_oob": args.allow_expl_oob,
5458 if args.defines_by_path is not None:
5459 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5460 obj, tail = schema().decode(der, ctx=ctx)
5464 with_colours=True if environ.get("NO_COLOR") is None else False,
5465 with_decode_path=args.print_decode_path,
5467 () if args.decode_path_only is None else
5468 tuple(args.decode_path_only.split(":"))
5472 print("\nTrailing data: %s" % hexenc(tail))
5475 if __name__ == "__main__":