3 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
4 # Copyright (C) 2017-2019 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``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``
389 * If object has an indefinite length encoding, then its ``lenindef``
390 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
391 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
393 * If object has an indefinite length encoded explicit tag, then
394 ``expl_lenindef`` is set to True.
395 * If object has either any of BER-related encoding (explicit tag
396 indefinite length, object's indefinite length, BER-encoding) or any
397 underlying component has that kind of encoding, then ``bered``
398 attribute is set to True. For example SignedData CMS can have
399 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
400 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
402 EOC (end-of-contents) token's length is taken in advance in object's
405 .. _allow_expl_oob_ctx:
407 Allow explicit tag out-of-bound
408 -------------------------------
410 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
411 one value, more than one object. If you set ``allow_expl_oob`` context
412 option to True, then no error will be raised and that invalid encoding
413 will be silently further processed. But pay attention that offsets and
414 lengths will be invalid in that case.
418 This option should be used only for skipping some decode errors, just
419 to see the decoded structure somehow.
426 .. autoclass:: pyderasn.Boolean
431 .. autoclass:: pyderasn.Integer
436 .. autoclass:: pyderasn.BitString
441 .. autoclass:: pyderasn.OctetString
446 .. autoclass:: pyderasn.Null
451 .. autoclass:: pyderasn.ObjectIdentifier
456 .. autoclass:: pyderasn.Enumerated
460 .. autoclass:: pyderasn.CommonString
464 .. autoclass:: pyderasn.NumericString
468 .. autoclass:: pyderasn.PrintableString
472 .. autoclass:: pyderasn.UTCTime
473 :members: __init__, todatetime
477 .. autoclass:: pyderasn.GeneralizedTime
484 .. autoclass:: pyderasn.Choice
489 .. autoclass:: PrimitiveTypes
493 .. autoclass:: pyderasn.Any
501 .. autoclass:: pyderasn.Sequence
506 .. autoclass:: pyderasn.Set
511 .. autoclass:: pyderasn.SequenceOf
516 .. autoclass:: pyderasn.SetOf
522 .. autofunction:: pyderasn.abs_decode_path
523 .. autofunction:: pyderasn.colonize_hex
524 .. autofunction:: pyderasn.hexenc
525 .. autofunction:: pyderasn.hexdec
526 .. autofunction:: pyderasn.tag_encode
527 .. autofunction:: pyderasn.tag_decode
528 .. autofunction:: pyderasn.tag_ctxp
529 .. autofunction:: pyderasn.tag_ctxc
530 .. autoclass:: pyderasn.Obj
531 .. autoclass:: pyderasn.DecodeError
533 .. autoclass:: pyderasn.NotEnoughData
534 .. autoclass:: pyderasn.LenIndefForm
535 .. autoclass:: pyderasn.TagMismatch
536 .. autoclass:: pyderasn.InvalidLength
537 .. autoclass:: pyderasn.InvalidOID
538 .. autoclass:: pyderasn.ObjUnknown
539 .. autoclass:: pyderasn.ObjNotReady
540 .. autoclass:: pyderasn.InvalidValueType
541 .. autoclass:: pyderasn.BoundsError
544 from codecs import getdecoder
545 from codecs import getencoder
546 from collections import namedtuple
547 from collections import OrderedDict
548 from copy import copy
549 from datetime import datetime
550 from math import ceil
551 from os import environ
552 from string import ascii_letters
553 from string import digits
555 from six import add_metaclass
556 from six import binary_type
557 from six import byte2int
558 from six import indexbytes
559 from six import int2byte
560 from six import integer_types
561 from six import iterbytes
562 from six import iteritems
563 from six import itervalues
565 from six import string_types
566 from six import text_type
567 from six import unichr as six_unichr
568 from six.moves import xrange as six_xrange
572 from termcolor import colored
573 except ImportError: # pragma: no cover
574 def colored(what, *args):
618 "TagClassApplication",
622 "TagFormConstructed",
633 TagClassUniversal = 0
634 TagClassApplication = 1 << 6
635 TagClassContext = 1 << 7
636 TagClassPrivate = 1 << 6 | 1 << 7
638 TagFormConstructed = 1 << 5
641 TagClassApplication: "APPLICATION ",
642 TagClassPrivate: "PRIVATE ",
643 TagClassUniversal: "UNIV ",
647 LENINDEF = b"\x80" # length indefinite mark
648 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
651 ########################################################################
653 ########################################################################
655 class ASN1Error(ValueError):
659 class DecodeError(ASN1Error):
660 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
662 :param str msg: reason of decode failing
663 :param klass: optional exact DecodeError inherited class (like
664 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
665 :py:exc:`InvalidLength`)
666 :param decode_path: tuple of strings. It contains human
667 readable names of the fields through which
668 decoding process has passed
669 :param int offset: binary offset where failure happened
671 super(DecodeError, self).__init__()
674 self.decode_path = decode_path
680 "" if self.klass is None else self.klass.__name__,
682 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
683 if len(self.decode_path) > 0 else ""
685 ("(at %d)" % self.offset) if self.offset > 0 else "",
691 return "%s(%s)" % (self.__class__.__name__, self)
694 class NotEnoughData(DecodeError):
698 class LenIndefForm(DecodeError):
702 class TagMismatch(DecodeError):
706 class InvalidLength(DecodeError):
710 class InvalidOID(DecodeError):
714 class ObjUnknown(ASN1Error):
715 def __init__(self, name):
716 super(ObjUnknown, self).__init__()
720 return "object is unknown: %s" % self.name
723 return "%s(%s)" % (self.__class__.__name__, self)
726 class ObjNotReady(ASN1Error):
727 def __init__(self, name):
728 super(ObjNotReady, self).__init__()
732 return "object is not ready: %s" % self.name
735 return "%s(%s)" % (self.__class__.__name__, self)
738 class InvalidValueType(ASN1Error):
739 def __init__(self, expected_types):
740 super(InvalidValueType, self).__init__()
741 self.expected_types = expected_types
744 return "invalid value type, expected: %s" % ", ".join(
745 [repr(t) for t in self.expected_types]
749 return "%s(%s)" % (self.__class__.__name__, self)
752 class BoundsError(ASN1Error):
753 def __init__(self, bound_min, value, bound_max):
754 super(BoundsError, self).__init__()
755 self.bound_min = bound_min
757 self.bound_max = bound_max
760 return "unsatisfied bounds: %s <= %s <= %s" % (
767 return "%s(%s)" % (self.__class__.__name__, self)
770 ########################################################################
772 ########################################################################
774 _hexdecoder = getdecoder("hex")
775 _hexencoder = getencoder("hex")
779 """Binary data to hexadecimal string convert
781 return _hexdecoder(data)[0]
785 """Hexadecimal string to binary data convert
787 return _hexencoder(data)[0].decode("ascii")
790 def int_bytes_len(num, byte_len=8):
793 return int(ceil(float(num.bit_length()) / byte_len))
796 def zero_ended_encode(num):
797 octets = bytearray(int_bytes_len(num, 7))
799 octets[i] = num & 0x7F
803 octets[i] = 0x80 | (num & 0x7F)
809 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
810 """Encode tag to binary form
812 :param int num: tag's number
813 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
814 :py:data:`pyderasn.TagClassContext`,
815 :py:data:`pyderasn.TagClassApplication`,
816 :py:data:`pyderasn.TagClassPrivate`)
817 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
818 :py:data:`pyderasn.TagFormConstructed`)
822 return int2byte(klass | form | num)
823 # [XX|X|11111][1.......][1.......] ... [0.......]
824 return int2byte(klass | form | 31) + zero_ended_encode(num)
828 """Decode tag from binary form
832 No validation is performed, assuming that it has already passed.
834 It returns tuple with three integers, as
835 :py:func:`pyderasn.tag_encode` accepts.
837 first_octet = byte2int(tag)
838 klass = first_octet & 0xC0
839 form = first_octet & 0x20
840 if first_octet & 0x1F < 0x1F:
841 return (klass, form, first_octet & 0x1F)
843 for octet in iterbytes(tag[1:]):
846 return (klass, form, num)
850 """Create CONTEXT PRIMITIVE tag
852 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
856 """Create CONTEXT CONSTRUCTED tag
858 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
862 """Take off tag from the data
864 :returns: (encoded tag, tag length, remaining data)
867 raise NotEnoughData("no data at all")
868 if byte2int(data) & 0x1F < 31:
869 return data[:1], 1, data[1:]
874 raise DecodeError("unfinished tag")
875 if indexbytes(data, i) & 0x80 == 0:
878 return data[:i], i, data[i:]
884 octets = bytearray(int_bytes_len(l) + 1)
885 octets[0] = 0x80 | (len(octets) - 1)
886 for i in six_xrange(len(octets) - 1, 0, -1):
892 def len_decode(data):
895 :returns: (decoded length, length's length, remaining data)
896 :raises LenIndefForm: if indefinite form encoding is met
899 raise NotEnoughData("no data at all")
900 first_octet = byte2int(data)
901 if first_octet & 0x80 == 0:
902 return first_octet, 1, data[1:]
903 octets_num = first_octet & 0x7F
904 if octets_num + 1 > len(data):
905 raise NotEnoughData("encoded length is longer than data")
908 if byte2int(data[1:]) == 0:
909 raise DecodeError("leading zeros")
911 for v in iterbytes(data[1:1 + octets_num]):
914 raise DecodeError("long form instead of short one")
915 return l, 1 + octets_num, data[1 + octets_num:]
918 ########################################################################
920 ########################################################################
922 class AutoAddSlots(type):
923 def __new__(mcs, name, bases, _dict):
924 _dict["__slots__"] = _dict.get("__slots__", ())
925 return type.__new__(mcs, name, bases, _dict)
928 @add_metaclass(AutoAddSlots)
930 """Common ASN.1 object class
932 All ASN.1 types are inherited from it. It has metaclass that
933 automatically adds ``__slots__`` to all inherited classes.
957 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
958 self._expl = getattr(self, "expl", None) if expl is None else expl
959 if self.tag != self.tag_default and self._expl is not None:
960 raise ValueError("implicit and explicit tags can not be set simultaneously")
961 if default is not None:
963 self.optional = optional
964 self.offset, self.llen, self.vlen = _decoded
966 self.expl_lenindef = False
967 self.lenindef = False
968 self.ber_encoded = False
971 def ready(self): # pragma: no cover
972 """Is object ready to be encoded?
974 raise NotImplementedError()
976 def _assert_ready(self):
978 raise ObjNotReady(self.__class__.__name__)
982 """Is either object or any elements inside is BER encoded?
984 return self.expl_lenindef or self.lenindef or self.ber_encoded
988 """Is object decoded?
990 return (self.llen + self.vlen) > 0
992 def copy(self): # pragma: no cover
993 """Make a copy of object, safe to be mutated
995 raise NotImplementedError()
1003 return self.tlen + self.llen + self.vlen
1005 def __str__(self): # pragma: no cover
1006 return self.__bytes__() if PY2 else self.__unicode__()
1008 def __ne__(self, their):
1009 return not(self == their)
1011 def __gt__(self, their): # pragma: no cover
1012 return not(self < their)
1014 def __le__(self, their): # pragma: no cover
1015 return (self == their) or (self < their)
1017 def __ge__(self, their): # pragma: no cover
1018 return (self == their) or (self > their)
1020 def _encode(self): # pragma: no cover
1021 raise NotImplementedError()
1023 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1024 raise NotImplementedError()
1027 raw = self._encode()
1028 if self._expl is None:
1030 return b"".join((self._expl, len_encode(len(raw)), raw))
1040 _ctx_immutable=True,
1044 :param data: either binary or memoryview
1045 :param int offset: initial data's offset
1046 :param bool leavemm: do we need to leave memoryview of remaining
1047 data as is, or convert it to bytes otherwise
1048 :param ctx: optional :ref:`context <ctx>` governing decoding process
1049 :param tag_only: decode only the tag, without length and contents
1050 (used only in Choice and Set structures, trying to
1051 determine if tag satisfies the scheme)
1052 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1053 :returns: (Obj, remaining data)
1057 elif _ctx_immutable:
1059 tlv = memoryview(data)
1060 if self._expl is None:
1061 result = self._decode(
1064 decode_path=decode_path,
1073 t, tlen, lv = tag_strip(tlv)
1074 except DecodeError as err:
1075 raise err.__class__(
1077 klass=self.__class__,
1078 decode_path=decode_path,
1083 klass=self.__class__,
1084 decode_path=decode_path,
1088 l, llen, v = len_decode(lv)
1089 except LenIndefForm as err:
1090 if not ctx.get("bered", False):
1091 raise err.__class__(
1093 klass=self.__class__,
1094 decode_path=decode_path,
1098 offset += tlen + llen
1099 result = self._decode(
1102 decode_path=decode_path,
1106 if tag_only: # pragma: no cover
1109 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1110 if eoc_expected.tobytes() != EOC:
1113 klass=self.__class__,
1114 decode_path=decode_path,
1118 obj.expl_lenindef = True
1119 except DecodeError as err:
1120 raise err.__class__(
1122 klass=self.__class__,
1123 decode_path=decode_path,
1128 raise NotEnoughData(
1129 "encoded length is longer than data",
1130 klass=self.__class__,
1131 decode_path=decode_path,
1134 result = self._decode(
1136 offset=offset + tlen + llen,
1137 decode_path=decode_path,
1141 if tag_only: # pragma: no cover
1144 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1146 "explicit tag out-of-bound, longer than data",
1147 klass=self.__class__,
1148 decode_path=decode_path,
1151 return obj, (tail if leavemm else tail.tobytes())
1155 return self._expl is not None
1162 def expl_tlen(self):
1163 return len(self._expl)
1166 def expl_llen(self):
1167 if self.expl_lenindef:
1169 return len(len_encode(self.tlvlen))
1172 def expl_offset(self):
1173 return self.offset - self.expl_tlen - self.expl_llen
1176 def expl_vlen(self):
1180 def expl_tlvlen(self):
1181 return self.expl_tlen + self.expl_llen + self.expl_vlen
1184 def fulloffset(self):
1185 return self.expl_offset if self.expled else self.offset
1189 return self.expl_tlvlen if self.expled else self.tlvlen
1191 def pps_lenindef(self, decode_path):
1192 if self.lenindef and not (
1193 getattr(self, "defined", None) is not None and
1194 self.defined[1].lenindef
1197 asn1_type_name="EOC",
1199 decode_path=decode_path,
1201 self.offset + self.tlvlen -
1202 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1210 if self.expl_lenindef:
1212 asn1_type_name="EOC",
1213 obj_name="EXPLICIT",
1214 decode_path=decode_path,
1215 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1224 class DecodePathDefBy(object):
1225 """DEFINED BY representation inside decode path
1227 __slots__ = ("defined_by",)
1229 def __init__(self, defined_by):
1230 self.defined_by = defined_by
1232 def __ne__(self, their):
1233 return not(self == their)
1235 def __eq__(self, their):
1236 if not isinstance(their, self.__class__):
1238 return self.defined_by == their.defined_by
1241 return "DEFINED BY " + str(self.defined_by)
1244 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1247 ########################################################################
1249 ########################################################################
1251 PP = namedtuple("PP", (
1279 asn1_type_name="unknown",
1296 expl_lenindef=False,
1327 def _colourize(what, colour, with_colours, attrs=("bold",)):
1328 return colored(what, colour, attrs=attrs) if with_colours else what
1331 def colonize_hex(hexed):
1332 """Separate hexadecimal string with colons
1334 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1343 with_decode_path=False,
1344 decode_path_len_decrease=0,
1351 " " if pp.expl_offset is None else
1352 ("-%d" % (pp.offset - pp.expl_offset))
1354 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1356 col = _colourize(col, "red", with_colours, ())
1357 col += _colourize("B", "red", with_colours) if pp.bered else " "
1359 col = "[%d,%d,%4d]%s" % (
1363 LENINDEF_PP_CHAR if pp.lenindef else " "
1365 col = _colourize(col, "green", with_colours, ())
1367 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1368 if decode_path_len > 0:
1369 cols.append(" ." * decode_path_len)
1370 ent = pp.decode_path[-1]
1371 if isinstance(ent, DecodePathDefBy):
1372 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1373 value = str(ent.defined_by)
1375 oids is not None and
1376 ent.defined_by.asn1_type_name ==
1377 ObjectIdentifier.asn1_type_name and
1380 cols.append(_colourize("%s:" % oids[value], "green", with_colours))
1382 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1384 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1385 if pp.expl is not None:
1386 klass, _, num = pp.expl
1387 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1388 cols.append(_colourize(col, "blue", with_colours))
1389 if pp.impl is not None:
1390 klass, _, num = pp.impl
1391 col = "[%s%d]" % (TagClassReprs[klass], num)
1392 cols.append(_colourize(col, "blue", with_colours))
1393 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1394 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1396 cols.append(_colourize("BER", "red", with_colours))
1397 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1398 if pp.value is not None:
1400 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1402 oids is not None and
1403 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
1406 cols.append(_colourize("(%s)" % oids[value], "green", with_colours))
1407 if pp.asn1_type_name == Integer.asn1_type_name:
1408 hex_repr = hex(int(pp.obj._value))[2:].upper()
1409 if len(hex_repr) % 2 != 0:
1410 hex_repr = "0" + hex_repr
1411 cols.append(_colourize(
1412 "(%s)" % colonize_hex(hex_repr),
1417 if isinstance(pp.blob, binary_type):
1418 cols.append(hexenc(pp.blob))
1419 elif isinstance(pp.blob, tuple):
1420 cols.append(", ".join(pp.blob))
1422 cols.append(_colourize("OPTIONAL", "red", with_colours))
1424 cols.append(_colourize("DEFAULT", "red", with_colours))
1425 if with_decode_path:
1426 cols.append(_colourize(
1427 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1431 return " ".join(cols)
1434 def pp_console_blob(pp, decode_path_len_decrease=0):
1435 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1436 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1437 if decode_path_len > 0:
1438 cols.append(" ." * (decode_path_len + 1))
1439 if isinstance(pp.blob, binary_type):
1440 blob = hexenc(pp.blob).upper()
1441 for i in six_xrange(0, len(blob), 32):
1442 chunk = blob[i:i + 32]
1443 yield " ".join(cols + [colonize_hex(chunk)])
1444 elif isinstance(pp.blob, tuple):
1445 yield " ".join(cols + [", ".join(pp.blob)])
1453 with_decode_path=False,
1454 decode_path_only=(),
1456 """Pretty print object
1458 :param Obj obj: object you want to pretty print
1459 :param oids: ``OID <-> humand readable string`` dictionary. When OID
1460 from it is met, then its humand readable form is printed
1461 :param big_blobs: if large binary objects are met (like OctetString
1462 values), do we need to print them too, on separate
1464 :param with_colours: colourize output, if ``termcolor`` library
1466 :param with_decode_path: print decode path
1467 :param decode_path_only: print only that specified decode path
1469 def _pprint_pps(pps):
1471 if hasattr(pp, "_fields"):
1473 decode_path_only != () and
1475 str(p) for p in pp.decode_path[:len(decode_path_only)]
1476 ) != decode_path_only
1480 yield pp_console_row(
1485 with_colours=with_colours,
1486 with_decode_path=with_decode_path,
1487 decode_path_len_decrease=len(decode_path_only),
1489 for row in pp_console_blob(
1491 decode_path_len_decrease=len(decode_path_only),
1495 yield pp_console_row(
1500 with_colours=with_colours,
1501 with_decode_path=with_decode_path,
1502 decode_path_len_decrease=len(decode_path_only),
1505 for row in _pprint_pps(pp):
1507 return "\n".join(_pprint_pps(obj.pps()))
1510 ########################################################################
1511 # ASN.1 primitive types
1512 ########################################################################
1515 """``BOOLEAN`` boolean type
1517 >>> b = Boolean(True)
1519 >>> b == Boolean(True)
1525 tag_default = tag_encode(1)
1526 asn1_type_name = "BOOLEAN"
1538 :param value: set the value. Either boolean type, or
1539 :py:class:`pyderasn.Boolean` object
1540 :param bytes impl: override default tag with ``IMPLICIT`` one
1541 :param bytes expl: override default tag with ``EXPLICIT`` one
1542 :param default: set default value. Type same as in ``value``
1543 :param bool optional: is object ``OPTIONAL`` in sequence
1545 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1546 self._value = None if value is None else self._value_sanitize(value)
1547 if default is not None:
1548 default = self._value_sanitize(default)
1549 self.default = self.__class__(
1555 self._value = default
1557 def _value_sanitize(self, value):
1558 if isinstance(value, bool):
1560 if issubclass(value.__class__, Boolean):
1562 raise InvalidValueType((self.__class__, bool))
1566 return self._value is not None
1569 obj = self.__class__()
1570 obj._value = self._value
1572 obj._expl = self._expl
1573 obj.default = self.default
1574 obj.optional = self.optional
1575 obj.offset = self.offset
1576 obj.llen = self.llen
1577 obj.vlen = self.vlen
1578 obj.expl_lenindef = self.expl_lenindef
1579 obj.lenindef = self.lenindef
1580 obj.ber_encoded = self.ber_encoded
1583 def __nonzero__(self):
1584 self._assert_ready()
1588 self._assert_ready()
1591 def __eq__(self, their):
1592 if isinstance(their, bool):
1593 return self._value == their
1594 if not issubclass(their.__class__, Boolean):
1597 self._value == their._value and
1598 self.tag == their.tag and
1599 self._expl == their._expl
1610 return self.__class__(
1612 impl=self.tag if impl is None else impl,
1613 expl=self._expl if expl is None else expl,
1614 default=self.default if default is None else default,
1615 optional=self.optional if optional is None else optional,
1619 self._assert_ready()
1623 (b"\xFF" if self._value else b"\x00"),
1626 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1628 t, _, lv = tag_strip(tlv)
1629 except DecodeError as err:
1630 raise err.__class__(
1632 klass=self.__class__,
1633 decode_path=decode_path,
1638 klass=self.__class__,
1639 decode_path=decode_path,
1645 l, _, v = len_decode(lv)
1646 except DecodeError as err:
1647 raise err.__class__(
1649 klass=self.__class__,
1650 decode_path=decode_path,
1654 raise InvalidLength(
1655 "Boolean's length must be equal to 1",
1656 klass=self.__class__,
1657 decode_path=decode_path,
1661 raise NotEnoughData(
1662 "encoded length is longer than data",
1663 klass=self.__class__,
1664 decode_path=decode_path,
1667 first_octet = byte2int(v)
1669 if first_octet == 0:
1671 elif first_octet == 0xFF:
1673 elif ctx.get("bered", False):
1678 "unacceptable Boolean value",
1679 klass=self.__class__,
1680 decode_path=decode_path,
1683 obj = self.__class__(
1687 default=self.default,
1688 optional=self.optional,
1689 _decoded=(offset, 1, 1),
1691 obj.ber_encoded = ber_encoded
1695 return pp_console_row(next(self.pps()))
1697 def pps(self, decode_path=()):
1700 asn1_type_name=self.asn1_type_name,
1701 obj_name=self.__class__.__name__,
1702 decode_path=decode_path,
1703 value=str(self._value) if self.ready else None,
1704 optional=self.optional,
1705 default=self == self.default,
1706 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1707 expl=None if self._expl is None else tag_decode(self._expl),
1712 expl_offset=self.expl_offset if self.expled else None,
1713 expl_tlen=self.expl_tlen if self.expled else None,
1714 expl_llen=self.expl_llen if self.expled else None,
1715 expl_vlen=self.expl_vlen if self.expled else None,
1716 expl_lenindef=self.expl_lenindef,
1717 ber_encoded=self.ber_encoded,
1720 for pp in self.pps_lenindef(decode_path):
1725 """``INTEGER`` integer type
1727 >>> b = Integer(-123)
1729 >>> b == Integer(-123)
1734 >>> Integer(2, bounds=(1, 3))
1736 >>> Integer(5, bounds=(1, 3))
1737 Traceback (most recent call last):
1738 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1742 class Version(Integer):
1749 >>> v = Version("v1")
1756 {'v3': 2, 'v1': 0, 'v2': 1}
1758 __slots__ = ("specs", "_bound_min", "_bound_max")
1759 tag_default = tag_encode(2)
1760 asn1_type_name = "INTEGER"
1774 :param value: set the value. Either integer type, named value
1775 (if ``schema`` is specified in the class), or
1776 :py:class:`pyderasn.Integer` object
1777 :param bounds: set ``(MIN, MAX)`` value constraint.
1778 (-inf, +inf) by default
1779 :param bytes impl: override default tag with ``IMPLICIT`` one
1780 :param bytes expl: override default tag with ``EXPLICIT`` one
1781 :param default: set default value. Type same as in ``value``
1782 :param bool optional: is object ``OPTIONAL`` in sequence
1784 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1786 specs = getattr(self, "schema", {}) if _specs is None else _specs
1787 self.specs = specs if isinstance(specs, dict) else dict(specs)
1788 self._bound_min, self._bound_max = getattr(
1791 (float("-inf"), float("+inf")),
1792 ) if bounds is None else bounds
1793 if value is not None:
1794 self._value = self._value_sanitize(value)
1795 if default is not None:
1796 default = self._value_sanitize(default)
1797 self.default = self.__class__(
1803 if self._value is None:
1804 self._value = default
1806 def _value_sanitize(self, value):
1807 if isinstance(value, integer_types):
1809 elif issubclass(value.__class__, Integer):
1810 value = value._value
1811 elif isinstance(value, str):
1812 value = self.specs.get(value)
1814 raise ObjUnknown("integer value: %s" % value)
1816 raise InvalidValueType((self.__class__, int, str))
1817 if not self._bound_min <= value <= self._bound_max:
1818 raise BoundsError(self._bound_min, value, self._bound_max)
1823 return self._value is not None
1826 obj = self.__class__(_specs=self.specs)
1827 obj._value = self._value
1828 obj._bound_min = self._bound_min
1829 obj._bound_max = self._bound_max
1831 obj._expl = self._expl
1832 obj.default = self.default
1833 obj.optional = self.optional
1834 obj.offset = self.offset
1835 obj.llen = self.llen
1836 obj.vlen = self.vlen
1837 obj.expl_lenindef = self.expl_lenindef
1838 obj.lenindef = self.lenindef
1839 obj.ber_encoded = self.ber_encoded
1843 self._assert_ready()
1844 return int(self._value)
1847 self._assert_ready()
1850 bytes(self._expl or b"") +
1851 str(self._value).encode("ascii"),
1854 def __eq__(self, their):
1855 if isinstance(their, integer_types):
1856 return self._value == their
1857 if not issubclass(their.__class__, Integer):
1860 self._value == their._value and
1861 self.tag == their.tag and
1862 self._expl == their._expl
1865 def __lt__(self, their):
1866 return self._value < their._value
1870 for name, value in iteritems(self.specs):
1871 if value == self._value:
1883 return self.__class__(
1886 (self._bound_min, self._bound_max)
1887 if bounds is None else bounds
1889 impl=self.tag if impl is None else impl,
1890 expl=self._expl if expl is None else expl,
1891 default=self.default if default is None else default,
1892 optional=self.optional if optional is None else optional,
1897 self._assert_ready()
1901 octets = bytearray([0])
1905 octets = bytearray()
1907 octets.append((value & 0xFF) ^ 0xFF)
1909 if len(octets) == 0 or octets[-1] & 0x80 == 0:
1912 octets = bytearray()
1914 octets.append(value & 0xFF)
1916 if octets[-1] & 0x80 > 0:
1919 octets = bytes(octets)
1921 bytes_len = ceil(value.bit_length() / 8) or 1
1924 octets = value.to_bytes(
1929 except OverflowError:
1933 return b"".join((self.tag, len_encode(len(octets)), octets))
1935 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1937 t, _, lv = tag_strip(tlv)
1938 except DecodeError as err:
1939 raise err.__class__(
1941 klass=self.__class__,
1942 decode_path=decode_path,
1947 klass=self.__class__,
1948 decode_path=decode_path,
1954 l, llen, v = len_decode(lv)
1955 except DecodeError as err:
1956 raise err.__class__(
1958 klass=self.__class__,
1959 decode_path=decode_path,
1963 raise NotEnoughData(
1964 "encoded length is longer than data",
1965 klass=self.__class__,
1966 decode_path=decode_path,
1970 raise NotEnoughData(
1972 klass=self.__class__,
1973 decode_path=decode_path,
1976 v, tail = v[:l], v[l:]
1977 first_octet = byte2int(v)
1979 second_octet = byte2int(v[1:])
1981 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
1982 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
1985 "non normalized integer",
1986 klass=self.__class__,
1987 decode_path=decode_path,
1992 if first_octet & 0x80 > 0:
1993 octets = bytearray()
1994 for octet in bytearray(v):
1995 octets.append(octet ^ 0xFF)
1996 for octet in octets:
1997 value = (value << 8) | octet
2001 for octet in bytearray(v):
2002 value = (value << 8) | octet
2004 value = int.from_bytes(v, byteorder="big", signed=True)
2006 obj = self.__class__(
2008 bounds=(self._bound_min, self._bound_max),
2011 default=self.default,
2012 optional=self.optional,
2014 _decoded=(offset, llen, l),
2016 except BoundsError as err:
2019 klass=self.__class__,
2020 decode_path=decode_path,
2026 return pp_console_row(next(self.pps()))
2028 def pps(self, decode_path=()):
2031 asn1_type_name=self.asn1_type_name,
2032 obj_name=self.__class__.__name__,
2033 decode_path=decode_path,
2034 value=(self.named or str(self._value)) if self.ready else None,
2035 optional=self.optional,
2036 default=self == self.default,
2037 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2038 expl=None if self._expl is None else tag_decode(self._expl),
2043 expl_offset=self.expl_offset if self.expled else None,
2044 expl_tlen=self.expl_tlen if self.expled else None,
2045 expl_llen=self.expl_llen if self.expled else None,
2046 expl_vlen=self.expl_vlen if self.expled else None,
2047 expl_lenindef=self.expl_lenindef,
2050 for pp in self.pps_lenindef(decode_path):
2054 SET01 = frozenset(("0", "1"))
2057 class BitString(Obj):
2058 """``BIT STRING`` bit string type
2060 >>> BitString(b"hello world")
2061 BIT STRING 88 bits 68656c6c6f20776f726c64
2064 >>> b == b"hello world"
2069 >>> BitString("'0A3B5F291CD'H")
2070 BIT STRING 44 bits 0a3b5f291cd0
2071 >>> b = BitString("'010110000000'B")
2072 BIT STRING 12 bits 5800
2075 >>> b[0], b[1], b[2], b[3]
2076 (False, True, False, True)
2080 [False, True, False, True, True, False, False, False, False, False, False, False]
2084 class KeyUsage(BitString):
2086 ("digitalSignature", 0),
2087 ("nonRepudiation", 1),
2088 ("keyEncipherment", 2),
2091 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2092 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2094 ['nonRepudiation', 'keyEncipherment']
2096 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2100 Pay attention that BIT STRING can be encoded both in primitive
2101 and constructed forms. Decoder always checks constructed form tag
2102 additionally to specified primitive one. If BER decoding is
2103 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2104 of DER restrictions.
2106 __slots__ = ("tag_constructed", "specs", "defined")
2107 tag_default = tag_encode(3)
2108 asn1_type_name = "BIT STRING"
2121 :param value: set the value. Either binary type, tuple of named
2122 values (if ``schema`` is specified in the class),
2123 string in ``'XXX...'B`` form, or
2124 :py:class:`pyderasn.BitString` object
2125 :param bytes impl: override default tag with ``IMPLICIT`` one
2126 :param bytes expl: override default tag with ``EXPLICIT`` one
2127 :param default: set default value. Type same as in ``value``
2128 :param bool optional: is object ``OPTIONAL`` in sequence
2130 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2131 specs = getattr(self, "schema", {}) if _specs is None else _specs
2132 self.specs = specs if isinstance(specs, dict) else dict(specs)
2133 self._value = None if value is None else self._value_sanitize(value)
2134 if default is not None:
2135 default = self._value_sanitize(default)
2136 self.default = self.__class__(
2142 self._value = default
2144 tag_klass, _, tag_num = tag_decode(self.tag)
2145 self.tag_constructed = tag_encode(
2147 form=TagFormConstructed,
2151 def _bits2octets(self, bits):
2152 if len(self.specs) > 0:
2153 bits = bits.rstrip("0")
2155 bits += "0" * ((8 - (bit_len % 8)) % 8)
2156 octets = bytearray(len(bits) // 8)
2157 for i in six_xrange(len(octets)):
2158 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2159 return bit_len, bytes(octets)
2161 def _value_sanitize(self, value):
2162 if isinstance(value, (string_types, binary_type)):
2164 isinstance(value, string_types) and
2165 value.startswith("'")
2167 if value.endswith("'B"):
2169 if not frozenset(value) <= SET01:
2170 raise ValueError("B's coding contains unacceptable chars")
2171 return self._bits2octets(value)
2172 elif value.endswith("'H"):
2176 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2178 if isinstance(value, binary_type):
2179 return (len(value) * 8, value)
2181 raise InvalidValueType((self.__class__, string_types, binary_type))
2182 if isinstance(value, tuple):
2185 isinstance(value[0], integer_types) and
2186 isinstance(value[1], binary_type)
2191 bit = self.specs.get(name)
2193 raise ObjUnknown("BitString value: %s" % name)
2196 return self._bits2octets("")
2197 bits = frozenset(bits)
2198 return self._bits2octets("".join(
2199 ("1" if bit in bits else "0")
2200 for bit in six_xrange(max(bits) + 1)
2202 if issubclass(value.__class__, BitString):
2204 raise InvalidValueType((self.__class__, binary_type, string_types))
2208 return self._value is not None
2211 obj = self.__class__(_specs=self.specs)
2213 if value is not None:
2214 value = (value[0], value[1])
2217 obj._expl = self._expl
2218 obj.default = self.default
2219 obj.optional = self.optional
2220 obj.offset = self.offset
2221 obj.llen = self.llen
2222 obj.vlen = self.vlen
2223 obj.expl_lenindef = self.expl_lenindef
2224 obj.lenindef = self.lenindef
2225 obj.ber_encoded = self.ber_encoded
2229 self._assert_ready()
2230 for i in six_xrange(self._value[0]):
2235 self._assert_ready()
2236 return self._value[0]
2238 def __bytes__(self):
2239 self._assert_ready()
2240 return self._value[1]
2242 def __eq__(self, their):
2243 if isinstance(their, bytes):
2244 return self._value[1] == their
2245 if not issubclass(their.__class__, BitString):
2248 self._value == their._value and
2249 self.tag == their.tag and
2250 self._expl == their._expl
2255 return [name for name, bit in iteritems(self.specs) if self[bit]]
2265 return self.__class__(
2267 impl=self.tag if impl is None else impl,
2268 expl=self._expl if expl is None else expl,
2269 default=self.default if default is None else default,
2270 optional=self.optional if optional is None else optional,
2274 def __getitem__(self, key):
2275 if isinstance(key, int):
2276 bit_len, octets = self._value
2280 byte2int(memoryview(octets)[key // 8:]) >>
2283 if isinstance(key, string_types):
2284 value = self.specs.get(key)
2286 raise ObjUnknown("BitString value: %s" % key)
2288 raise InvalidValueType((int, str))
2291 self._assert_ready()
2292 bit_len, octets = self._value
2295 len_encode(len(octets) + 1),
2296 int2byte((8 - bit_len % 8) % 8),
2300 def _decode_chunk(self, lv, offset, decode_path, ctx):
2302 l, llen, v = len_decode(lv)
2303 except DecodeError as err:
2304 raise err.__class__(
2306 klass=self.__class__,
2307 decode_path=decode_path,
2311 raise NotEnoughData(
2312 "encoded length is longer than data",
2313 klass=self.__class__,
2314 decode_path=decode_path,
2318 raise NotEnoughData(
2320 klass=self.__class__,
2321 decode_path=decode_path,
2324 pad_size = byte2int(v)
2325 if l == 1 and pad_size != 0:
2327 "invalid empty value",
2328 klass=self.__class__,
2329 decode_path=decode_path,
2335 klass=self.__class__,
2336 decode_path=decode_path,
2339 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2342 klass=self.__class__,
2343 decode_path=decode_path,
2346 v, tail = v[:l], v[l:]
2347 obj = self.__class__(
2348 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2351 default=self.default,
2352 optional=self.optional,
2354 _decoded=(offset, llen, l),
2358 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2360 t, tlen, lv = tag_strip(tlv)
2361 except DecodeError as err:
2362 raise err.__class__(
2364 klass=self.__class__,
2365 decode_path=decode_path,
2369 if tag_only: # pragma: no cover
2371 return self._decode_chunk(lv, offset, decode_path, ctx)
2372 if t == self.tag_constructed:
2373 if not ctx.get("bered", False):
2375 "unallowed BER constructed encoding",
2376 klass=self.__class__,
2377 decode_path=decode_path,
2380 if tag_only: # pragma: no cover
2384 l, llen, v = len_decode(lv)
2385 except LenIndefForm:
2386 llen, l, v = 1, 0, lv[1:]
2388 except DecodeError as err:
2389 raise err.__class__(
2391 klass=self.__class__,
2392 decode_path=decode_path,
2396 raise NotEnoughData(
2397 "encoded length is longer than data",
2398 klass=self.__class__,
2399 decode_path=decode_path,
2402 if not lenindef and l == 0:
2403 raise NotEnoughData(
2405 klass=self.__class__,
2406 decode_path=decode_path,
2410 sub_offset = offset + tlen + llen
2414 if v[:EOC_LEN].tobytes() == EOC:
2421 "chunk out of bounds",
2422 klass=self.__class__,
2423 decode_path=decode_path + (str(len(chunks) - 1),),
2424 offset=chunks[-1].offset,
2426 sub_decode_path = decode_path + (str(len(chunks)),)
2428 chunk, v_tail = BitString().decode(
2431 decode_path=sub_decode_path,
2434 _ctx_immutable=False,
2438 "expected BitString encoded chunk",
2439 klass=self.__class__,
2440 decode_path=sub_decode_path,
2443 chunks.append(chunk)
2444 sub_offset += chunk.tlvlen
2445 vlen += chunk.tlvlen
2447 if len(chunks) == 0:
2450 klass=self.__class__,
2451 decode_path=decode_path,
2456 for chunk_i, chunk in enumerate(chunks[:-1]):
2457 if chunk.bit_len % 8 != 0:
2459 "BitString chunk is not multiple of 8 bits",
2460 klass=self.__class__,
2461 decode_path=decode_path + (str(chunk_i),),
2462 offset=chunk.offset,
2464 values.append(bytes(chunk))
2465 bit_len += chunk.bit_len
2466 chunk_last = chunks[-1]
2467 values.append(bytes(chunk_last))
2468 bit_len += chunk_last.bit_len
2469 obj = self.__class__(
2470 value=(bit_len, b"".join(values)),
2473 default=self.default,
2474 optional=self.optional,
2476 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2478 obj.lenindef = lenindef
2479 obj.ber_encoded = True
2480 return obj, (v[EOC_LEN:] if lenindef else v)
2482 klass=self.__class__,
2483 decode_path=decode_path,
2488 return pp_console_row(next(self.pps()))
2490 def pps(self, decode_path=()):
2494 bit_len, blob = self._value
2495 value = "%d bits" % bit_len
2496 if len(self.specs) > 0:
2497 blob = tuple(self.named)
2500 asn1_type_name=self.asn1_type_name,
2501 obj_name=self.__class__.__name__,
2502 decode_path=decode_path,
2505 optional=self.optional,
2506 default=self == self.default,
2507 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2508 expl=None if self._expl is None else tag_decode(self._expl),
2513 expl_offset=self.expl_offset if self.expled else None,
2514 expl_tlen=self.expl_tlen if self.expled else None,
2515 expl_llen=self.expl_llen if self.expled else None,
2516 expl_vlen=self.expl_vlen if self.expled else None,
2517 expl_lenindef=self.expl_lenindef,
2518 lenindef=self.lenindef,
2519 ber_encoded=self.ber_encoded,
2522 defined_by, defined = self.defined or (None, None)
2523 if defined_by is not None:
2525 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2527 for pp in self.pps_lenindef(decode_path):
2531 class OctetString(Obj):
2532 """``OCTET STRING`` binary string type
2534 >>> s = OctetString(b"hello world")
2535 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2536 >>> s == OctetString(b"hello world")
2541 >>> OctetString(b"hello", bounds=(4, 4))
2542 Traceback (most recent call last):
2543 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2544 >>> OctetString(b"hell", bounds=(4, 4))
2545 OCTET STRING 4 bytes 68656c6c
2549 Pay attention that OCTET STRING can be encoded both in primitive
2550 and constructed forms. Decoder always checks constructed form tag
2551 additionally to specified primitive one. If BER decoding is
2552 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2553 of DER restrictions.
2555 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2556 tag_default = tag_encode(4)
2557 asn1_type_name = "OCTET STRING"
2570 :param value: set the value. Either binary type, or
2571 :py:class:`pyderasn.OctetString` object
2572 :param bounds: set ``(MIN, MAX)`` value size constraint.
2573 (-inf, +inf) by default
2574 :param bytes impl: override default tag with ``IMPLICIT`` one
2575 :param bytes expl: override default tag with ``EXPLICIT`` one
2576 :param default: set default value. Type same as in ``value``
2577 :param bool optional: is object ``OPTIONAL`` in sequence
2579 super(OctetString, self).__init__(
2587 self._bound_min, self._bound_max = getattr(
2591 ) if bounds is None else bounds
2592 if value is not None:
2593 self._value = self._value_sanitize(value)
2594 if default is not None:
2595 default = self._value_sanitize(default)
2596 self.default = self.__class__(
2601 if self._value is None:
2602 self._value = default
2604 tag_klass, _, tag_num = tag_decode(self.tag)
2605 self.tag_constructed = tag_encode(
2607 form=TagFormConstructed,
2611 def _value_sanitize(self, value):
2612 if isinstance(value, binary_type):
2614 elif issubclass(value.__class__, OctetString):
2615 value = value._value
2617 raise InvalidValueType((self.__class__, bytes))
2618 if not self._bound_min <= len(value) <= self._bound_max:
2619 raise BoundsError(self._bound_min, len(value), self._bound_max)
2624 return self._value is not None
2627 obj = self.__class__()
2628 obj._value = self._value
2629 obj._bound_min = self._bound_min
2630 obj._bound_max = self._bound_max
2632 obj._expl = self._expl
2633 obj.default = self.default
2634 obj.optional = self.optional
2635 obj.offset = self.offset
2636 obj.llen = self.llen
2637 obj.vlen = self.vlen
2638 obj.expl_lenindef = self.expl_lenindef
2639 obj.lenindef = self.lenindef
2640 obj.ber_encoded = self.ber_encoded
2643 def __bytes__(self):
2644 self._assert_ready()
2647 def __eq__(self, their):
2648 if isinstance(their, binary_type):
2649 return self._value == their
2650 if not issubclass(their.__class__, OctetString):
2653 self._value == their._value and
2654 self.tag == their.tag and
2655 self._expl == their._expl
2658 def __lt__(self, their):
2659 return self._value < their._value
2670 return self.__class__(
2673 (self._bound_min, self._bound_max)
2674 if bounds is None else bounds
2676 impl=self.tag if impl is None else impl,
2677 expl=self._expl if expl is None else expl,
2678 default=self.default if default is None else default,
2679 optional=self.optional if optional is None else optional,
2683 self._assert_ready()
2686 len_encode(len(self._value)),
2690 def _decode_chunk(self, lv, offset, decode_path, ctx):
2692 l, llen, v = len_decode(lv)
2693 except DecodeError as err:
2694 raise err.__class__(
2696 klass=self.__class__,
2697 decode_path=decode_path,
2701 raise NotEnoughData(
2702 "encoded length is longer than data",
2703 klass=self.__class__,
2704 decode_path=decode_path,
2707 v, tail = v[:l], v[l:]
2709 obj = self.__class__(
2711 bounds=(self._bound_min, self._bound_max),
2714 default=self.default,
2715 optional=self.optional,
2716 _decoded=(offset, llen, l),
2718 except DecodeError as err:
2721 klass=self.__class__,
2722 decode_path=decode_path,
2725 except BoundsError as err:
2728 klass=self.__class__,
2729 decode_path=decode_path,
2734 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2736 t, tlen, lv = tag_strip(tlv)
2737 except DecodeError as err:
2738 raise err.__class__(
2740 klass=self.__class__,
2741 decode_path=decode_path,
2747 return self._decode_chunk(lv, offset, decode_path, ctx)
2748 if t == self.tag_constructed:
2749 if not ctx.get("bered", False):
2751 "unallowed BER constructed encoding",
2752 klass=self.__class__,
2753 decode_path=decode_path,
2760 l, llen, v = len_decode(lv)
2761 except LenIndefForm:
2762 llen, l, v = 1, 0, lv[1:]
2764 except DecodeError as err:
2765 raise err.__class__(
2767 klass=self.__class__,
2768 decode_path=decode_path,
2772 raise NotEnoughData(
2773 "encoded length is longer than data",
2774 klass=self.__class__,
2775 decode_path=decode_path,
2779 sub_offset = offset + tlen + llen
2783 if v[:EOC_LEN].tobytes() == EOC:
2790 "chunk out of bounds",
2791 klass=self.__class__,
2792 decode_path=decode_path + (str(len(chunks) - 1),),
2793 offset=chunks[-1].offset,
2795 sub_decode_path = decode_path + (str(len(chunks)),)
2797 chunk, v_tail = OctetString().decode(
2800 decode_path=sub_decode_path,
2803 _ctx_immutable=False,
2807 "expected OctetString encoded chunk",
2808 klass=self.__class__,
2809 decode_path=sub_decode_path,
2812 chunks.append(chunk)
2813 sub_offset += chunk.tlvlen
2814 vlen += chunk.tlvlen
2817 obj = self.__class__(
2818 value=b"".join(bytes(chunk) for chunk in chunks),
2819 bounds=(self._bound_min, self._bound_max),
2822 default=self.default,
2823 optional=self.optional,
2824 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2826 except DecodeError as err:
2829 klass=self.__class__,
2830 decode_path=decode_path,
2833 except BoundsError as err:
2836 klass=self.__class__,
2837 decode_path=decode_path,
2840 obj.lenindef = lenindef
2841 obj.ber_encoded = True
2842 return obj, (v[EOC_LEN:] if lenindef else v)
2844 klass=self.__class__,
2845 decode_path=decode_path,
2850 return pp_console_row(next(self.pps()))
2852 def pps(self, decode_path=()):
2855 asn1_type_name=self.asn1_type_name,
2856 obj_name=self.__class__.__name__,
2857 decode_path=decode_path,
2858 value=("%d bytes" % len(self._value)) if self.ready else None,
2859 blob=self._value if self.ready else None,
2860 optional=self.optional,
2861 default=self == self.default,
2862 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2863 expl=None if self._expl is None else tag_decode(self._expl),
2868 expl_offset=self.expl_offset if self.expled else None,
2869 expl_tlen=self.expl_tlen if self.expled else None,
2870 expl_llen=self.expl_llen if self.expled else None,
2871 expl_vlen=self.expl_vlen if self.expled else None,
2872 expl_lenindef=self.expl_lenindef,
2873 lenindef=self.lenindef,
2874 ber_encoded=self.ber_encoded,
2877 defined_by, defined = self.defined or (None, None)
2878 if defined_by is not None:
2880 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2882 for pp in self.pps_lenindef(decode_path):
2887 """``NULL`` null object
2895 tag_default = tag_encode(5)
2896 asn1_type_name = "NULL"
2900 value=None, # unused, but Sequence passes it
2907 :param bytes impl: override default tag with ``IMPLICIT`` one
2908 :param bytes expl: override default tag with ``EXPLICIT`` one
2909 :param bool optional: is object ``OPTIONAL`` in sequence
2911 super(Null, self).__init__(impl, expl, None, optional, _decoded)
2919 obj = self.__class__()
2921 obj._expl = self._expl
2922 obj.default = self.default
2923 obj.optional = self.optional
2924 obj.offset = self.offset
2925 obj.llen = self.llen
2926 obj.vlen = self.vlen
2927 obj.expl_lenindef = self.expl_lenindef
2928 obj.lenindef = self.lenindef
2929 obj.ber_encoded = self.ber_encoded
2932 def __eq__(self, their):
2933 if not issubclass(their.__class__, Null):
2936 self.tag == their.tag and
2937 self._expl == their._expl
2947 return self.__class__(
2948 impl=self.tag if impl is None else impl,
2949 expl=self._expl if expl is None else expl,
2950 optional=self.optional if optional is None else optional,
2954 return self.tag + len_encode(0)
2956 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2958 t, _, lv = tag_strip(tlv)
2959 except DecodeError as err:
2960 raise err.__class__(
2962 klass=self.__class__,
2963 decode_path=decode_path,
2968 klass=self.__class__,
2969 decode_path=decode_path,
2972 if tag_only: # pragma: no cover
2975 l, _, v = len_decode(lv)
2976 except DecodeError as err:
2977 raise err.__class__(
2979 klass=self.__class__,
2980 decode_path=decode_path,
2984 raise InvalidLength(
2985 "Null must have zero length",
2986 klass=self.__class__,
2987 decode_path=decode_path,
2990 obj = self.__class__(
2993 optional=self.optional,
2994 _decoded=(offset, 1, 0),
2999 return pp_console_row(next(self.pps()))
3001 def pps(self, decode_path=()):
3004 asn1_type_name=self.asn1_type_name,
3005 obj_name=self.__class__.__name__,
3006 decode_path=decode_path,
3007 optional=self.optional,
3008 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3009 expl=None if self._expl is None else tag_decode(self._expl),
3014 expl_offset=self.expl_offset if self.expled else None,
3015 expl_tlen=self.expl_tlen if self.expled else None,
3016 expl_llen=self.expl_llen if self.expled else None,
3017 expl_vlen=self.expl_vlen if self.expled else None,
3018 expl_lenindef=self.expl_lenindef,
3021 for pp in self.pps_lenindef(decode_path):
3025 class ObjectIdentifier(Obj):
3026 """``OBJECT IDENTIFIER`` OID type
3028 >>> oid = ObjectIdentifier((1, 2, 3))
3029 OBJECT IDENTIFIER 1.2.3
3030 >>> oid == ObjectIdentifier("1.2.3")
3036 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3037 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3039 >>> str(ObjectIdentifier((3, 1)))
3040 Traceback (most recent call last):
3041 pyderasn.InvalidOID: unacceptable first arc value
3043 __slots__ = ("defines",)
3044 tag_default = tag_encode(6)
3045 asn1_type_name = "OBJECT IDENTIFIER"
3058 :param value: set the value. Either tuples of integers,
3059 string of "."-concatenated integers, or
3060 :py:class:`pyderasn.ObjectIdentifier` object
3061 :param defines: sequence of tuples. Each tuple has two elements.
3062 First one is relative to current one decode
3063 path, aiming to the field defined by that OID.
3064 Read about relative path in
3065 :py:func:`pyderasn.abs_decode_path`. Second
3066 tuple element is ``{OID: pyderasn.Obj()}``
3067 dictionary, mapping between current OID value
3068 and structure applied to defined field.
3069 :ref:`Read about DEFINED BY <definedby>`
3070 :param bytes impl: override default tag with ``IMPLICIT`` one
3071 :param bytes expl: override default tag with ``EXPLICIT`` one
3072 :param default: set default value. Type same as in ``value``
3073 :param bool optional: is object ``OPTIONAL`` in sequence
3075 super(ObjectIdentifier, self).__init__(
3083 if value is not None:
3084 self._value = self._value_sanitize(value)
3085 if default is not None:
3086 default = self._value_sanitize(default)
3087 self.default = self.__class__(
3092 if self._value is None:
3093 self._value = default
3094 self.defines = defines
3096 def __add__(self, their):
3097 if isinstance(their, self.__class__):
3098 return self.__class__(self._value + their._value)
3099 if isinstance(their, tuple):
3100 return self.__class__(self._value + their)
3101 raise InvalidValueType((self.__class__, tuple))
3103 def _value_sanitize(self, value):
3104 if issubclass(value.__class__, ObjectIdentifier):
3106 if isinstance(value, string_types):
3108 value = tuple(int(arc) for arc in value.split("."))
3110 raise InvalidOID("unacceptable arcs values")
3111 if isinstance(value, tuple):
3113 raise InvalidOID("less than 2 arcs")
3114 first_arc = value[0]
3115 if first_arc in (0, 1):
3116 if not (0 <= value[1] <= 39):
3117 raise InvalidOID("second arc is too wide")
3118 elif first_arc == 2:
3121 raise InvalidOID("unacceptable first arc value")
3123 raise InvalidValueType((self.__class__, str, tuple))
3127 return self._value is not None
3130 obj = self.__class__()
3131 obj._value = self._value
3132 obj.defines = self.defines
3134 obj._expl = self._expl
3135 obj.default = self.default
3136 obj.optional = self.optional
3137 obj.offset = self.offset
3138 obj.llen = self.llen
3139 obj.vlen = self.vlen
3140 obj.expl_lenindef = self.expl_lenindef
3141 obj.lenindef = self.lenindef
3142 obj.ber_encoded = self.ber_encoded
3146 self._assert_ready()
3147 return iter(self._value)
3150 return ".".join(str(arc) for arc in self._value or ())
3153 self._assert_ready()
3156 bytes(self._expl or b"") +
3157 str(self._value).encode("ascii"),
3160 def __eq__(self, their):
3161 if isinstance(their, tuple):
3162 return self._value == their
3163 if not issubclass(their.__class__, ObjectIdentifier):
3166 self.tag == their.tag and
3167 self._expl == their._expl and
3168 self._value == their._value
3171 def __lt__(self, their):
3172 return self._value < their._value
3183 return self.__class__(
3185 defines=self.defines if defines is None else defines,
3186 impl=self.tag if impl is None else impl,
3187 expl=self._expl if expl is None else expl,
3188 default=self.default if default is None else default,
3189 optional=self.optional if optional is None else optional,
3193 self._assert_ready()
3195 first_value = value[1]
3196 first_arc = value[0]
3199 elif first_arc == 1:
3201 elif first_arc == 2:
3203 else: # pragma: no cover
3204 raise RuntimeError("invalid arc is stored")
3205 octets = [zero_ended_encode(first_value)]
3206 for arc in value[2:]:
3207 octets.append(zero_ended_encode(arc))
3208 v = b"".join(octets)
3209 return b"".join((self.tag, len_encode(len(v)), v))
3211 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3213 t, _, lv = tag_strip(tlv)
3214 except DecodeError as err:
3215 raise err.__class__(
3217 klass=self.__class__,
3218 decode_path=decode_path,
3223 klass=self.__class__,
3224 decode_path=decode_path,
3227 if tag_only: # pragma: no cover
3230 l, llen, v = len_decode(lv)
3231 except DecodeError as err:
3232 raise err.__class__(
3234 klass=self.__class__,
3235 decode_path=decode_path,
3239 raise NotEnoughData(
3240 "encoded length is longer than data",
3241 klass=self.__class__,
3242 decode_path=decode_path,
3246 raise NotEnoughData(
3248 klass=self.__class__,
3249 decode_path=decode_path,
3252 v, tail = v[:l], v[l:]
3259 octet = indexbytes(v, i)
3260 if i == 0 and octet == 0x80:
3261 if ctx.get("bered", False):
3264 raise DecodeError("non normalized arc encoding")
3265 arc = (arc << 7) | (octet & 0x7F)
3266 if octet & 0x80 == 0:
3274 klass=self.__class__,
3275 decode_path=decode_path,
3279 second_arc = arcs[0]
3280 if 0 <= second_arc <= 39:
3282 elif 40 <= second_arc <= 79:
3288 obj = self.__class__(
3289 value=tuple([first_arc, second_arc] + arcs[1:]),
3292 default=self.default,
3293 optional=self.optional,
3294 _decoded=(offset, llen, l),
3297 obj.ber_encoded = True
3301 return pp_console_row(next(self.pps()))
3303 def pps(self, decode_path=()):
3306 asn1_type_name=self.asn1_type_name,
3307 obj_name=self.__class__.__name__,
3308 decode_path=decode_path,
3309 value=str(self) if self.ready else None,
3310 optional=self.optional,
3311 default=self == self.default,
3312 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3313 expl=None if self._expl is None else tag_decode(self._expl),
3318 expl_offset=self.expl_offset if self.expled else None,
3319 expl_tlen=self.expl_tlen if self.expled else None,
3320 expl_llen=self.expl_llen if self.expled else None,
3321 expl_vlen=self.expl_vlen if self.expled else None,
3322 expl_lenindef=self.expl_lenindef,
3323 ber_encoded=self.ber_encoded,
3326 for pp in self.pps_lenindef(decode_path):
3330 class Enumerated(Integer):
3331 """``ENUMERATED`` integer type
3333 This type is identical to :py:class:`pyderasn.Integer`, but requires
3334 schema to be specified and does not accept values missing from it.
3337 tag_default = tag_encode(10)
3338 asn1_type_name = "ENUMERATED"
3349 bounds=None, # dummy argument, workability for Integer.decode
3351 super(Enumerated, self).__init__(
3360 if len(self.specs) == 0:
3361 raise ValueError("schema must be specified")
3363 def _value_sanitize(self, value):
3364 if isinstance(value, self.__class__):
3365 value = value._value
3366 elif isinstance(value, integer_types):
3367 for _value in itervalues(self.specs):
3372 "unknown integer value: %s" % value,
3373 klass=self.__class__,
3375 elif isinstance(value, string_types):
3376 value = self.specs.get(value)
3378 raise ObjUnknown("integer value: %s" % value)
3380 raise InvalidValueType((self.__class__, int, str))
3384 obj = self.__class__(_specs=self.specs)
3385 obj._value = self._value
3386 obj._bound_min = self._bound_min
3387 obj._bound_max = self._bound_max
3389 obj._expl = self._expl
3390 obj.default = self.default
3391 obj.optional = self.optional
3392 obj.offset = self.offset
3393 obj.llen = self.llen
3394 obj.vlen = self.vlen
3395 obj.expl_lenindef = self.expl_lenindef
3396 obj.lenindef = self.lenindef
3397 obj.ber_encoded = self.ber_encoded
3409 return self.__class__(
3411 impl=self.tag if impl is None else impl,
3412 expl=self._expl if expl is None else expl,
3413 default=self.default if default is None else default,
3414 optional=self.optional if optional is None else optional,
3419 class CommonString(OctetString):
3420 """Common class for all strings
3422 Everything resembles :py:class:`pyderasn.OctetString`, except
3423 ability to deal with unicode text strings.
3425 >>> hexenc("привет мир".encode("utf-8"))
3426 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3427 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3429 >>> s = UTF8String("привет мир")
3430 UTF8String UTF8String привет мир
3432 'привет мир'
3433 >>> hexenc(bytes(s))
3434 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3436 >>> PrintableString("привет мир")
3437 Traceback (most recent call last):
3438 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3440 >>> BMPString("ада", bounds=(2, 2))
3441 Traceback (most recent call last):
3442 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3443 >>> s = BMPString("ад", bounds=(2, 2))
3446 >>> hexenc(bytes(s))
3454 * - :py:class:`pyderasn.UTF8String`
3456 * - :py:class:`pyderasn.NumericString`
3458 * - :py:class:`pyderasn.PrintableString`
3460 * - :py:class:`pyderasn.TeletexString`
3462 * - :py:class:`pyderasn.T61String`
3464 * - :py:class:`pyderasn.VideotexString`
3466 * - :py:class:`pyderasn.IA5String`
3468 * - :py:class:`pyderasn.GraphicString`
3470 * - :py:class:`pyderasn.VisibleString`
3472 * - :py:class:`pyderasn.ISO646String`
3474 * - :py:class:`pyderasn.GeneralString`
3476 * - :py:class:`pyderasn.UniversalString`
3478 * - :py:class:`pyderasn.BMPString`
3481 __slots__ = ("encoding",)
3483 def _value_sanitize(self, value):
3485 value_decoded = None
3486 if isinstance(value, self.__class__):
3487 value_raw = value._value
3488 elif isinstance(value, text_type):
3489 value_decoded = value
3490 elif isinstance(value, binary_type):
3493 raise InvalidValueType((self.__class__, text_type, binary_type))
3496 value_decoded.encode(self.encoding)
3497 if value_raw is None else value_raw
3500 value_raw.decode(self.encoding)
3501 if value_decoded is None else value_decoded
3503 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3504 raise DecodeError(str(err))
3505 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3513 def __eq__(self, their):
3514 if isinstance(their, binary_type):
3515 return self._value == their
3516 if isinstance(their, text_type):
3517 return self._value == their.encode(self.encoding)
3518 if not isinstance(their, self.__class__):
3521 self._value == their._value and
3522 self.tag == their.tag and
3523 self._expl == their._expl
3526 def __unicode__(self):
3528 return self._value.decode(self.encoding)
3529 return text_type(self._value)
3532 return pp_console_row(next(self.pps(no_unicode=PY2)))
3534 def pps(self, decode_path=(), no_unicode=False):
3537 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
3540 asn1_type_name=self.asn1_type_name,
3541 obj_name=self.__class__.__name__,
3542 decode_path=decode_path,
3544 optional=self.optional,
3545 default=self == self.default,
3546 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3547 expl=None if self._expl is None else tag_decode(self._expl),
3552 expl_offset=self.expl_offset if self.expled else None,
3553 expl_tlen=self.expl_tlen if self.expled else None,
3554 expl_llen=self.expl_llen if self.expled else None,
3555 expl_vlen=self.expl_vlen if self.expled else None,
3556 expl_lenindef=self.expl_lenindef,
3557 ber_encoded=self.ber_encoded,
3560 for pp in self.pps_lenindef(decode_path):
3564 class UTF8String(CommonString):
3566 tag_default = tag_encode(12)
3568 asn1_type_name = "UTF8String"
3571 class AllowableCharsMixin(object):
3573 def allowable_chars(self):
3575 return self._allowable_chars
3576 return frozenset(six_unichr(c) for c in self._allowable_chars)
3579 class NumericString(AllowableCharsMixin, CommonString):
3582 Its value is properly sanitized: only ASCII digits with spaces can
3585 >>> NumericString().allowable_chars
3586 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3589 tag_default = tag_encode(18)
3591 asn1_type_name = "NumericString"
3592 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3594 def _value_sanitize(self, value):
3595 value = super(NumericString, self)._value_sanitize(value)
3596 if not frozenset(value) <= self._allowable_chars:
3597 raise DecodeError("non-numeric value")
3601 class PrintableString(AllowableCharsMixin, CommonString):
3604 Its value is properly sanitized: see X.680 41.4 table 10.
3606 >>> PrintableString().allowable_chars
3607 frozenset([' ', "'", ..., 'z'])
3610 tag_default = tag_encode(19)
3612 asn1_type_name = "PrintableString"
3613 _allowable_chars = frozenset(
3614 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3617 def _value_sanitize(self, value):
3618 value = super(PrintableString, self)._value_sanitize(value)
3619 if not frozenset(value) <= self._allowable_chars:
3620 raise DecodeError("non-printable value")
3624 class TeletexString(CommonString):
3626 tag_default = tag_encode(20)
3628 asn1_type_name = "TeletexString"
3631 class T61String(TeletexString):
3633 asn1_type_name = "T61String"
3636 class VideotexString(CommonString):
3638 tag_default = tag_encode(21)
3639 encoding = "iso-8859-1"
3640 asn1_type_name = "VideotexString"
3643 class IA5String(CommonString):
3645 tag_default = tag_encode(22)
3647 asn1_type_name = "IA5"
3650 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3651 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3652 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3655 class UTCTime(CommonString):
3656 """``UTCTime`` datetime type
3658 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3659 UTCTime UTCTime 2017-09-30T22:07:50
3665 datetime.datetime(2017, 9, 30, 22, 7, 50)
3666 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3667 datetime.datetime(1957, 9, 30, 22, 7, 50)
3671 BER encoding is unsupported.
3674 tag_default = tag_encode(23)
3676 asn1_type_name = "UTCTime"
3686 bounds=None, # dummy argument, workability for OctetString.decode
3689 :param value: set the value. Either datetime type, or
3690 :py:class:`pyderasn.UTCTime` object
3691 :param bytes impl: override default tag with ``IMPLICIT`` one
3692 :param bytes expl: override default tag with ``EXPLICIT`` one
3693 :param default: set default value. Type same as in ``value``
3694 :param bool optional: is object ``OPTIONAL`` in sequence
3696 super(UTCTime, self).__init__(
3704 if value is not None:
3705 self._value = self._value_sanitize(value)
3706 if default is not None:
3707 default = self._value_sanitize(default)
3708 self.default = self.__class__(
3713 if self._value is None:
3714 self._value = default
3716 def _strptime(self, value):
3717 # datetime.strptime's format: %y%m%d%H%M%SZ
3718 if len(value) != LEN_YYMMDDHHMMSSZ:
3719 raise ValueError("invalid UTCTime length")
3720 if value[-1] != "Z":
3721 raise ValueError("non UTC timezone")
3723 2000 + int(value[:2]), # %y
3724 int(value[2:4]), # %m
3725 int(value[4:6]), # %d
3726 int(value[6:8]), # %H
3727 int(value[8:10]), # %M
3728 int(value[10:12]), # %S
3731 def _value_sanitize(self, value):
3732 if isinstance(value, binary_type):
3734 value_decoded = value.decode("ascii")
3735 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3736 raise DecodeError("invalid UTCTime encoding")
3738 self._strptime(value_decoded)
3739 except (TypeError, ValueError) as err:
3740 raise DecodeError("invalid UTCTime format: %r" % err)
3742 if isinstance(value, self.__class__):
3744 if isinstance(value, datetime):
3745 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3746 raise InvalidValueType((self.__class__, datetime))
3748 def __eq__(self, their):
3749 if isinstance(their, binary_type):
3750 return self._value == their
3751 if isinstance(their, datetime):
3752 return self.todatetime() == their
3753 if not isinstance(their, self.__class__):
3756 self._value == their._value and
3757 self.tag == their.tag and
3758 self._expl == their._expl
3761 def todatetime(self):
3762 """Convert to datetime
3766 Pay attention that UTCTime can not hold full year, so all years
3767 having < 50 years are treated as 20xx, 19xx otherwise, according
3768 to X.509 recomendation.
3770 value = self._strptime(self._value.decode("ascii"))
3771 year = value.year % 100
3773 year=(2000 + year) if year < 50 else (1900 + year),
3777 minute=value.minute,
3778 second=value.second,
3782 return pp_console_row(next(self.pps()))
3784 def pps(self, decode_path=()):
3787 asn1_type_name=self.asn1_type_name,
3788 obj_name=self.__class__.__name__,
3789 decode_path=decode_path,
3790 value=self.todatetime().isoformat() if self.ready else None,
3791 optional=self.optional,
3792 default=self == self.default,
3793 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3794 expl=None if self._expl is None else tag_decode(self._expl),
3799 expl_offset=self.expl_offset if self.expled else None,
3800 expl_tlen=self.expl_tlen if self.expled else None,
3801 expl_llen=self.expl_llen if self.expled else None,
3802 expl_vlen=self.expl_vlen if self.expled else None,
3803 expl_lenindef=self.expl_lenindef,
3804 ber_encoded=self.ber_encoded,
3807 for pp in self.pps_lenindef(decode_path):
3811 class GeneralizedTime(UTCTime):
3812 """``GeneralizedTime`` datetime type
3814 This type is similar to :py:class:`pyderasn.UTCTime`.
3816 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3817 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3819 '20170930220750.000123Z'
3820 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3821 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3825 BER encoding is unsupported.
3829 Only microsecond fractions are supported.
3830 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
3831 higher precision values.
3834 tag_default = tag_encode(24)
3835 asn1_type_name = "GeneralizedTime"
3837 def _strptime(self, value):
3839 if l == LEN_YYYYMMDDHHMMSSZ:
3840 # datetime.strptime's format: %y%m%d%H%M%SZ
3841 if value[-1] != "Z":
3842 raise ValueError("non UTC timezone")
3844 int(value[:4]), # %Y
3845 int(value[4:6]), # %m
3846 int(value[6:8]), # %d
3847 int(value[8:10]), # %H
3848 int(value[10:12]), # %M
3849 int(value[12:14]), # %S
3851 if l >= LEN_YYYYMMDDHHMMSSDMZ:
3852 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
3853 if value[-1] != "Z":
3854 raise ValueError("non UTC timezone")
3855 if value[14] != ".":
3856 raise ValueError("no fractions separator")
3859 raise ValueError("trailing zero")
3862 raise ValueError("only microsecond fractions are supported")
3863 us = int(us + ("0" * (6 - us_len)))
3865 int(value[:4]), # %Y
3866 int(value[4:6]), # %m
3867 int(value[6:8]), # %d
3868 int(value[8:10]), # %H
3869 int(value[10:12]), # %M
3870 int(value[12:14]), # %S
3874 raise ValueError("invalid GeneralizedTime length")
3876 def _value_sanitize(self, value):
3877 if isinstance(value, binary_type):
3879 value_decoded = value.decode("ascii")
3880 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3881 raise DecodeError("invalid GeneralizedTime encoding")
3883 self._strptime(value_decoded)
3884 except (TypeError, ValueError) as err:
3886 "invalid GeneralizedTime format: %r" % err,
3887 klass=self.__class__,
3890 if isinstance(value, self.__class__):
3892 if isinstance(value, datetime):
3893 encoded = value.strftime("%Y%m%d%H%M%S")
3894 if value.microsecond > 0:
3895 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
3896 return (encoded + "Z").encode("ascii")
3897 raise InvalidValueType((self.__class__, datetime))
3899 def todatetime(self):
3900 return self._strptime(self._value.decode("ascii"))
3903 class GraphicString(CommonString):
3905 tag_default = tag_encode(25)
3906 encoding = "iso-8859-1"
3907 asn1_type_name = "GraphicString"
3910 class VisibleString(CommonString):
3912 tag_default = tag_encode(26)
3914 asn1_type_name = "VisibleString"
3917 class ISO646String(VisibleString):
3919 asn1_type_name = "ISO646String"
3922 class GeneralString(CommonString):
3924 tag_default = tag_encode(27)
3925 encoding = "iso-8859-1"
3926 asn1_type_name = "GeneralString"
3929 class UniversalString(CommonString):
3931 tag_default = tag_encode(28)
3932 encoding = "utf-32-be"
3933 asn1_type_name = "UniversalString"
3936 class BMPString(CommonString):
3938 tag_default = tag_encode(30)
3939 encoding = "utf-16-be"
3940 asn1_type_name = "BMPString"
3944 """``CHOICE`` special type
3948 class GeneralName(Choice):
3950 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
3951 ("dNSName", IA5String(impl=tag_ctxp(2))),
3954 >>> gn = GeneralName()
3956 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
3957 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3958 >>> gn["dNSName"] = IA5String("bar.baz")
3959 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
3960 >>> gn["rfc822Name"]
3963 [2] IA5String IA5 bar.baz
3966 >>> gn.value == gn["dNSName"]
3969 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
3971 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
3972 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3974 __slots__ = ("specs",)
3976 asn1_type_name = "CHOICE"
3989 :param value: set the value. Either ``(choice, value)`` tuple, or
3990 :py:class:`pyderasn.Choice` object
3991 :param bytes impl: can not be set, do **not** use it
3992 :param bytes expl: override default tag with ``EXPLICIT`` one
3993 :param default: set default value. Type same as in ``value``
3994 :param bool optional: is object ``OPTIONAL`` in sequence
3996 if impl is not None:
3997 raise ValueError("no implicit tag allowed for CHOICE")
3998 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4000 schema = getattr(self, "schema", ())
4001 if len(schema) == 0:
4002 raise ValueError("schema must be specified")
4004 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4007 if value is not None:
4008 self._value = self._value_sanitize(value)
4009 if default is not None:
4010 default_value = self._value_sanitize(default)
4011 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4012 default_obj.specs = self.specs
4013 default_obj._value = default_value
4014 self.default = default_obj
4016 self._value = default_obj.copy()._value
4018 def _value_sanitize(self, value):
4019 if isinstance(value, tuple) and len(value) == 2:
4021 spec = self.specs.get(choice)
4023 raise ObjUnknown(choice)
4024 if not isinstance(obj, spec.__class__):
4025 raise InvalidValueType((spec,))
4026 return (choice, spec(obj))
4027 if isinstance(value, self.__class__):
4029 raise InvalidValueType((self.__class__, tuple))
4033 return self._value is not None and self._value[1].ready
4037 return self.expl_lenindef or (
4038 (self._value is not None) and
4039 self._value[1].bered
4043 obj = self.__class__(schema=self.specs)
4044 obj._expl = self._expl
4045 obj.default = self.default
4046 obj.optional = self.optional
4047 obj.offset = self.offset
4048 obj.llen = self.llen
4049 obj.vlen = self.vlen
4050 obj.expl_lenindef = self.expl_lenindef
4051 obj.lenindef = self.lenindef
4052 obj.ber_encoded = self.ber_encoded
4054 if value is not None:
4055 obj._value = (value[0], value[1].copy())
4058 def __eq__(self, their):
4059 if isinstance(their, tuple) and len(their) == 2:
4060 return self._value == their
4061 if not isinstance(their, self.__class__):
4064 self.specs == their.specs and
4065 self._value == their._value
4075 return self.__class__(
4078 expl=self._expl if expl is None else expl,
4079 default=self.default if default is None else default,
4080 optional=self.optional if optional is None else optional,
4085 self._assert_ready()
4086 return self._value[0]
4090 self._assert_ready()
4091 return self._value[1]
4093 def __getitem__(self, key):
4094 if key not in self.specs:
4095 raise ObjUnknown(key)
4096 if self._value is None:
4098 choice, value = self._value
4103 def __setitem__(self, key, value):
4104 spec = self.specs.get(key)
4106 raise ObjUnknown(key)
4107 if not isinstance(value, spec.__class__):
4108 raise InvalidValueType((spec.__class__,))
4109 self._value = (key, spec(value))
4117 return self._value[1].decoded if self.ready else False
4120 self._assert_ready()
4121 return self._value[1].encode()
4123 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4124 for choice, spec in iteritems(self.specs):
4125 sub_decode_path = decode_path + (choice,)
4131 decode_path=sub_decode_path,
4134 _ctx_immutable=False,
4141 klass=self.__class__,
4142 decode_path=decode_path,
4145 if tag_only: # pragma: no cover
4147 value, tail = spec.decode(
4151 decode_path=sub_decode_path,
4153 _ctx_immutable=False,
4155 obj = self.__class__(
4158 default=self.default,
4159 optional=self.optional,
4160 _decoded=(offset, 0, value.fulllen),
4162 obj._value = (choice, value)
4166 value = pp_console_row(next(self.pps()))
4168 value = "%s[%r]" % (value, self.value)
4171 def pps(self, decode_path=()):
4174 asn1_type_name=self.asn1_type_name,
4175 obj_name=self.__class__.__name__,
4176 decode_path=decode_path,
4177 value=self.choice if self.ready else None,
4178 optional=self.optional,
4179 default=self == self.default,
4180 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4181 expl=None if self._expl is None else tag_decode(self._expl),
4186 expl_lenindef=self.expl_lenindef,
4190 yield self.value.pps(decode_path=decode_path + (self.choice,))
4191 for pp in self.pps_lenindef(decode_path):
4195 class PrimitiveTypes(Choice):
4196 """Predefined ``CHOICE`` for all generic primitive types
4198 It could be useful for general decoding of some unspecified values:
4200 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4201 OCTET STRING 3 bytes 666f6f
4202 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4206 schema = tuple((klass.__name__, klass()) for klass in (
4231 """``ANY`` special type
4233 >>> Any(Integer(-123))
4235 >>> a = Any(OctetString(b"hello world").encode())
4236 ANY 040b68656c6c6f20776f726c64
4237 >>> hexenc(bytes(a))
4238 b'0x040x0bhello world'
4240 __slots__ = ("defined",)
4241 tag_default = tag_encode(0)
4242 asn1_type_name = "ANY"
4252 :param value: set the value. Either any kind of pyderasn's
4253 **ready** object, or bytes. Pay attention that
4254 **no** validation is performed is raw binary value
4256 :param bytes expl: override default tag with ``EXPLICIT`` one
4257 :param bool optional: is object ``OPTIONAL`` in sequence
4259 super(Any, self).__init__(None, expl, None, optional, _decoded)
4260 self._value = None if value is None else self._value_sanitize(value)
4263 def _value_sanitize(self, value):
4264 if isinstance(value, binary_type):
4266 if isinstance(value, self.__class__):
4268 if isinstance(value, Obj):
4269 return value.encode()
4270 raise InvalidValueType((self.__class__, Obj, binary_type))
4274 return self._value is not None
4278 if self.expl_lenindef or self.lenindef:
4280 if self.defined is None:
4282 return self.defined[1].bered
4285 obj = self.__class__()
4286 obj._value = self._value
4288 obj._expl = self._expl
4289 obj.optional = self.optional
4290 obj.offset = self.offset
4291 obj.llen = self.llen
4292 obj.vlen = self.vlen
4293 obj.expl_lenindef = self.expl_lenindef
4294 obj.lenindef = self.lenindef
4295 obj.ber_encoded = self.ber_encoded
4298 def __eq__(self, their):
4299 if isinstance(their, binary_type):
4300 return self._value == their
4301 if issubclass(their.__class__, Any):
4302 return self._value == their._value
4311 return self.__class__(
4313 expl=self._expl if expl is None else expl,
4314 optional=self.optional if optional is None else optional,
4317 def __bytes__(self):
4318 self._assert_ready()
4326 self._assert_ready()
4329 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4331 t, tlen, lv = tag_strip(tlv)
4332 except DecodeError as err:
4333 raise err.__class__(
4335 klass=self.__class__,
4336 decode_path=decode_path,
4340 l, llen, v = len_decode(lv)
4341 except LenIndefForm as err:
4342 if not ctx.get("bered", False):
4343 raise err.__class__(
4345 klass=self.__class__,
4346 decode_path=decode_path,
4349 llen, vlen, v = 1, 0, lv[1:]
4350 sub_offset = offset + tlen + llen
4352 while v[:EOC_LEN].tobytes() != EOC:
4353 chunk, v = Any().decode(
4356 decode_path=decode_path + (str(chunk_i),),
4359 _ctx_immutable=False,
4361 vlen += chunk.tlvlen
4362 sub_offset += chunk.tlvlen
4364 tlvlen = tlen + llen + vlen + EOC_LEN
4365 obj = self.__class__(
4366 value=tlv[:tlvlen].tobytes(),
4368 optional=self.optional,
4369 _decoded=(offset, 0, tlvlen),
4373 return obj, v[EOC_LEN:]
4374 except DecodeError as err:
4375 raise err.__class__(
4377 klass=self.__class__,
4378 decode_path=decode_path,
4382 raise NotEnoughData(
4383 "encoded length is longer than data",
4384 klass=self.__class__,
4385 decode_path=decode_path,
4388 tlvlen = tlen + llen + l
4389 v, tail = tlv[:tlvlen], v[l:]
4390 obj = self.__class__(
4393 optional=self.optional,
4394 _decoded=(offset, 0, tlvlen),
4400 return pp_console_row(next(self.pps()))
4402 def pps(self, decode_path=()):
4405 asn1_type_name=self.asn1_type_name,
4406 obj_name=self.__class__.__name__,
4407 decode_path=decode_path,
4408 blob=self._value if self.ready else None,
4409 optional=self.optional,
4410 default=self == self.default,
4411 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4412 expl=None if self._expl is None else tag_decode(self._expl),
4417 expl_offset=self.expl_offset if self.expled else None,
4418 expl_tlen=self.expl_tlen if self.expled else None,
4419 expl_llen=self.expl_llen if self.expled else None,
4420 expl_vlen=self.expl_vlen if self.expled else None,
4421 expl_lenindef=self.expl_lenindef,
4422 lenindef=self.lenindef,
4425 defined_by, defined = self.defined or (None, None)
4426 if defined_by is not None:
4428 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4430 for pp in self.pps_lenindef(decode_path):
4434 ########################################################################
4435 # ASN.1 constructed types
4436 ########################################################################
4438 def get_def_by_path(defines_by_path, sub_decode_path):
4439 """Get define by decode path
4441 for path, define in defines_by_path:
4442 if len(path) != len(sub_decode_path):
4444 for p1, p2 in zip(path, sub_decode_path):
4445 if (p1 != any) and (p1 != p2):
4451 def abs_decode_path(decode_path, rel_path):
4452 """Create an absolute decode path from current and relative ones
4454 :param decode_path: current decode path, starting point. Tuple of strings
4455 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4456 If first tuple's element is "/", then treat it as
4457 an absolute path, ignoring ``decode_path`` as
4458 starting point. Also this tuple can contain ".."
4459 elements, stripping the leading element from
4462 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4463 ("foo", "bar", "baz", "whatever")
4464 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4466 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4469 if rel_path[0] == "/":
4471 if rel_path[0] == "..":
4472 return abs_decode_path(decode_path[:-1], rel_path[1:])
4473 return decode_path + rel_path
4476 class Sequence(Obj):
4477 """``SEQUENCE`` structure type
4479 You have to make specification of sequence::
4481 class Extension(Sequence):
4483 ("extnID", ObjectIdentifier()),
4484 ("critical", Boolean(default=False)),
4485 ("extnValue", OctetString()),
4488 Then, you can work with it as with dictionary.
4490 >>> ext = Extension()
4491 >>> Extension().specs
4493 ('extnID', OBJECT IDENTIFIER),
4494 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4495 ('extnValue', OCTET STRING),
4497 >>> ext["extnID"] = "1.2.3"
4498 Traceback (most recent call last):
4499 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4500 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4502 You can determine if sequence is ready to be encoded:
4507 Traceback (most recent call last):
4508 pyderasn.ObjNotReady: object is not ready: extnValue
4509 >>> ext["extnValue"] = OctetString(b"foobar")
4513 Value you want to assign, must have the same **type** as in
4514 corresponding specification, but it can have different tags,
4515 optional/default attributes -- they will be taken from specification
4518 class TBSCertificate(Sequence):
4520 ("version", Version(expl=tag_ctxc(0), default="v1")),
4523 >>> tbs = TBSCertificate()
4524 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4526 Assign ``None`` to remove value from sequence.
4528 You can set values in Sequence during its initialization:
4530 >>> AlgorithmIdentifier((
4531 ("algorithm", ObjectIdentifier("1.2.3")),
4532 ("parameters", Any(Null()))
4534 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4536 You can determine if value exists/set in the sequence and take its value:
4538 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4541 OBJECT IDENTIFIER 1.2.3
4543 But pay attention that if value has default, then it won't be (not
4544 in) in the sequence (because ``DEFAULT`` must not be encoded in
4545 DER), but you can read its value:
4547 >>> "critical" in ext, ext["critical"]
4548 (False, BOOLEAN False)
4549 >>> ext["critical"] = Boolean(True)
4550 >>> "critical" in ext, ext["critical"]
4551 (True, BOOLEAN True)
4553 All defaulted values are always optional.
4555 .. _allow_default_values_ctx:
4557 DER prohibits default value encoding and will raise an error if
4558 default value is unexpectedly met during decode.
4559 If :ref:`bered <bered_ctx>` context option is set, then no error
4560 will be raised, but ``bered`` attribute set. You can disable strict
4561 defaulted values existence validation by setting
4562 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4564 Two sequences are equal if they have equal specification (schema),
4565 implicit/explicit tagging and the same values.
4567 __slots__ = ("specs",)
4568 tag_default = tag_encode(form=TagFormConstructed, num=16)
4569 asn1_type_name = "SEQUENCE"
4581 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4583 schema = getattr(self, "schema", ())
4585 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4588 if value is not None:
4589 if issubclass(value.__class__, Sequence):
4590 self._value = value._value
4591 elif hasattr(value, "__iter__"):
4592 for seq_key, seq_value in value:
4593 self[seq_key] = seq_value
4595 raise InvalidValueType((Sequence,))
4596 if default is not None:
4597 if not issubclass(default.__class__, Sequence):
4598 raise InvalidValueType((Sequence,))
4599 default_value = default._value
4600 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4601 default_obj.specs = self.specs
4602 default_obj._value = default_value
4603 self.default = default_obj
4605 self._value = default_obj.copy()._value
4609 for name, spec in iteritems(self.specs):
4610 value = self._value.get(name)
4622 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4624 return any(value.bered for value in itervalues(self._value))
4627 obj = self.__class__(schema=self.specs)
4629 obj._expl = self._expl
4630 obj.default = self.default
4631 obj.optional = self.optional
4632 obj.offset = self.offset
4633 obj.llen = self.llen
4634 obj.vlen = self.vlen
4635 obj.expl_lenindef = self.expl_lenindef
4636 obj.lenindef = self.lenindef
4637 obj.ber_encoded = self.ber_encoded
4638 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4641 def __eq__(self, their):
4642 if not isinstance(their, self.__class__):
4645 self.specs == their.specs and
4646 self.tag == their.tag and
4647 self._expl == their._expl and
4648 self._value == their._value
4659 return self.__class__(
4662 impl=self.tag if impl is None else impl,
4663 expl=self._expl if expl is None else expl,
4664 default=self.default if default is None else default,
4665 optional=self.optional if optional is None else optional,
4668 def __contains__(self, key):
4669 return key in self._value
4671 def __setitem__(self, key, value):
4672 spec = self.specs.get(key)
4674 raise ObjUnknown(key)
4676 self._value.pop(key, None)
4678 if not isinstance(value, spec.__class__):
4679 raise InvalidValueType((spec.__class__,))
4680 value = spec(value=value)
4681 if spec.default is not None and value == spec.default:
4682 self._value.pop(key, None)
4684 self._value[key] = value
4686 def __getitem__(self, key):
4687 value = self._value.get(key)
4688 if value is not None:
4690 spec = self.specs.get(key)
4692 raise ObjUnknown(key)
4693 if spec.default is not None:
4697 def _encoded_values(self):
4699 for name, spec in iteritems(self.specs):
4700 value = self._value.get(name)
4704 raise ObjNotReady(name)
4705 raws.append(value.encode())
4709 v = b"".join(self._encoded_values())
4710 return b"".join((self.tag, len_encode(len(v)), v))
4712 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4714 t, tlen, lv = tag_strip(tlv)
4715 except DecodeError as err:
4716 raise err.__class__(
4718 klass=self.__class__,
4719 decode_path=decode_path,
4724 klass=self.__class__,
4725 decode_path=decode_path,
4728 if tag_only: # pragma: no cover
4731 ctx_bered = ctx.get("bered", False)
4733 l, llen, v = len_decode(lv)
4734 except LenIndefForm as err:
4736 raise err.__class__(
4738 klass=self.__class__,
4739 decode_path=decode_path,
4742 l, llen, v = 0, 1, lv[1:]
4744 except DecodeError as err:
4745 raise err.__class__(
4747 klass=self.__class__,
4748 decode_path=decode_path,
4752 raise NotEnoughData(
4753 "encoded length is longer than data",
4754 klass=self.__class__,
4755 decode_path=decode_path,
4759 v, tail = v[:l], v[l:]
4761 sub_offset = offset + tlen + llen
4764 ctx_allow_default_values = ctx.get("allow_default_values", False)
4765 for name, spec in iteritems(self.specs):
4766 if spec.optional and (
4767 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4771 sub_decode_path = decode_path + (name,)
4773 value, v_tail = spec.decode(
4777 decode_path=sub_decode_path,
4779 _ctx_immutable=False,
4786 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4787 if defined is not None:
4788 defined_by, defined_spec = defined
4789 if issubclass(value.__class__, SequenceOf):
4790 for i, _value in enumerate(value):
4791 sub_sub_decode_path = sub_decode_path + (
4793 DecodePathDefBy(defined_by),
4795 defined_value, defined_tail = defined_spec.decode(
4796 memoryview(bytes(_value)),
4798 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4799 if value.expled else (value.tlen + value.llen)
4802 decode_path=sub_sub_decode_path,
4804 _ctx_immutable=False,
4806 if len(defined_tail) > 0:
4809 klass=self.__class__,
4810 decode_path=sub_sub_decode_path,
4813 _value.defined = (defined_by, defined_value)
4815 defined_value, defined_tail = defined_spec.decode(
4816 memoryview(bytes(value)),
4818 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4819 if value.expled else (value.tlen + value.llen)
4822 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4824 _ctx_immutable=False,
4826 if len(defined_tail) > 0:
4829 klass=self.__class__,
4830 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4833 value.defined = (defined_by, defined_value)
4835 value_len = value.fulllen
4837 sub_offset += value_len
4839 if spec.default is not None and value == spec.default:
4840 if ctx_bered or ctx_allow_default_values:
4844 "DEFAULT value met",
4845 klass=self.__class__,
4846 decode_path=sub_decode_path,
4849 values[name] = value
4851 spec_defines = getattr(spec, "defines", ())
4852 if len(spec_defines) == 0:
4853 defines_by_path = ctx.get("defines_by_path", ())
4854 if len(defines_by_path) > 0:
4855 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4856 if spec_defines is not None and len(spec_defines) > 0:
4857 for rel_path, schema in spec_defines:
4858 defined = schema.get(value, None)
4859 if defined is not None:
4860 ctx.setdefault("_defines", []).append((
4861 abs_decode_path(sub_decode_path[:-1], rel_path),
4865 if v[:EOC_LEN].tobytes() != EOC:
4868 klass=self.__class__,
4869 decode_path=decode_path,
4877 klass=self.__class__,
4878 decode_path=decode_path,
4881 obj = self.__class__(
4885 default=self.default,
4886 optional=self.optional,
4887 _decoded=(offset, llen, vlen),
4890 obj.lenindef = lenindef
4891 obj.ber_encoded = ber_encoded
4895 value = pp_console_row(next(self.pps()))
4897 for name in self.specs:
4898 _value = self._value.get(name)
4901 cols.append("%s: %s" % (name, repr(_value)))
4902 return "%s[%s]" % (value, "; ".join(cols))
4904 def pps(self, decode_path=()):
4907 asn1_type_name=self.asn1_type_name,
4908 obj_name=self.__class__.__name__,
4909 decode_path=decode_path,
4910 optional=self.optional,
4911 default=self == self.default,
4912 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4913 expl=None if self._expl is None else tag_decode(self._expl),
4918 expl_offset=self.expl_offset if self.expled else None,
4919 expl_tlen=self.expl_tlen if self.expled else None,
4920 expl_llen=self.expl_llen if self.expled else None,
4921 expl_vlen=self.expl_vlen if self.expled else None,
4922 expl_lenindef=self.expl_lenindef,
4923 lenindef=self.lenindef,
4924 ber_encoded=self.ber_encoded,
4927 for name in self.specs:
4928 value = self._value.get(name)
4931 yield value.pps(decode_path=decode_path + (name,))
4932 for pp in self.pps_lenindef(decode_path):
4936 class Set(Sequence):
4937 """``SET`` structure type
4939 Its usage is identical to :py:class:`pyderasn.Sequence`.
4941 .. _allow_unordered_set_ctx:
4943 DER prohibits unordered values encoding and will raise an error
4944 during decode. If If :ref:`bered <bered_ctx>` context option is set,
4945 then no error will occure. Also you can disable strict values
4946 ordering check by setting ``"allow_unordered_set": True``
4947 :ref:`context <ctx>` option.
4950 tag_default = tag_encode(form=TagFormConstructed, num=17)
4951 asn1_type_name = "SET"
4954 raws = self._encoded_values()
4957 return b"".join((self.tag, len_encode(len(v)), v))
4959 def _specs_items(self):
4960 return iteritems(self.specs)
4962 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4964 t, tlen, lv = tag_strip(tlv)
4965 except DecodeError as err:
4966 raise err.__class__(
4968 klass=self.__class__,
4969 decode_path=decode_path,
4974 klass=self.__class__,
4975 decode_path=decode_path,
4981 ctx_bered = ctx.get("bered", False)
4983 l, llen, v = len_decode(lv)
4984 except LenIndefForm as err:
4986 raise err.__class__(
4988 klass=self.__class__,
4989 decode_path=decode_path,
4992 l, llen, v = 0, 1, lv[1:]
4994 except DecodeError as err:
4995 raise err.__class__(
4997 klass=self.__class__,
4998 decode_path=decode_path,
5002 raise NotEnoughData(
5003 "encoded length is longer than data",
5004 klass=self.__class__,
5008 v, tail = v[:l], v[l:]
5010 sub_offset = offset + tlen + llen
5013 ctx_allow_default_values = ctx.get("allow_default_values", False)
5014 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5015 value_prev = memoryview(v[:0])
5018 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5020 for name, spec in self._specs_items():
5021 sub_decode_path = decode_path + (name,)
5027 decode_path=sub_decode_path,
5030 _ctx_immutable=False,
5037 klass=self.__class__,
5038 decode_path=decode_path,
5041 value, v_tail = spec.decode(
5045 decode_path=sub_decode_path,
5047 _ctx_immutable=False,
5049 value_len = value.fulllen
5050 if value_prev.tobytes() > v[:value_len].tobytes():
5051 if ctx_bered or ctx_allow_unordered_set:
5055 "unordered " + self.asn1_type_name,
5056 klass=self.__class__,
5057 decode_path=sub_decode_path,
5060 if spec.default is None or value != spec.default:
5062 elif ctx_bered or ctx_allow_default_values:
5066 "DEFAULT value met",
5067 klass=self.__class__,
5068 decode_path=sub_decode_path,
5071 values[name] = value
5072 value_prev = v[:value_len]
5073 sub_offset += value_len
5076 obj = self.__class__(
5080 default=self.default,
5081 optional=self.optional,
5082 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5085 if v[:EOC_LEN].tobytes() != EOC:
5088 klass=self.__class__,
5089 decode_path=decode_path,
5097 "not all values are ready",
5098 klass=self.__class__,
5099 decode_path=decode_path,
5102 obj.ber_encoded = ber_encoded
5106 class SequenceOf(Obj):
5107 """``SEQUENCE OF`` sequence type
5109 For that kind of type you must specify the object it will carry on
5110 (bounds are for example here, not required)::
5112 class Ints(SequenceOf):
5117 >>> ints.append(Integer(123))
5118 >>> ints.append(Integer(234))
5120 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5121 >>> [int(i) for i in ints]
5123 >>> ints.append(Integer(345))
5124 Traceback (most recent call last):
5125 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5128 >>> ints[1] = Integer(345)
5130 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5132 Also you can initialize sequence with preinitialized values:
5134 >>> ints = Ints([Integer(123), Integer(234)])
5136 __slots__ = ("spec", "_bound_min", "_bound_max")
5137 tag_default = tag_encode(form=TagFormConstructed, num=16)
5138 asn1_type_name = "SEQUENCE OF"
5151 super(SequenceOf, self).__init__(
5159 schema = getattr(self, "schema", None)
5161 raise ValueError("schema must be specified")
5163 self._bound_min, self._bound_max = getattr(
5167 ) if bounds is None else bounds
5169 if value is not None:
5170 self._value = self._value_sanitize(value)
5171 if default is not None:
5172 default_value = self._value_sanitize(default)
5173 default_obj = self.__class__(
5178 default_obj._value = default_value
5179 self.default = default_obj
5181 self._value = default_obj.copy()._value
5183 def _value_sanitize(self, value):
5184 if issubclass(value.__class__, SequenceOf):
5185 value = value._value
5186 elif hasattr(value, "__iter__"):
5189 raise InvalidValueType((self.__class__, iter))
5190 if not self._bound_min <= len(value) <= self._bound_max:
5191 raise BoundsError(self._bound_min, len(value), self._bound_max)
5193 if not isinstance(v, self.spec.__class__):
5194 raise InvalidValueType((self.spec.__class__,))
5199 return all(v.ready for v in self._value)
5203 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5205 return any(v.bered for v in self._value)
5208 obj = self.__class__(schema=self.spec)
5209 obj._bound_min = self._bound_min
5210 obj._bound_max = self._bound_max
5212 obj._expl = self._expl
5213 obj.default = self.default
5214 obj.optional = self.optional
5215 obj.offset = self.offset
5216 obj.llen = self.llen
5217 obj.vlen = self.vlen
5218 obj.expl_lenindef = self.expl_lenindef
5219 obj.lenindef = self.lenindef
5220 obj.ber_encoded = self.ber_encoded
5221 obj._value = [v.copy() for v in self._value]
5224 def __eq__(self, their):
5225 if isinstance(their, self.__class__):
5227 self.spec == their.spec and
5228 self.tag == their.tag and
5229 self._expl == their._expl and
5230 self._value == their._value
5232 if hasattr(their, "__iter__"):
5233 return self._value == list(their)
5245 return self.__class__(
5249 (self._bound_min, self._bound_max)
5250 if bounds is None else bounds
5252 impl=self.tag if impl is None else impl,
5253 expl=self._expl if expl is None else expl,
5254 default=self.default if default is None else default,
5255 optional=self.optional if optional is None else optional,
5258 def __contains__(self, key):
5259 return key in self._value
5261 def append(self, value):
5262 if not isinstance(value, self.spec.__class__):
5263 raise InvalidValueType((self.spec.__class__,))
5264 if len(self._value) + 1 > self._bound_max:
5267 len(self._value) + 1,
5270 self._value.append(value)
5273 self._assert_ready()
5274 return iter(self._value)
5277 self._assert_ready()
5278 return len(self._value)
5280 def __setitem__(self, key, value):
5281 if not isinstance(value, self.spec.__class__):
5282 raise InvalidValueType((self.spec.__class__,))
5283 self._value[key] = self.spec(value=value)
5285 def __getitem__(self, key):
5286 return self._value[key]
5288 def _encoded_values(self):
5289 return [v.encode() for v in self._value]
5292 v = b"".join(self._encoded_values())
5293 return b"".join((self.tag, len_encode(len(v)), v))
5295 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5297 t, tlen, lv = tag_strip(tlv)
5298 except DecodeError as err:
5299 raise err.__class__(
5301 klass=self.__class__,
5302 decode_path=decode_path,
5307 klass=self.__class__,
5308 decode_path=decode_path,
5314 ctx_bered = ctx.get("bered", False)
5316 l, llen, v = len_decode(lv)
5317 except LenIndefForm as err:
5319 raise err.__class__(
5321 klass=self.__class__,
5322 decode_path=decode_path,
5325 l, llen, v = 0, 1, lv[1:]
5327 except DecodeError as err:
5328 raise err.__class__(
5330 klass=self.__class__,
5331 decode_path=decode_path,
5335 raise NotEnoughData(
5336 "encoded length is longer than data",
5337 klass=self.__class__,
5338 decode_path=decode_path,
5342 v, tail = v[:l], v[l:]
5344 sub_offset = offset + tlen + llen
5346 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5347 value_prev = memoryview(v[:0])
5351 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5353 sub_decode_path = decode_path + (str(len(_value)),)
5354 value, v_tail = spec.decode(
5358 decode_path=sub_decode_path,
5360 _ctx_immutable=False,
5362 value_len = value.fulllen
5364 if value_prev.tobytes() > v[:value_len].tobytes():
5365 if ctx_bered or ctx_allow_unordered_set:
5369 "unordered " + self.asn1_type_name,
5370 klass=self.__class__,
5371 decode_path=sub_decode_path,
5374 value_prev = v[:value_len]
5375 _value.append(value)
5376 sub_offset += value_len
5380 obj = self.__class__(
5383 bounds=(self._bound_min, self._bound_max),
5386 default=self.default,
5387 optional=self.optional,
5388 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5390 except BoundsError as err:
5393 klass=self.__class__,
5394 decode_path=decode_path,
5398 if v[:EOC_LEN].tobytes() != EOC:
5401 klass=self.__class__,
5402 decode_path=decode_path,
5407 obj.ber_encoded = ber_encoded
5412 pp_console_row(next(self.pps())),
5413 ", ".join(repr(v) for v in self._value),
5416 def pps(self, decode_path=()):
5419 asn1_type_name=self.asn1_type_name,
5420 obj_name=self.__class__.__name__,
5421 decode_path=decode_path,
5422 optional=self.optional,
5423 default=self == self.default,
5424 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5425 expl=None if self._expl is None else tag_decode(self._expl),
5430 expl_offset=self.expl_offset if self.expled else None,
5431 expl_tlen=self.expl_tlen if self.expled else None,
5432 expl_llen=self.expl_llen if self.expled else None,
5433 expl_vlen=self.expl_vlen if self.expled else None,
5434 expl_lenindef=self.expl_lenindef,
5435 lenindef=self.lenindef,
5436 ber_encoded=self.ber_encoded,
5439 for i, value in enumerate(self._value):
5440 yield value.pps(decode_path=decode_path + (str(i),))
5441 for pp in self.pps_lenindef(decode_path):
5445 class SetOf(SequenceOf):
5446 """``SET OF`` sequence type
5448 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5451 tag_default = tag_encode(form=TagFormConstructed, num=17)
5452 asn1_type_name = "SET OF"
5455 raws = self._encoded_values()
5458 return b"".join((self.tag, len_encode(len(v)), v))
5460 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5461 return super(SetOf, self)._decode(
5467 ordering_check=True,
5471 def obj_by_path(pypath): # pragma: no cover
5472 """Import object specified as string Python path
5474 Modules must be separated from classes/functions with ``:``.
5476 >>> obj_by_path("foo.bar:Baz")
5477 <class 'foo.bar.Baz'>
5478 >>> obj_by_path("foo.bar:Baz.boo")
5479 <classmethod 'foo.bar.Baz.boo'>
5481 mod, objs = pypath.rsplit(":", 1)
5482 from importlib import import_module
5483 obj = import_module(mod)
5484 for obj_name in objs.split("."):
5485 obj = getattr(obj, obj_name)
5489 def generic_decoder(): # pragma: no cover
5490 # All of this below is a big hack with self references
5491 choice = PrimitiveTypes()
5492 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5493 choice.specs["SetOf"] = SetOf(schema=choice)
5494 for i in six_xrange(31):
5495 choice.specs["SequenceOf%d" % i] = SequenceOf(
5499 choice.specs["Any"] = Any()
5501 # Class name equals to type name, to omit it from output
5502 class SEQUENCEOF(SequenceOf):
5510 with_decode_path=False,
5511 decode_path_only=(),
5513 def _pprint_pps(pps):
5515 if hasattr(pp, "_fields"):
5517 decode_path_only != () and
5518 pp.decode_path[:len(decode_path_only)] != decode_path_only
5521 if pp.asn1_type_name == Choice.asn1_type_name:
5523 pp_kwargs = pp._asdict()
5524 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5525 pp = _pp(**pp_kwargs)
5526 yield pp_console_row(
5531 with_colours=with_colours,
5532 with_decode_path=with_decode_path,
5533 decode_path_len_decrease=len(decode_path_only),
5535 for row in pp_console_blob(
5537 decode_path_len_decrease=len(decode_path_only),
5541 for row in _pprint_pps(pp):
5543 return "\n".join(_pprint_pps(obj.pps()))
5544 return SEQUENCEOF(), pprint_any
5547 def main(): # pragma: no cover
5549 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5550 parser.add_argument(
5554 help="Skip that number of bytes from the beginning",
5556 parser.add_argument(
5558 help="Python path to dictionary with OIDs",
5560 parser.add_argument(
5562 help="Python path to schema definition to use",
5564 parser.add_argument(
5565 "--defines-by-path",
5566 help="Python path to decoder's defines_by_path",
5568 parser.add_argument(
5570 action="store_true",
5571 help="Disallow BER encoding",
5573 parser.add_argument(
5574 "--print-decode-path",
5575 action="store_true",
5576 help="Print decode paths",
5578 parser.add_argument(
5579 "--decode-path-only",
5580 help="Print only specified decode path",
5582 parser.add_argument(
5584 action="store_true",
5585 help="Allow explicit tag out-of-bound",
5587 parser.add_argument(
5589 type=argparse.FileType("rb"),
5590 help="Path to DER file you want to decode",
5592 args = parser.parse_args()
5593 args.DERFile.seek(args.skip)
5594 der = memoryview(args.DERFile.read())
5595 args.DERFile.close()
5596 oids = obj_by_path(args.oids) if args.oids else {}
5598 schema = obj_by_path(args.schema)
5599 from functools import partial
5600 pprinter = partial(pprint, big_blobs=True)
5602 schema, pprinter = generic_decoder()
5604 "bered": not args.nobered,
5605 "allow_expl_oob": args.allow_expl_oob,
5607 if args.defines_by_path is not None:
5608 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5609 obj, tail = schema().decode(der, ctx=ctx)
5613 with_colours=True if environ.get("NO_COLOR") is None else False,
5614 with_decode_path=args.print_decode_path,
5616 () if args.decode_path_only is None else
5617 tuple(args.decode_path_only.split(":"))
5621 print("\nTrailing data: %s" % hexenc(tail))
5624 if __name__ == "__main__":