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.UTCTime
469 :members: __init__, todatetime
473 .. autoclass:: pyderasn.GeneralizedTime
480 .. autoclass:: pyderasn.Choice
485 .. autoclass:: PrimitiveTypes
489 .. autoclass:: pyderasn.Any
497 .. autoclass:: pyderasn.Sequence
502 .. autoclass:: pyderasn.Set
507 .. autoclass:: pyderasn.SequenceOf
512 .. autoclass:: pyderasn.SetOf
518 .. autofunction:: pyderasn.abs_decode_path
519 .. autofunction:: pyderasn.colonize_hex
520 .. autofunction:: pyderasn.hexenc
521 .. autofunction:: pyderasn.hexdec
522 .. autofunction:: pyderasn.tag_encode
523 .. autofunction:: pyderasn.tag_decode
524 .. autofunction:: pyderasn.tag_ctxp
525 .. autofunction:: pyderasn.tag_ctxc
526 .. autoclass:: pyderasn.Obj
527 .. autoclass:: pyderasn.DecodeError
529 .. autoclass:: pyderasn.NotEnoughData
530 .. autoclass:: pyderasn.LenIndefForm
531 .. autoclass:: pyderasn.TagMismatch
532 .. autoclass:: pyderasn.InvalidLength
533 .. autoclass:: pyderasn.InvalidOID
534 .. autoclass:: pyderasn.ObjUnknown
535 .. autoclass:: pyderasn.ObjNotReady
536 .. autoclass:: pyderasn.InvalidValueType
537 .. autoclass:: pyderasn.BoundsError
540 from codecs import getdecoder
541 from codecs import getencoder
542 from collections import namedtuple
543 from collections import OrderedDict
544 from copy import copy
545 from datetime import datetime
546 from math import ceil
547 from os import environ
548 from string import ascii_letters
549 from string import digits
551 from six import add_metaclass
552 from six import binary_type
553 from six import byte2int
554 from six import indexbytes
555 from six import int2byte
556 from six import integer_types
557 from six import iterbytes
558 from six import iteritems
559 from six import itervalues
561 from six import string_types
562 from six import text_type
563 from six import unichr as six_unichr
564 from six.moves import xrange as six_xrange
568 from termcolor import colored
569 except ImportError: # pragma: no cover
570 def colored(what, *args):
614 "TagClassApplication",
618 "TagFormConstructed",
629 TagClassUniversal = 0
630 TagClassApplication = 1 << 6
631 TagClassContext = 1 << 7
632 TagClassPrivate = 1 << 6 | 1 << 7
634 TagFormConstructed = 1 << 5
637 TagClassApplication: "APPLICATION ",
638 TagClassPrivate: "PRIVATE ",
639 TagClassUniversal: "UNIV ",
643 LENINDEF = b"\x80" # length indefinite mark
644 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
647 ########################################################################
649 ########################################################################
651 class ASN1Error(ValueError):
655 class DecodeError(ASN1Error):
656 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
658 :param str msg: reason of decode failing
659 :param klass: optional exact DecodeError inherited class (like
660 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
661 :py:exc:`InvalidLength`)
662 :param decode_path: tuple of strings. It contains human
663 readable names of the fields through which
664 decoding process has passed
665 :param int offset: binary offset where failure happened
667 super(DecodeError, self).__init__()
670 self.decode_path = decode_path
676 "" if self.klass is None else self.klass.__name__,
678 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
679 if len(self.decode_path) > 0 else ""
681 ("(at %d)" % self.offset) if self.offset > 0 else "",
687 return "%s(%s)" % (self.__class__.__name__, self)
690 class NotEnoughData(DecodeError):
694 class LenIndefForm(DecodeError):
698 class TagMismatch(DecodeError):
702 class InvalidLength(DecodeError):
706 class InvalidOID(DecodeError):
710 class ObjUnknown(ASN1Error):
711 def __init__(self, name):
712 super(ObjUnknown, self).__init__()
716 return "object is unknown: %s" % self.name
719 return "%s(%s)" % (self.__class__.__name__, self)
722 class ObjNotReady(ASN1Error):
723 def __init__(self, name):
724 super(ObjNotReady, self).__init__()
728 return "object is not ready: %s" % self.name
731 return "%s(%s)" % (self.__class__.__name__, self)
734 class InvalidValueType(ASN1Error):
735 def __init__(self, expected_types):
736 super(InvalidValueType, self).__init__()
737 self.expected_types = expected_types
740 return "invalid value type, expected: %s" % ", ".join(
741 [repr(t) for t in self.expected_types]
745 return "%s(%s)" % (self.__class__.__name__, self)
748 class BoundsError(ASN1Error):
749 def __init__(self, bound_min, value, bound_max):
750 super(BoundsError, self).__init__()
751 self.bound_min = bound_min
753 self.bound_max = bound_max
756 return "unsatisfied bounds: %s <= %s <= %s" % (
763 return "%s(%s)" % (self.__class__.__name__, self)
766 ########################################################################
768 ########################################################################
770 _hexdecoder = getdecoder("hex")
771 _hexencoder = getencoder("hex")
775 """Binary data to hexadecimal string convert
777 return _hexdecoder(data)[0]
781 """Hexadecimal string to binary data convert
783 return _hexencoder(data)[0].decode("ascii")
786 def int_bytes_len(num, byte_len=8):
789 return int(ceil(float(num.bit_length()) / byte_len))
792 def zero_ended_encode(num):
793 octets = bytearray(int_bytes_len(num, 7))
795 octets[i] = num & 0x7F
799 octets[i] = 0x80 | (num & 0x7F)
805 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
806 """Encode tag to binary form
808 :param int num: tag's number
809 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
810 :py:data:`pyderasn.TagClassContext`,
811 :py:data:`pyderasn.TagClassApplication`,
812 :py:data:`pyderasn.TagClassPrivate`)
813 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
814 :py:data:`pyderasn.TagFormConstructed`)
818 return int2byte(klass | form | num)
819 # [XX|X|11111][1.......][1.......] ... [0.......]
820 return int2byte(klass | form | 31) + zero_ended_encode(num)
824 """Decode tag from binary form
828 No validation is performed, assuming that it has already passed.
830 It returns tuple with three integers, as
831 :py:func:`pyderasn.tag_encode` accepts.
833 first_octet = byte2int(tag)
834 klass = first_octet & 0xC0
835 form = first_octet & 0x20
836 if first_octet & 0x1F < 0x1F:
837 return (klass, form, first_octet & 0x1F)
839 for octet in iterbytes(tag[1:]):
842 return (klass, form, num)
846 """Create CONTEXT PRIMITIVE tag
848 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
852 """Create CONTEXT CONSTRUCTED tag
854 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
858 """Take off tag from the data
860 :returns: (encoded tag, tag length, remaining data)
863 raise NotEnoughData("no data at all")
864 if byte2int(data) & 0x1F < 31:
865 return data[:1], 1, data[1:]
870 raise DecodeError("unfinished tag")
871 if indexbytes(data, i) & 0x80 == 0:
874 return data[:i], i, data[i:]
880 octets = bytearray(int_bytes_len(l) + 1)
881 octets[0] = 0x80 | (len(octets) - 1)
882 for i in six_xrange(len(octets) - 1, 0, -1):
888 def len_decode(data):
891 :returns: (decoded length, length's length, remaining data)
892 :raises LenIndefForm: if indefinite form encoding is met
895 raise NotEnoughData("no data at all")
896 first_octet = byte2int(data)
897 if first_octet & 0x80 == 0:
898 return first_octet, 1, data[1:]
899 octets_num = first_octet & 0x7F
900 if octets_num + 1 > len(data):
901 raise NotEnoughData("encoded length is longer than data")
904 if byte2int(data[1:]) == 0:
905 raise DecodeError("leading zeros")
907 for v in iterbytes(data[1:1 + octets_num]):
910 raise DecodeError("long form instead of short one")
911 return l, 1 + octets_num, data[1 + octets_num:]
914 ########################################################################
916 ########################################################################
918 class AutoAddSlots(type):
919 def __new__(mcs, name, bases, _dict):
920 _dict["__slots__"] = _dict.get("__slots__", ())
921 return type.__new__(mcs, name, bases, _dict)
924 @add_metaclass(AutoAddSlots)
926 """Common ASN.1 object class
928 All ASN.1 types are inherited from it. It has metaclass that
929 automatically adds ``__slots__`` to all inherited classes.
953 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
954 self._expl = getattr(self, "expl", None) if expl is None else expl
955 if self.tag != self.tag_default and self._expl is not None:
956 raise ValueError("implicit and explicit tags can not be set simultaneously")
957 if default is not None:
959 self.optional = optional
960 self.offset, self.llen, self.vlen = _decoded
962 self.expl_lenindef = False
963 self.lenindef = False
964 self.ber_encoded = False
967 def ready(self): # pragma: no cover
968 """Is object ready to be encoded?
970 raise NotImplementedError()
972 def _assert_ready(self):
974 raise ObjNotReady(self.__class__.__name__)
978 """Is either object or any elements inside is BER encoded?
980 return self.expl_lenindef or self.lenindef or self.ber_encoded
984 """Is object decoded?
986 return (self.llen + self.vlen) > 0
988 def copy(self): # pragma: no cover
989 """Make a copy of object, safe to be mutated
991 raise NotImplementedError()
999 return self.tlen + self.llen + self.vlen
1001 def __str__(self): # pragma: no cover
1002 return self.__bytes__() if PY2 else self.__unicode__()
1004 def __ne__(self, their):
1005 return not(self == their)
1007 def __gt__(self, their): # pragma: no cover
1008 return not(self < their)
1010 def __le__(self, their): # pragma: no cover
1011 return (self == their) or (self < their)
1013 def __ge__(self, their): # pragma: no cover
1014 return (self == their) or (self > their)
1016 def _encode(self): # pragma: no cover
1017 raise NotImplementedError()
1019 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1020 raise NotImplementedError()
1023 raw = self._encode()
1024 if self._expl is None:
1026 return b"".join((self._expl, len_encode(len(raw)), raw))
1036 _ctx_immutable=True,
1040 :param data: either binary or memoryview
1041 :param int offset: initial data's offset
1042 :param bool leavemm: do we need to leave memoryview of remaining
1043 data as is, or convert it to bytes otherwise
1044 :param ctx: optional :ref:`context <ctx>` governing decoding process
1045 :param tag_only: decode only the tag, without length and contents
1046 (used only in Choice and Set structures, trying to
1047 determine if tag satisfies the scheme)
1048 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1049 :returns: (Obj, remaining data)
1053 elif _ctx_immutable:
1055 tlv = memoryview(data)
1056 if self._expl is None:
1057 result = self._decode(
1060 decode_path=decode_path,
1069 t, tlen, lv = tag_strip(tlv)
1070 except DecodeError as err:
1071 raise err.__class__(
1073 klass=self.__class__,
1074 decode_path=decode_path,
1079 klass=self.__class__,
1080 decode_path=decode_path,
1084 l, llen, v = len_decode(lv)
1085 except LenIndefForm as err:
1086 if not ctx.get("bered", False):
1087 raise err.__class__(
1089 klass=self.__class__,
1090 decode_path=decode_path,
1094 offset += tlen + llen
1095 result = self._decode(
1098 decode_path=decode_path,
1102 if tag_only: # pragma: no cover
1105 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1106 if eoc_expected.tobytes() != EOC:
1109 klass=self.__class__,
1110 decode_path=decode_path,
1114 obj.expl_lenindef = True
1115 except DecodeError as err:
1116 raise err.__class__(
1118 klass=self.__class__,
1119 decode_path=decode_path,
1124 raise NotEnoughData(
1125 "encoded length is longer than data",
1126 klass=self.__class__,
1127 decode_path=decode_path,
1130 result = self._decode(
1132 offset=offset + tlen + llen,
1133 decode_path=decode_path,
1137 if tag_only: # pragma: no cover
1140 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1142 "explicit tag out-of-bound, longer than data",
1143 klass=self.__class__,
1144 decode_path=decode_path,
1147 return obj, (tail if leavemm else tail.tobytes())
1151 return self._expl is not None
1158 def expl_tlen(self):
1159 return len(self._expl)
1162 def expl_llen(self):
1163 if self.expl_lenindef:
1165 return len(len_encode(self.tlvlen))
1168 def expl_offset(self):
1169 return self.offset - self.expl_tlen - self.expl_llen
1172 def expl_vlen(self):
1176 def expl_tlvlen(self):
1177 return self.expl_tlen + self.expl_llen + self.expl_vlen
1180 def fulloffset(self):
1181 return self.expl_offset if self.expled else self.offset
1185 return self.expl_tlvlen if self.expled else self.tlvlen
1187 def pps_lenindef(self, decode_path):
1188 if self.lenindef and not (
1189 getattr(self, "defined", None) is not None and
1190 self.defined[1].lenindef
1193 asn1_type_name="EOC",
1195 decode_path=decode_path,
1197 self.offset + self.tlvlen -
1198 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1206 if self.expl_lenindef:
1208 asn1_type_name="EOC",
1209 obj_name="EXPLICIT",
1210 decode_path=decode_path,
1211 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1220 class DecodePathDefBy(object):
1221 """DEFINED BY representation inside decode path
1223 __slots__ = ("defined_by",)
1225 def __init__(self, defined_by):
1226 self.defined_by = defined_by
1228 def __ne__(self, their):
1229 return not(self == their)
1231 def __eq__(self, their):
1232 if not isinstance(their, self.__class__):
1234 return self.defined_by == their.defined_by
1237 return "DEFINED BY " + str(self.defined_by)
1240 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1243 ########################################################################
1245 ########################################################################
1247 PP = namedtuple("PP", (
1275 asn1_type_name="unknown",
1292 expl_lenindef=False,
1323 def _colourize(what, colour, with_colours, attrs=("bold",)):
1324 return colored(what, colour, attrs=attrs) if with_colours else what
1327 def colonize_hex(hexed):
1328 """Separate hexadecimal string with colons
1330 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1339 with_decode_path=False,
1340 decode_path_len_decrease=0,
1347 " " if pp.expl_offset is None else
1348 ("-%d" % (pp.offset - pp.expl_offset))
1350 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1352 col = _colourize(col, "red", with_colours, ())
1353 col += _colourize("B", "red", with_colours) if pp.bered else " "
1355 col = "[%d,%d,%4d]%s" % (
1359 LENINDEF_PP_CHAR if pp.lenindef else " "
1361 col = _colourize(col, "green", with_colours, ())
1363 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1364 if decode_path_len > 0:
1365 cols.append(" ." * decode_path_len)
1366 ent = pp.decode_path[-1]
1367 if isinstance(ent, DecodePathDefBy):
1368 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1369 value = str(ent.defined_by)
1371 oids is not None and
1372 ent.defined_by.asn1_type_name ==
1373 ObjectIdentifier.asn1_type_name and
1376 cols.append(_colourize("%s:" % oids[value], "green", with_colours))
1378 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1380 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1381 if pp.expl is not None:
1382 klass, _, num = pp.expl
1383 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1384 cols.append(_colourize(col, "blue", with_colours))
1385 if pp.impl is not None:
1386 klass, _, num = pp.impl
1387 col = "[%s%d]" % (TagClassReprs[klass], num)
1388 cols.append(_colourize(col, "blue", with_colours))
1389 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1390 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1392 cols.append(_colourize("BER", "red", with_colours))
1393 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1394 if pp.value is not None:
1396 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1398 oids is not None and
1399 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
1402 cols.append(_colourize("(%s)" % oids[value], "green", with_colours))
1403 if pp.asn1_type_name == Integer.asn1_type_name:
1404 hex_repr = hex(int(pp.obj._value))[2:].upper()
1405 if len(hex_repr) % 2 != 0:
1406 hex_repr = "0" + hex_repr
1407 cols.append(_colourize(
1408 "(%s)" % colonize_hex(hex_repr),
1413 if isinstance(pp.blob, binary_type):
1414 cols.append(hexenc(pp.blob))
1415 elif isinstance(pp.blob, tuple):
1416 cols.append(", ".join(pp.blob))
1418 cols.append(_colourize("OPTIONAL", "red", with_colours))
1420 cols.append(_colourize("DEFAULT", "red", with_colours))
1421 if with_decode_path:
1422 cols.append(_colourize(
1423 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1427 return " ".join(cols)
1430 def pp_console_blob(pp, decode_path_len_decrease=0):
1431 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1432 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1433 if decode_path_len > 0:
1434 cols.append(" ." * (decode_path_len + 1))
1435 if isinstance(pp.blob, binary_type):
1436 blob = hexenc(pp.blob).upper()
1437 for i in six_xrange(0, len(blob), 32):
1438 chunk = blob[i:i + 32]
1439 yield " ".join(cols + [colonize_hex(chunk)])
1440 elif isinstance(pp.blob, tuple):
1441 yield " ".join(cols + [", ".join(pp.blob)])
1449 with_decode_path=False,
1450 decode_path_only=(),
1452 """Pretty print object
1454 :param Obj obj: object you want to pretty print
1455 :param oids: ``OID <-> humand readable string`` dictionary. When OID
1456 from it is met, then its humand readable form is printed
1457 :param big_blobs: if large binary objects are met (like OctetString
1458 values), do we need to print them too, on separate
1460 :param with_colours: colourize output, if ``termcolor`` library
1462 :param with_decode_path: print decode path
1463 :param decode_path_only: print only that specified decode path
1465 def _pprint_pps(pps):
1467 if hasattr(pp, "_fields"):
1469 decode_path_only != () and
1471 str(p) for p in pp.decode_path[:len(decode_path_only)]
1472 ) != decode_path_only
1476 yield pp_console_row(
1481 with_colours=with_colours,
1482 with_decode_path=with_decode_path,
1483 decode_path_len_decrease=len(decode_path_only),
1485 for row in pp_console_blob(
1487 decode_path_len_decrease=len(decode_path_only),
1491 yield pp_console_row(
1496 with_colours=with_colours,
1497 with_decode_path=with_decode_path,
1498 decode_path_len_decrease=len(decode_path_only),
1501 for row in _pprint_pps(pp):
1503 return "\n".join(_pprint_pps(obj.pps()))
1506 ########################################################################
1507 # ASN.1 primitive types
1508 ########################################################################
1511 """``BOOLEAN`` boolean type
1513 >>> b = Boolean(True)
1515 >>> b == Boolean(True)
1521 tag_default = tag_encode(1)
1522 asn1_type_name = "BOOLEAN"
1534 :param value: set the value. Either boolean type, or
1535 :py:class:`pyderasn.Boolean` object
1536 :param bytes impl: override default tag with ``IMPLICIT`` one
1537 :param bytes expl: override default tag with ``EXPLICIT`` one
1538 :param default: set default value. Type same as in ``value``
1539 :param bool optional: is object ``OPTIONAL`` in sequence
1541 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1542 self._value = None if value is None else self._value_sanitize(value)
1543 if default is not None:
1544 default = self._value_sanitize(default)
1545 self.default = self.__class__(
1551 self._value = default
1553 def _value_sanitize(self, value):
1554 if isinstance(value, bool):
1556 if issubclass(value.__class__, Boolean):
1558 raise InvalidValueType((self.__class__, bool))
1562 return self._value is not None
1565 obj = self.__class__()
1566 obj._value = self._value
1568 obj._expl = self._expl
1569 obj.default = self.default
1570 obj.optional = self.optional
1571 obj.offset = self.offset
1572 obj.llen = self.llen
1573 obj.vlen = self.vlen
1574 obj.expl_lenindef = self.expl_lenindef
1575 obj.lenindef = self.lenindef
1576 obj.ber_encoded = self.ber_encoded
1579 def __nonzero__(self):
1580 self._assert_ready()
1584 self._assert_ready()
1587 def __eq__(self, their):
1588 if isinstance(their, bool):
1589 return self._value == their
1590 if not issubclass(their.__class__, Boolean):
1593 self._value == their._value and
1594 self.tag == their.tag and
1595 self._expl == their._expl
1606 return self.__class__(
1608 impl=self.tag if impl is None else impl,
1609 expl=self._expl if expl is None else expl,
1610 default=self.default if default is None else default,
1611 optional=self.optional if optional is None else optional,
1615 self._assert_ready()
1619 (b"\xFF" if self._value else b"\x00"),
1622 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1624 t, _, lv = tag_strip(tlv)
1625 except DecodeError as err:
1626 raise err.__class__(
1628 klass=self.__class__,
1629 decode_path=decode_path,
1634 klass=self.__class__,
1635 decode_path=decode_path,
1641 l, _, v = len_decode(lv)
1642 except DecodeError as err:
1643 raise err.__class__(
1645 klass=self.__class__,
1646 decode_path=decode_path,
1650 raise InvalidLength(
1651 "Boolean's length must be equal to 1",
1652 klass=self.__class__,
1653 decode_path=decode_path,
1657 raise NotEnoughData(
1658 "encoded length is longer than data",
1659 klass=self.__class__,
1660 decode_path=decode_path,
1663 first_octet = byte2int(v)
1665 if first_octet == 0:
1667 elif first_octet == 0xFF:
1669 elif ctx.get("bered", False):
1674 "unacceptable Boolean value",
1675 klass=self.__class__,
1676 decode_path=decode_path,
1679 obj = self.__class__(
1683 default=self.default,
1684 optional=self.optional,
1685 _decoded=(offset, 1, 1),
1687 obj.ber_encoded = ber_encoded
1691 return pp_console_row(next(self.pps()))
1693 def pps(self, decode_path=()):
1696 asn1_type_name=self.asn1_type_name,
1697 obj_name=self.__class__.__name__,
1698 decode_path=decode_path,
1699 value=str(self._value) if self.ready else None,
1700 optional=self.optional,
1701 default=self == self.default,
1702 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1703 expl=None if self._expl is None else tag_decode(self._expl),
1708 expl_offset=self.expl_offset if self.expled else None,
1709 expl_tlen=self.expl_tlen if self.expled else None,
1710 expl_llen=self.expl_llen if self.expled else None,
1711 expl_vlen=self.expl_vlen if self.expled else None,
1712 expl_lenindef=self.expl_lenindef,
1713 ber_encoded=self.ber_encoded,
1716 for pp in self.pps_lenindef(decode_path):
1721 """``INTEGER`` integer type
1723 >>> b = Integer(-123)
1725 >>> b == Integer(-123)
1730 >>> Integer(2, bounds=(1, 3))
1732 >>> Integer(5, bounds=(1, 3))
1733 Traceback (most recent call last):
1734 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1738 class Version(Integer):
1745 >>> v = Version("v1")
1752 {'v3': 2, 'v1': 0, 'v2': 1}
1754 __slots__ = ("specs", "_bound_min", "_bound_max")
1755 tag_default = tag_encode(2)
1756 asn1_type_name = "INTEGER"
1770 :param value: set the value. Either integer type, named value
1771 (if ``schema`` is specified in the class), or
1772 :py:class:`pyderasn.Integer` object
1773 :param bounds: set ``(MIN, MAX)`` value constraint.
1774 (-inf, +inf) by default
1775 :param bytes impl: override default tag with ``IMPLICIT`` one
1776 :param bytes expl: override default tag with ``EXPLICIT`` one
1777 :param default: set default value. Type same as in ``value``
1778 :param bool optional: is object ``OPTIONAL`` in sequence
1780 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1782 specs = getattr(self, "schema", {}) if _specs is None else _specs
1783 self.specs = specs if isinstance(specs, dict) else dict(specs)
1784 self._bound_min, self._bound_max = getattr(
1787 (float("-inf"), float("+inf")),
1788 ) if bounds is None else bounds
1789 if value is not None:
1790 self._value = self._value_sanitize(value)
1791 if default is not None:
1792 default = self._value_sanitize(default)
1793 self.default = self.__class__(
1799 if self._value is None:
1800 self._value = default
1802 def _value_sanitize(self, value):
1803 if isinstance(value, integer_types):
1805 elif issubclass(value.__class__, Integer):
1806 value = value._value
1807 elif isinstance(value, str):
1808 value = self.specs.get(value)
1810 raise ObjUnknown("integer value: %s" % value)
1812 raise InvalidValueType((self.__class__, int, str))
1813 if not self._bound_min <= value <= self._bound_max:
1814 raise BoundsError(self._bound_min, value, self._bound_max)
1819 return self._value is not None
1822 obj = self.__class__(_specs=self.specs)
1823 obj._value = self._value
1824 obj._bound_min = self._bound_min
1825 obj._bound_max = self._bound_max
1827 obj._expl = self._expl
1828 obj.default = self.default
1829 obj.optional = self.optional
1830 obj.offset = self.offset
1831 obj.llen = self.llen
1832 obj.vlen = self.vlen
1833 obj.expl_lenindef = self.expl_lenindef
1834 obj.lenindef = self.lenindef
1835 obj.ber_encoded = self.ber_encoded
1839 self._assert_ready()
1840 return int(self._value)
1843 self._assert_ready()
1846 bytes(self._expl or b"") +
1847 str(self._value).encode("ascii"),
1850 def __eq__(self, their):
1851 if isinstance(their, integer_types):
1852 return self._value == their
1853 if not issubclass(their.__class__, Integer):
1856 self._value == their._value and
1857 self.tag == their.tag and
1858 self._expl == their._expl
1861 def __lt__(self, their):
1862 return self._value < their._value
1866 for name, value in iteritems(self.specs):
1867 if value == self._value:
1879 return self.__class__(
1882 (self._bound_min, self._bound_max)
1883 if bounds is None else bounds
1885 impl=self.tag if impl is None else impl,
1886 expl=self._expl if expl is None else expl,
1887 default=self.default if default is None else default,
1888 optional=self.optional if optional is None else optional,
1893 self._assert_ready()
1897 octets = bytearray([0])
1901 octets = bytearray()
1903 octets.append((value & 0xFF) ^ 0xFF)
1905 if len(octets) == 0 or octets[-1] & 0x80 == 0:
1908 octets = bytearray()
1910 octets.append(value & 0xFF)
1912 if octets[-1] & 0x80 > 0:
1915 octets = bytes(octets)
1917 bytes_len = ceil(value.bit_length() / 8) or 1
1920 octets = value.to_bytes(
1925 except OverflowError:
1929 return b"".join((self.tag, len_encode(len(octets)), octets))
1931 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1933 t, _, lv = tag_strip(tlv)
1934 except DecodeError as err:
1935 raise err.__class__(
1937 klass=self.__class__,
1938 decode_path=decode_path,
1943 klass=self.__class__,
1944 decode_path=decode_path,
1950 l, llen, v = len_decode(lv)
1951 except DecodeError as err:
1952 raise err.__class__(
1954 klass=self.__class__,
1955 decode_path=decode_path,
1959 raise NotEnoughData(
1960 "encoded length is longer than data",
1961 klass=self.__class__,
1962 decode_path=decode_path,
1966 raise NotEnoughData(
1968 klass=self.__class__,
1969 decode_path=decode_path,
1972 v, tail = v[:l], v[l:]
1973 first_octet = byte2int(v)
1975 second_octet = byte2int(v[1:])
1977 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
1978 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
1981 "non normalized integer",
1982 klass=self.__class__,
1983 decode_path=decode_path,
1988 if first_octet & 0x80 > 0:
1989 octets = bytearray()
1990 for octet in bytearray(v):
1991 octets.append(octet ^ 0xFF)
1992 for octet in octets:
1993 value = (value << 8) | octet
1997 for octet in bytearray(v):
1998 value = (value << 8) | octet
2000 value = int.from_bytes(v, byteorder="big", signed=True)
2002 obj = self.__class__(
2004 bounds=(self._bound_min, self._bound_max),
2007 default=self.default,
2008 optional=self.optional,
2010 _decoded=(offset, llen, l),
2012 except BoundsError as err:
2015 klass=self.__class__,
2016 decode_path=decode_path,
2022 return pp_console_row(next(self.pps()))
2024 def pps(self, decode_path=()):
2027 asn1_type_name=self.asn1_type_name,
2028 obj_name=self.__class__.__name__,
2029 decode_path=decode_path,
2030 value=(self.named or str(self._value)) if self.ready else None,
2031 optional=self.optional,
2032 default=self == self.default,
2033 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2034 expl=None if self._expl is None else tag_decode(self._expl),
2039 expl_offset=self.expl_offset if self.expled else None,
2040 expl_tlen=self.expl_tlen if self.expled else None,
2041 expl_llen=self.expl_llen if self.expled else None,
2042 expl_vlen=self.expl_vlen if self.expled else None,
2043 expl_lenindef=self.expl_lenindef,
2046 for pp in self.pps_lenindef(decode_path):
2050 SET01 = frozenset(("0", "1"))
2053 class BitString(Obj):
2054 """``BIT STRING`` bit string type
2056 >>> BitString(b"hello world")
2057 BIT STRING 88 bits 68656c6c6f20776f726c64
2060 >>> b == b"hello world"
2065 >>> BitString("'0A3B5F291CD'H")
2066 BIT STRING 44 bits 0a3b5f291cd0
2067 >>> b = BitString("'010110000000'B")
2068 BIT STRING 12 bits 5800
2071 >>> b[0], b[1], b[2], b[3]
2072 (False, True, False, True)
2076 [False, True, False, True, True, False, False, False, False, False, False, False]
2080 class KeyUsage(BitString):
2082 ("digitalSignature", 0),
2083 ("nonRepudiation", 1),
2084 ("keyEncipherment", 2),
2087 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2088 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2090 ['nonRepudiation', 'keyEncipherment']
2092 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2096 Pay attention that BIT STRING can be encoded both in primitive
2097 and constructed forms. Decoder always checks constructed form tag
2098 additionally to specified primitive one. If BER decoding is
2099 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2100 of DER restrictions.
2102 __slots__ = ("tag_constructed", "specs", "defined")
2103 tag_default = tag_encode(3)
2104 asn1_type_name = "BIT STRING"
2117 :param value: set the value. Either binary type, tuple of named
2118 values (if ``schema`` is specified in the class),
2119 string in ``'XXX...'B`` form, or
2120 :py:class:`pyderasn.BitString` object
2121 :param bytes impl: override default tag with ``IMPLICIT`` one
2122 :param bytes expl: override default tag with ``EXPLICIT`` one
2123 :param default: set default value. Type same as in ``value``
2124 :param bool optional: is object ``OPTIONAL`` in sequence
2126 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2127 specs = getattr(self, "schema", {}) if _specs is None else _specs
2128 self.specs = specs if isinstance(specs, dict) else dict(specs)
2129 self._value = None if value is None else self._value_sanitize(value)
2130 if default is not None:
2131 default = self._value_sanitize(default)
2132 self.default = self.__class__(
2138 self._value = default
2140 tag_klass, _, tag_num = tag_decode(self.tag)
2141 self.tag_constructed = tag_encode(
2143 form=TagFormConstructed,
2147 def _bits2octets(self, bits):
2148 if len(self.specs) > 0:
2149 bits = bits.rstrip("0")
2151 bits += "0" * ((8 - (bit_len % 8)) % 8)
2152 octets = bytearray(len(bits) // 8)
2153 for i in six_xrange(len(octets)):
2154 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2155 return bit_len, bytes(octets)
2157 def _value_sanitize(self, value):
2158 if isinstance(value, (string_types, binary_type)):
2160 isinstance(value, string_types) and
2161 value.startswith("'")
2163 if value.endswith("'B"):
2165 if not frozenset(value) <= SET01:
2166 raise ValueError("B's coding contains unacceptable chars")
2167 return self._bits2octets(value)
2168 elif value.endswith("'H"):
2172 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2174 if isinstance(value, binary_type):
2175 return (len(value) * 8, value)
2177 raise InvalidValueType((self.__class__, string_types, binary_type))
2178 if isinstance(value, tuple):
2181 isinstance(value[0], integer_types) and
2182 isinstance(value[1], binary_type)
2187 bit = self.specs.get(name)
2189 raise ObjUnknown("BitString value: %s" % name)
2192 return self._bits2octets("")
2193 bits = frozenset(bits)
2194 return self._bits2octets("".join(
2195 ("1" if bit in bits else "0")
2196 for bit in six_xrange(max(bits) + 1)
2198 if issubclass(value.__class__, BitString):
2200 raise InvalidValueType((self.__class__, binary_type, string_types))
2204 return self._value is not None
2207 obj = self.__class__(_specs=self.specs)
2209 if value is not None:
2210 value = (value[0], value[1])
2213 obj._expl = self._expl
2214 obj.default = self.default
2215 obj.optional = self.optional
2216 obj.offset = self.offset
2217 obj.llen = self.llen
2218 obj.vlen = self.vlen
2219 obj.expl_lenindef = self.expl_lenindef
2220 obj.lenindef = self.lenindef
2221 obj.ber_encoded = self.ber_encoded
2225 self._assert_ready()
2226 for i in six_xrange(self._value[0]):
2231 self._assert_ready()
2232 return self._value[0]
2234 def __bytes__(self):
2235 self._assert_ready()
2236 return self._value[1]
2238 def __eq__(self, their):
2239 if isinstance(their, bytes):
2240 return self._value[1] == their
2241 if not issubclass(their.__class__, BitString):
2244 self._value == their._value and
2245 self.tag == their.tag and
2246 self._expl == their._expl
2251 return [name for name, bit in iteritems(self.specs) if self[bit]]
2261 return self.__class__(
2263 impl=self.tag if impl is None else impl,
2264 expl=self._expl if expl is None else expl,
2265 default=self.default if default is None else default,
2266 optional=self.optional if optional is None else optional,
2270 def __getitem__(self, key):
2271 if isinstance(key, int):
2272 bit_len, octets = self._value
2276 byte2int(memoryview(octets)[key // 8:]) >>
2279 if isinstance(key, string_types):
2280 value = self.specs.get(key)
2282 raise ObjUnknown("BitString value: %s" % key)
2284 raise InvalidValueType((int, str))
2287 self._assert_ready()
2288 bit_len, octets = self._value
2291 len_encode(len(octets) + 1),
2292 int2byte((8 - bit_len % 8) % 8),
2296 def _decode_chunk(self, lv, offset, decode_path, ctx):
2298 l, llen, v = len_decode(lv)
2299 except DecodeError as err:
2300 raise err.__class__(
2302 klass=self.__class__,
2303 decode_path=decode_path,
2307 raise NotEnoughData(
2308 "encoded length is longer than data",
2309 klass=self.__class__,
2310 decode_path=decode_path,
2314 raise NotEnoughData(
2316 klass=self.__class__,
2317 decode_path=decode_path,
2320 pad_size = byte2int(v)
2321 if l == 1 and pad_size != 0:
2323 "invalid empty value",
2324 klass=self.__class__,
2325 decode_path=decode_path,
2331 klass=self.__class__,
2332 decode_path=decode_path,
2335 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2338 klass=self.__class__,
2339 decode_path=decode_path,
2342 v, tail = v[:l], v[l:]
2343 obj = self.__class__(
2344 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2347 default=self.default,
2348 optional=self.optional,
2350 _decoded=(offset, llen, l),
2354 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2356 t, tlen, lv = tag_strip(tlv)
2357 except DecodeError as err:
2358 raise err.__class__(
2360 klass=self.__class__,
2361 decode_path=decode_path,
2365 if tag_only: # pragma: no cover
2367 return self._decode_chunk(lv, offset, decode_path, ctx)
2368 if t == self.tag_constructed:
2369 if not ctx.get("bered", False):
2371 "unallowed BER constructed encoding",
2372 klass=self.__class__,
2373 decode_path=decode_path,
2376 if tag_only: # pragma: no cover
2380 l, llen, v = len_decode(lv)
2381 except LenIndefForm:
2382 llen, l, v = 1, 0, lv[1:]
2384 except DecodeError as err:
2385 raise err.__class__(
2387 klass=self.__class__,
2388 decode_path=decode_path,
2392 raise NotEnoughData(
2393 "encoded length is longer than data",
2394 klass=self.__class__,
2395 decode_path=decode_path,
2398 if not lenindef and l == 0:
2399 raise NotEnoughData(
2401 klass=self.__class__,
2402 decode_path=decode_path,
2406 sub_offset = offset + tlen + llen
2410 if v[:EOC_LEN].tobytes() == EOC:
2417 "chunk out of bounds",
2418 klass=self.__class__,
2419 decode_path=decode_path + (str(len(chunks) - 1),),
2420 offset=chunks[-1].offset,
2422 sub_decode_path = decode_path + (str(len(chunks)),)
2424 chunk, v_tail = BitString().decode(
2427 decode_path=sub_decode_path,
2430 _ctx_immutable=False,
2434 "expected BitString encoded chunk",
2435 klass=self.__class__,
2436 decode_path=sub_decode_path,
2439 chunks.append(chunk)
2440 sub_offset += chunk.tlvlen
2441 vlen += chunk.tlvlen
2443 if len(chunks) == 0:
2446 klass=self.__class__,
2447 decode_path=decode_path,
2452 for chunk_i, chunk in enumerate(chunks[:-1]):
2453 if chunk.bit_len % 8 != 0:
2455 "BitString chunk is not multiple of 8 bits",
2456 klass=self.__class__,
2457 decode_path=decode_path + (str(chunk_i),),
2458 offset=chunk.offset,
2460 values.append(bytes(chunk))
2461 bit_len += chunk.bit_len
2462 chunk_last = chunks[-1]
2463 values.append(bytes(chunk_last))
2464 bit_len += chunk_last.bit_len
2465 obj = self.__class__(
2466 value=(bit_len, b"".join(values)),
2469 default=self.default,
2470 optional=self.optional,
2472 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2474 obj.lenindef = lenindef
2475 obj.ber_encoded = True
2476 return obj, (v[EOC_LEN:] if lenindef else v)
2478 klass=self.__class__,
2479 decode_path=decode_path,
2484 return pp_console_row(next(self.pps()))
2486 def pps(self, decode_path=()):
2490 bit_len, blob = self._value
2491 value = "%d bits" % bit_len
2492 if len(self.specs) > 0:
2493 blob = tuple(self.named)
2496 asn1_type_name=self.asn1_type_name,
2497 obj_name=self.__class__.__name__,
2498 decode_path=decode_path,
2501 optional=self.optional,
2502 default=self == self.default,
2503 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2504 expl=None if self._expl is None else tag_decode(self._expl),
2509 expl_offset=self.expl_offset if self.expled else None,
2510 expl_tlen=self.expl_tlen if self.expled else None,
2511 expl_llen=self.expl_llen if self.expled else None,
2512 expl_vlen=self.expl_vlen if self.expled else None,
2513 expl_lenindef=self.expl_lenindef,
2514 lenindef=self.lenindef,
2515 ber_encoded=self.ber_encoded,
2518 defined_by, defined = self.defined or (None, None)
2519 if defined_by is not None:
2521 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2523 for pp in self.pps_lenindef(decode_path):
2527 class OctetString(Obj):
2528 """``OCTET STRING`` binary string type
2530 >>> s = OctetString(b"hello world")
2531 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2532 >>> s == OctetString(b"hello world")
2537 >>> OctetString(b"hello", bounds=(4, 4))
2538 Traceback (most recent call last):
2539 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2540 >>> OctetString(b"hell", bounds=(4, 4))
2541 OCTET STRING 4 bytes 68656c6c
2545 Pay attention that OCTET STRING can be encoded both in primitive
2546 and constructed forms. Decoder always checks constructed form tag
2547 additionally to specified primitive one. If BER decoding is
2548 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2549 of DER restrictions.
2551 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2552 tag_default = tag_encode(4)
2553 asn1_type_name = "OCTET STRING"
2566 :param value: set the value. Either binary type, or
2567 :py:class:`pyderasn.OctetString` object
2568 :param bounds: set ``(MIN, MAX)`` value size constraint.
2569 (-inf, +inf) by default
2570 :param bytes impl: override default tag with ``IMPLICIT`` one
2571 :param bytes expl: override default tag with ``EXPLICIT`` one
2572 :param default: set default value. Type same as in ``value``
2573 :param bool optional: is object ``OPTIONAL`` in sequence
2575 super(OctetString, self).__init__(
2583 self._bound_min, self._bound_max = getattr(
2587 ) if bounds is None else bounds
2588 if value is not None:
2589 self._value = self._value_sanitize(value)
2590 if default is not None:
2591 default = self._value_sanitize(default)
2592 self.default = self.__class__(
2597 if self._value is None:
2598 self._value = default
2600 tag_klass, _, tag_num = tag_decode(self.tag)
2601 self.tag_constructed = tag_encode(
2603 form=TagFormConstructed,
2607 def _value_sanitize(self, value):
2608 if isinstance(value, binary_type):
2610 elif issubclass(value.__class__, OctetString):
2611 value = value._value
2613 raise InvalidValueType((self.__class__, bytes))
2614 if not self._bound_min <= len(value) <= self._bound_max:
2615 raise BoundsError(self._bound_min, len(value), self._bound_max)
2620 return self._value is not None
2623 obj = self.__class__()
2624 obj._value = self._value
2625 obj._bound_min = self._bound_min
2626 obj._bound_max = self._bound_max
2628 obj._expl = self._expl
2629 obj.default = self.default
2630 obj.optional = self.optional
2631 obj.offset = self.offset
2632 obj.llen = self.llen
2633 obj.vlen = self.vlen
2634 obj.expl_lenindef = self.expl_lenindef
2635 obj.lenindef = self.lenindef
2636 obj.ber_encoded = self.ber_encoded
2639 def __bytes__(self):
2640 self._assert_ready()
2643 def __eq__(self, their):
2644 if isinstance(their, binary_type):
2645 return self._value == their
2646 if not issubclass(their.__class__, OctetString):
2649 self._value == their._value and
2650 self.tag == their.tag and
2651 self._expl == their._expl
2654 def __lt__(self, their):
2655 return self._value < their._value
2666 return self.__class__(
2669 (self._bound_min, self._bound_max)
2670 if bounds is None else bounds
2672 impl=self.tag if impl is None else impl,
2673 expl=self._expl if expl is None else expl,
2674 default=self.default if default is None else default,
2675 optional=self.optional if optional is None else optional,
2679 self._assert_ready()
2682 len_encode(len(self._value)),
2686 def _decode_chunk(self, lv, offset, decode_path, ctx):
2688 l, llen, v = len_decode(lv)
2689 except DecodeError as err:
2690 raise err.__class__(
2692 klass=self.__class__,
2693 decode_path=decode_path,
2697 raise NotEnoughData(
2698 "encoded length is longer than data",
2699 klass=self.__class__,
2700 decode_path=decode_path,
2703 v, tail = v[:l], v[l:]
2705 obj = self.__class__(
2707 bounds=(self._bound_min, self._bound_max),
2710 default=self.default,
2711 optional=self.optional,
2712 _decoded=(offset, llen, l),
2714 except DecodeError as err:
2717 klass=self.__class__,
2718 decode_path=decode_path,
2721 except BoundsError as err:
2724 klass=self.__class__,
2725 decode_path=decode_path,
2730 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2732 t, tlen, lv = tag_strip(tlv)
2733 except DecodeError as err:
2734 raise err.__class__(
2736 klass=self.__class__,
2737 decode_path=decode_path,
2743 return self._decode_chunk(lv, offset, decode_path, ctx)
2744 if t == self.tag_constructed:
2745 if not ctx.get("bered", False):
2747 "unallowed BER constructed encoding",
2748 klass=self.__class__,
2749 decode_path=decode_path,
2756 l, llen, v = len_decode(lv)
2757 except LenIndefForm:
2758 llen, l, v = 1, 0, lv[1:]
2760 except DecodeError as err:
2761 raise err.__class__(
2763 klass=self.__class__,
2764 decode_path=decode_path,
2768 raise NotEnoughData(
2769 "encoded length is longer than data",
2770 klass=self.__class__,
2771 decode_path=decode_path,
2775 sub_offset = offset + tlen + llen
2779 if v[:EOC_LEN].tobytes() == EOC:
2786 "chunk out of bounds",
2787 klass=self.__class__,
2788 decode_path=decode_path + (str(len(chunks) - 1),),
2789 offset=chunks[-1].offset,
2791 sub_decode_path = decode_path + (str(len(chunks)),)
2793 chunk, v_tail = OctetString().decode(
2796 decode_path=sub_decode_path,
2799 _ctx_immutable=False,
2803 "expected OctetString encoded chunk",
2804 klass=self.__class__,
2805 decode_path=sub_decode_path,
2808 chunks.append(chunk)
2809 sub_offset += chunk.tlvlen
2810 vlen += chunk.tlvlen
2813 obj = self.__class__(
2814 value=b"".join(bytes(chunk) for chunk in chunks),
2815 bounds=(self._bound_min, self._bound_max),
2818 default=self.default,
2819 optional=self.optional,
2820 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2822 except DecodeError as err:
2825 klass=self.__class__,
2826 decode_path=decode_path,
2829 except BoundsError as err:
2832 klass=self.__class__,
2833 decode_path=decode_path,
2836 obj.lenindef = lenindef
2837 obj.ber_encoded = True
2838 return obj, (v[EOC_LEN:] if lenindef else v)
2840 klass=self.__class__,
2841 decode_path=decode_path,
2846 return pp_console_row(next(self.pps()))
2848 def pps(self, decode_path=()):
2851 asn1_type_name=self.asn1_type_name,
2852 obj_name=self.__class__.__name__,
2853 decode_path=decode_path,
2854 value=("%d bytes" % len(self._value)) if self.ready else None,
2855 blob=self._value if self.ready else None,
2856 optional=self.optional,
2857 default=self == self.default,
2858 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2859 expl=None if self._expl is None else tag_decode(self._expl),
2864 expl_offset=self.expl_offset if self.expled else None,
2865 expl_tlen=self.expl_tlen if self.expled else None,
2866 expl_llen=self.expl_llen if self.expled else None,
2867 expl_vlen=self.expl_vlen if self.expled else None,
2868 expl_lenindef=self.expl_lenindef,
2869 lenindef=self.lenindef,
2870 ber_encoded=self.ber_encoded,
2873 defined_by, defined = self.defined or (None, None)
2874 if defined_by is not None:
2876 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2878 for pp in self.pps_lenindef(decode_path):
2883 """``NULL`` null object
2891 tag_default = tag_encode(5)
2892 asn1_type_name = "NULL"
2896 value=None, # unused, but Sequence passes it
2903 :param bytes impl: override default tag with ``IMPLICIT`` one
2904 :param bytes expl: override default tag with ``EXPLICIT`` one
2905 :param bool optional: is object ``OPTIONAL`` in sequence
2907 super(Null, self).__init__(impl, expl, None, optional, _decoded)
2915 obj = self.__class__()
2917 obj._expl = self._expl
2918 obj.default = self.default
2919 obj.optional = self.optional
2920 obj.offset = self.offset
2921 obj.llen = self.llen
2922 obj.vlen = self.vlen
2923 obj.expl_lenindef = self.expl_lenindef
2924 obj.lenindef = self.lenindef
2925 obj.ber_encoded = self.ber_encoded
2928 def __eq__(self, their):
2929 if not issubclass(their.__class__, Null):
2932 self.tag == their.tag and
2933 self._expl == their._expl
2943 return self.__class__(
2944 impl=self.tag if impl is None else impl,
2945 expl=self._expl if expl is None else expl,
2946 optional=self.optional if optional is None else optional,
2950 return self.tag + len_encode(0)
2952 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2954 t, _, lv = tag_strip(tlv)
2955 except DecodeError as err:
2956 raise err.__class__(
2958 klass=self.__class__,
2959 decode_path=decode_path,
2964 klass=self.__class__,
2965 decode_path=decode_path,
2968 if tag_only: # pragma: no cover
2971 l, _, v = len_decode(lv)
2972 except DecodeError as err:
2973 raise err.__class__(
2975 klass=self.__class__,
2976 decode_path=decode_path,
2980 raise InvalidLength(
2981 "Null must have zero length",
2982 klass=self.__class__,
2983 decode_path=decode_path,
2986 obj = self.__class__(
2989 optional=self.optional,
2990 _decoded=(offset, 1, 0),
2995 return pp_console_row(next(self.pps()))
2997 def pps(self, decode_path=()):
3000 asn1_type_name=self.asn1_type_name,
3001 obj_name=self.__class__.__name__,
3002 decode_path=decode_path,
3003 optional=self.optional,
3004 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3005 expl=None if self._expl is None else tag_decode(self._expl),
3010 expl_offset=self.expl_offset if self.expled else None,
3011 expl_tlen=self.expl_tlen if self.expled else None,
3012 expl_llen=self.expl_llen if self.expled else None,
3013 expl_vlen=self.expl_vlen if self.expled else None,
3014 expl_lenindef=self.expl_lenindef,
3017 for pp in self.pps_lenindef(decode_path):
3021 class ObjectIdentifier(Obj):
3022 """``OBJECT IDENTIFIER`` OID type
3024 >>> oid = ObjectIdentifier((1, 2, 3))
3025 OBJECT IDENTIFIER 1.2.3
3026 >>> oid == ObjectIdentifier("1.2.3")
3032 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3033 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3035 >>> str(ObjectIdentifier((3, 1)))
3036 Traceback (most recent call last):
3037 pyderasn.InvalidOID: unacceptable first arc value
3039 __slots__ = ("defines",)
3040 tag_default = tag_encode(6)
3041 asn1_type_name = "OBJECT IDENTIFIER"
3054 :param value: set the value. Either tuples of integers,
3055 string of "."-concatenated integers, or
3056 :py:class:`pyderasn.ObjectIdentifier` object
3057 :param defines: sequence of tuples. Each tuple has two elements.
3058 First one is relative to current one decode
3059 path, aiming to the field defined by that OID.
3060 Read about relative path in
3061 :py:func:`pyderasn.abs_decode_path`. Second
3062 tuple element is ``{OID: pyderasn.Obj()}``
3063 dictionary, mapping between current OID value
3064 and structure applied to defined field.
3065 :ref:`Read about DEFINED BY <definedby>`
3066 :param bytes impl: override default tag with ``IMPLICIT`` one
3067 :param bytes expl: override default tag with ``EXPLICIT`` one
3068 :param default: set default value. Type same as in ``value``
3069 :param bool optional: is object ``OPTIONAL`` in sequence
3071 super(ObjectIdentifier, self).__init__(
3079 if value is not None:
3080 self._value = self._value_sanitize(value)
3081 if default is not None:
3082 default = self._value_sanitize(default)
3083 self.default = self.__class__(
3088 if self._value is None:
3089 self._value = default
3090 self.defines = defines
3092 def __add__(self, their):
3093 if isinstance(their, self.__class__):
3094 return self.__class__(self._value + their._value)
3095 if isinstance(their, tuple):
3096 return self.__class__(self._value + their)
3097 raise InvalidValueType((self.__class__, tuple))
3099 def _value_sanitize(self, value):
3100 if issubclass(value.__class__, ObjectIdentifier):
3102 if isinstance(value, string_types):
3104 value = tuple(int(arc) for arc in value.split("."))
3106 raise InvalidOID("unacceptable arcs values")
3107 if isinstance(value, tuple):
3109 raise InvalidOID("less than 2 arcs")
3110 first_arc = value[0]
3111 if first_arc in (0, 1):
3112 if not (0 <= value[1] <= 39):
3113 raise InvalidOID("second arc is too wide")
3114 elif first_arc == 2:
3117 raise InvalidOID("unacceptable first arc value")
3119 raise InvalidValueType((self.__class__, str, tuple))
3123 return self._value is not None
3126 obj = self.__class__()
3127 obj._value = self._value
3128 obj.defines = self.defines
3130 obj._expl = self._expl
3131 obj.default = self.default
3132 obj.optional = self.optional
3133 obj.offset = self.offset
3134 obj.llen = self.llen
3135 obj.vlen = self.vlen
3136 obj.expl_lenindef = self.expl_lenindef
3137 obj.lenindef = self.lenindef
3138 obj.ber_encoded = self.ber_encoded
3142 self._assert_ready()
3143 return iter(self._value)
3146 return ".".join(str(arc) for arc in self._value or ())
3149 self._assert_ready()
3152 bytes(self._expl or b"") +
3153 str(self._value).encode("ascii"),
3156 def __eq__(self, their):
3157 if isinstance(their, tuple):
3158 return self._value == their
3159 if not issubclass(their.__class__, ObjectIdentifier):
3162 self.tag == their.tag and
3163 self._expl == their._expl and
3164 self._value == their._value
3167 def __lt__(self, their):
3168 return self._value < their._value
3179 return self.__class__(
3181 defines=self.defines if defines is None else defines,
3182 impl=self.tag if impl is None else impl,
3183 expl=self._expl if expl is None else expl,
3184 default=self.default if default is None else default,
3185 optional=self.optional if optional is None else optional,
3189 self._assert_ready()
3191 first_value = value[1]
3192 first_arc = value[0]
3195 elif first_arc == 1:
3197 elif first_arc == 2:
3199 else: # pragma: no cover
3200 raise RuntimeError("invalid arc is stored")
3201 octets = [zero_ended_encode(first_value)]
3202 for arc in value[2:]:
3203 octets.append(zero_ended_encode(arc))
3204 v = b"".join(octets)
3205 return b"".join((self.tag, len_encode(len(v)), v))
3207 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3209 t, _, lv = tag_strip(tlv)
3210 except DecodeError as err:
3211 raise err.__class__(
3213 klass=self.__class__,
3214 decode_path=decode_path,
3219 klass=self.__class__,
3220 decode_path=decode_path,
3223 if tag_only: # pragma: no cover
3226 l, llen, v = len_decode(lv)
3227 except DecodeError as err:
3228 raise err.__class__(
3230 klass=self.__class__,
3231 decode_path=decode_path,
3235 raise NotEnoughData(
3236 "encoded length is longer than data",
3237 klass=self.__class__,
3238 decode_path=decode_path,
3242 raise NotEnoughData(
3244 klass=self.__class__,
3245 decode_path=decode_path,
3248 v, tail = v[:l], v[l:]
3255 octet = indexbytes(v, i)
3256 if i == 0 and octet == 0x80:
3257 if ctx.get("bered", False):
3260 raise DecodeError("non normalized arc encoding")
3261 arc = (arc << 7) | (octet & 0x7F)
3262 if octet & 0x80 == 0:
3270 klass=self.__class__,
3271 decode_path=decode_path,
3275 second_arc = arcs[0]
3276 if 0 <= second_arc <= 39:
3278 elif 40 <= second_arc <= 79:
3284 obj = self.__class__(
3285 value=tuple([first_arc, second_arc] + arcs[1:]),
3288 default=self.default,
3289 optional=self.optional,
3290 _decoded=(offset, llen, l),
3293 obj.ber_encoded = True
3297 return pp_console_row(next(self.pps()))
3299 def pps(self, decode_path=()):
3302 asn1_type_name=self.asn1_type_name,
3303 obj_name=self.__class__.__name__,
3304 decode_path=decode_path,
3305 value=str(self) if self.ready else None,
3306 optional=self.optional,
3307 default=self == self.default,
3308 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3309 expl=None if self._expl is None else tag_decode(self._expl),
3314 expl_offset=self.expl_offset if self.expled else None,
3315 expl_tlen=self.expl_tlen if self.expled else None,
3316 expl_llen=self.expl_llen if self.expled else None,
3317 expl_vlen=self.expl_vlen if self.expled else None,
3318 expl_lenindef=self.expl_lenindef,
3319 ber_encoded=self.ber_encoded,
3322 for pp in self.pps_lenindef(decode_path):
3326 class Enumerated(Integer):
3327 """``ENUMERATED`` integer type
3329 This type is identical to :py:class:`pyderasn.Integer`, but requires
3330 schema to be specified and does not accept values missing from it.
3333 tag_default = tag_encode(10)
3334 asn1_type_name = "ENUMERATED"
3345 bounds=None, # dummy argument, workability for Integer.decode
3347 super(Enumerated, self).__init__(
3356 if len(self.specs) == 0:
3357 raise ValueError("schema must be specified")
3359 def _value_sanitize(self, value):
3360 if isinstance(value, self.__class__):
3361 value = value._value
3362 elif isinstance(value, integer_types):
3363 for _value in itervalues(self.specs):
3368 "unknown integer value: %s" % value,
3369 klass=self.__class__,
3371 elif isinstance(value, string_types):
3372 value = self.specs.get(value)
3374 raise ObjUnknown("integer value: %s" % value)
3376 raise InvalidValueType((self.__class__, int, str))
3380 obj = self.__class__(_specs=self.specs)
3381 obj._value = self._value
3382 obj._bound_min = self._bound_min
3383 obj._bound_max = self._bound_max
3385 obj._expl = self._expl
3386 obj.default = self.default
3387 obj.optional = self.optional
3388 obj.offset = self.offset
3389 obj.llen = self.llen
3390 obj.vlen = self.vlen
3391 obj.expl_lenindef = self.expl_lenindef
3392 obj.lenindef = self.lenindef
3393 obj.ber_encoded = self.ber_encoded
3405 return self.__class__(
3407 impl=self.tag if impl is None else impl,
3408 expl=self._expl if expl is None else expl,
3409 default=self.default if default is None else default,
3410 optional=self.optional if optional is None else optional,
3415 class CommonString(OctetString):
3416 """Common class for all strings
3418 Everything resembles :py:class:`pyderasn.OctetString`, except
3419 ability to deal with unicode text strings.
3421 >>> hexenc("привет мир".encode("utf-8"))
3422 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3423 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3425 >>> s = UTF8String("привет мир")
3426 UTF8String UTF8String привет мир
3428 'привет мир'
3429 >>> hexenc(bytes(s))
3430 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3432 >>> PrintableString("привет мир")
3433 Traceback (most recent call last):
3434 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3436 >>> BMPString("ада", bounds=(2, 2))
3437 Traceback (most recent call last):
3438 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3439 >>> s = BMPString("ад", bounds=(2, 2))
3442 >>> hexenc(bytes(s))
3450 * - :py:class:`pyderasn.UTF8String`
3452 * - :py:class:`pyderasn.NumericString`
3454 * - :py:class:`pyderasn.PrintableString`
3456 * - :py:class:`pyderasn.TeletexString`
3458 * - :py:class:`pyderasn.T61String`
3460 * - :py:class:`pyderasn.VideotexString`
3462 * - :py:class:`pyderasn.IA5String`
3464 * - :py:class:`pyderasn.GraphicString`
3466 * - :py:class:`pyderasn.VisibleString`
3468 * - :py:class:`pyderasn.ISO646String`
3470 * - :py:class:`pyderasn.GeneralString`
3472 * - :py:class:`pyderasn.UniversalString`
3474 * - :py:class:`pyderasn.BMPString`
3477 __slots__ = ("encoding",)
3479 def _value_sanitize(self, value):
3481 value_decoded = None
3482 if isinstance(value, self.__class__):
3483 value_raw = value._value
3484 elif isinstance(value, text_type):
3485 value_decoded = value
3486 elif isinstance(value, binary_type):
3489 raise InvalidValueType((self.__class__, text_type, binary_type))
3492 value_decoded.encode(self.encoding)
3493 if value_raw is None else value_raw
3496 value_raw.decode(self.encoding)
3497 if value_decoded is None else value_decoded
3499 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3500 raise DecodeError(str(err))
3501 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3509 def __eq__(self, their):
3510 if isinstance(their, binary_type):
3511 return self._value == their
3512 if isinstance(their, text_type):
3513 return self._value == their.encode(self.encoding)
3514 if not isinstance(their, self.__class__):
3517 self._value == their._value and
3518 self.tag == their.tag and
3519 self._expl == their._expl
3522 def __unicode__(self):
3524 return self._value.decode(self.encoding)
3525 return text_type(self._value)
3528 return pp_console_row(next(self.pps(no_unicode=PY2)))
3530 def pps(self, decode_path=(), no_unicode=False):
3533 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
3536 asn1_type_name=self.asn1_type_name,
3537 obj_name=self.__class__.__name__,
3538 decode_path=decode_path,
3540 optional=self.optional,
3541 default=self == self.default,
3542 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3543 expl=None if self._expl is None else tag_decode(self._expl),
3548 expl_offset=self.expl_offset if self.expled else None,
3549 expl_tlen=self.expl_tlen if self.expled else None,
3550 expl_llen=self.expl_llen if self.expled else None,
3551 expl_vlen=self.expl_vlen if self.expled else None,
3552 expl_lenindef=self.expl_lenindef,
3553 ber_encoded=self.ber_encoded,
3556 for pp in self.pps_lenindef(decode_path):
3560 class UTF8String(CommonString):
3562 tag_default = tag_encode(12)
3564 asn1_type_name = "UTF8String"
3567 class AllowableCharsMixin(object):
3569 def allowable_chars(self):
3571 return self._allowable_chars
3572 return frozenset(six_unichr(c) for c in self._allowable_chars)
3575 class NumericString(AllowableCharsMixin, CommonString):
3578 Its value is properly sanitized: only ASCII digits with spaces can
3581 >>> NumericString().allowable_chars
3582 set(['3', '4', '7', '5', '1', '0', '8', '9', ' ', '6', '2'])
3585 tag_default = tag_encode(18)
3587 asn1_type_name = "NumericString"
3588 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3590 def _value_sanitize(self, value):
3591 value = super(NumericString, self)._value_sanitize(value)
3592 if not frozenset(value) <= self._allowable_chars:
3593 raise DecodeError("non-numeric value")
3597 class PrintableString(AllowableCharsMixin, CommonString):
3600 Its value is properly sanitized: see X.680 41.4 table 10.
3602 >>> PrintableString().allowable_chars
3603 >>> set([' ', "'", ..., 'z'])
3606 tag_default = tag_encode(19)
3608 asn1_type_name = "PrintableString"
3609 _allowable_chars = frozenset(
3610 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3613 def _value_sanitize(self, value):
3614 value = super(PrintableString, self)._value_sanitize(value)
3615 if not frozenset(value) <= self._allowable_chars:
3616 raise DecodeError("non-printable value")
3620 class TeletexString(CommonString):
3622 tag_default = tag_encode(20)
3624 asn1_type_name = "TeletexString"
3627 class T61String(TeletexString):
3629 asn1_type_name = "T61String"
3632 class VideotexString(CommonString):
3634 tag_default = tag_encode(21)
3635 encoding = "iso-8859-1"
3636 asn1_type_name = "VideotexString"
3639 class IA5String(CommonString):
3641 tag_default = tag_encode(22)
3643 asn1_type_name = "IA5"
3646 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3647 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3648 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3651 class UTCTime(CommonString):
3652 """``UTCTime`` datetime type
3654 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3655 UTCTime UTCTime 2017-09-30T22:07:50
3661 datetime.datetime(2017, 9, 30, 22, 7, 50)
3662 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3663 datetime.datetime(1957, 9, 30, 22, 7, 50)
3667 No BER encodings are supported. Only DER.
3670 tag_default = tag_encode(23)
3672 asn1_type_name = "UTCTime"
3682 bounds=None, # dummy argument, workability for OctetString.decode
3685 :param value: set the value. Either datetime type, or
3686 :py:class:`pyderasn.UTCTime` object
3687 :param bytes impl: override default tag with ``IMPLICIT`` one
3688 :param bytes expl: override default tag with ``EXPLICIT`` one
3689 :param default: set default value. Type same as in ``value``
3690 :param bool optional: is object ``OPTIONAL`` in sequence
3692 super(UTCTime, self).__init__(
3700 if value is not None:
3701 self._value = self._value_sanitize(value)
3702 if default is not None:
3703 default = self._value_sanitize(default)
3704 self.default = self.__class__(
3709 if self._value is None:
3710 self._value = default
3712 def _strptime(self, value):
3713 # datetime.strptime's format: %y%m%d%H%M%SZ
3714 if len(value) != LEN_YYMMDDHHMMSSZ:
3715 raise ValueError("invalid UTCTime length")
3716 if value[-1] != "Z":
3717 raise ValueError("non UTC timezone")
3719 2000 + int(value[:2]), # %y
3720 int(value[2:4]), # %m
3721 int(value[4:6]), # %d
3722 int(value[6:8]), # %H
3723 int(value[8:10]), # %M
3724 int(value[10:12]), # %S
3727 def _value_sanitize(self, value):
3728 if isinstance(value, binary_type):
3730 value_decoded = value.decode("ascii")
3731 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3732 raise DecodeError("invalid UTCTime encoding")
3734 self._strptime(value_decoded)
3735 except (TypeError, ValueError) as err:
3736 raise DecodeError("invalid UTCTime format: %r" % err)
3738 if isinstance(value, self.__class__):
3740 if isinstance(value, datetime):
3741 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3742 raise InvalidValueType((self.__class__, datetime))
3744 def __eq__(self, their):
3745 if isinstance(their, binary_type):
3746 return self._value == their
3747 if isinstance(their, datetime):
3748 return self.todatetime() == their
3749 if not isinstance(their, self.__class__):
3752 self._value == their._value and
3753 self.tag == their.tag and
3754 self._expl == their._expl
3757 def todatetime(self):
3758 """Convert to datetime
3762 Pay attention that UTCTime can not hold full year, so all years
3763 having < 50 years are treated as 20xx, 19xx otherwise, according
3764 to X.509 recomendation.
3766 value = self._strptime(self._value.decode("ascii"))
3767 year = value.year % 100
3769 year=(2000 + year) if year < 50 else (1900 + year),
3773 minute=value.minute,
3774 second=value.second,
3778 return pp_console_row(next(self.pps()))
3780 def pps(self, decode_path=()):
3783 asn1_type_name=self.asn1_type_name,
3784 obj_name=self.__class__.__name__,
3785 decode_path=decode_path,
3786 value=self.todatetime().isoformat() if self.ready else None,
3787 optional=self.optional,
3788 default=self == self.default,
3789 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3790 expl=None if self._expl is None else tag_decode(self._expl),
3795 expl_offset=self.expl_offset if self.expled else None,
3796 expl_tlen=self.expl_tlen if self.expled else None,
3797 expl_llen=self.expl_llen if self.expled else None,
3798 expl_vlen=self.expl_vlen if self.expled else None,
3799 expl_lenindef=self.expl_lenindef,
3800 ber_encoded=self.ber_encoded,
3803 for pp in self.pps_lenindef(decode_path):
3807 class GeneralizedTime(UTCTime):
3808 """``GeneralizedTime`` datetime type
3810 This type is similar to :py:class:`pyderasn.UTCTime`.
3812 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3813 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3815 '20170930220750.000123Z'
3816 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3817 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3821 No BER encodings are supported. Only DER.
3825 Only microsecond fractions are supported.
3826 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
3827 higher precision values.
3830 tag_default = tag_encode(24)
3831 asn1_type_name = "GeneralizedTime"
3833 def _strptime(self, value):
3835 if l == LEN_YYYYMMDDHHMMSSZ:
3836 # datetime.strptime's format: %y%m%d%H%M%SZ
3837 if value[-1] != "Z":
3838 raise ValueError("non UTC timezone")
3840 int(value[:4]), # %Y
3841 int(value[4:6]), # %m
3842 int(value[6:8]), # %d
3843 int(value[8:10]), # %H
3844 int(value[10:12]), # %M
3845 int(value[12:14]), # %S
3847 if l >= LEN_YYYYMMDDHHMMSSDMZ:
3848 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
3849 if value[-1] != "Z":
3850 raise ValueError("non UTC timezone")
3851 if value[14] != ".":
3852 raise ValueError("no fractions separator")
3855 raise ValueError("trailing zero")
3858 raise ValueError("only microsecond fractions are supported")
3859 us = int(us + ("0" * (6 - us_len)))
3861 int(value[:4]), # %Y
3862 int(value[4:6]), # %m
3863 int(value[6:8]), # %d
3864 int(value[8:10]), # %H
3865 int(value[10:12]), # %M
3866 int(value[12:14]), # %S
3870 raise ValueError("invalid GeneralizedTime length")
3872 def _value_sanitize(self, value):
3873 if isinstance(value, binary_type):
3875 value_decoded = value.decode("ascii")
3876 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3877 raise DecodeError("invalid GeneralizedTime encoding")
3879 self._strptime(value_decoded)
3880 except (TypeError, ValueError) as err:
3882 "invalid GeneralizedTime format: %r" % err,
3883 klass=self.__class__,
3886 if isinstance(value, self.__class__):
3888 if isinstance(value, datetime):
3889 encoded = value.strftime("%Y%m%d%H%M%S")
3890 if value.microsecond > 0:
3891 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
3892 return (encoded + "Z").encode("ascii")
3893 raise InvalidValueType((self.__class__, datetime))
3895 def todatetime(self):
3896 return self._strptime(self._value.decode("ascii"))
3899 class GraphicString(CommonString):
3901 tag_default = tag_encode(25)
3902 encoding = "iso-8859-1"
3903 asn1_type_name = "GraphicString"
3906 class VisibleString(CommonString):
3908 tag_default = tag_encode(26)
3910 asn1_type_name = "VisibleString"
3913 class ISO646String(VisibleString):
3915 asn1_type_name = "ISO646String"
3918 class GeneralString(CommonString):
3920 tag_default = tag_encode(27)
3921 encoding = "iso-8859-1"
3922 asn1_type_name = "GeneralString"
3925 class UniversalString(CommonString):
3927 tag_default = tag_encode(28)
3928 encoding = "utf-32-be"
3929 asn1_type_name = "UniversalString"
3932 class BMPString(CommonString):
3934 tag_default = tag_encode(30)
3935 encoding = "utf-16-be"
3936 asn1_type_name = "BMPString"
3940 """``CHOICE`` special type
3944 class GeneralName(Choice):
3946 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
3947 ("dNSName", IA5String(impl=tag_ctxp(2))),
3950 >>> gn = GeneralName()
3952 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
3953 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3954 >>> gn["dNSName"] = IA5String("bar.baz")
3955 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
3956 >>> gn["rfc822Name"]
3959 [2] IA5String IA5 bar.baz
3962 >>> gn.value == gn["dNSName"]
3965 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
3967 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
3968 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3970 __slots__ = ("specs",)
3972 asn1_type_name = "CHOICE"
3985 :param value: set the value. Either ``(choice, value)`` tuple, or
3986 :py:class:`pyderasn.Choice` object
3987 :param bytes impl: can not be set, do **not** use it
3988 :param bytes expl: override default tag with ``EXPLICIT`` one
3989 :param default: set default value. Type same as in ``value``
3990 :param bool optional: is object ``OPTIONAL`` in sequence
3992 if impl is not None:
3993 raise ValueError("no implicit tag allowed for CHOICE")
3994 super(Choice, self).__init__(None, expl, default, optional, _decoded)
3996 schema = getattr(self, "schema", ())
3997 if len(schema) == 0:
3998 raise ValueError("schema must be specified")
4000 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4003 if value is not None:
4004 self._value = self._value_sanitize(value)
4005 if default is not None:
4006 default_value = self._value_sanitize(default)
4007 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4008 default_obj.specs = self.specs
4009 default_obj._value = default_value
4010 self.default = default_obj
4012 self._value = default_obj.copy()._value
4014 def _value_sanitize(self, value):
4015 if isinstance(value, tuple) and len(value) == 2:
4017 spec = self.specs.get(choice)
4019 raise ObjUnknown(choice)
4020 if not isinstance(obj, spec.__class__):
4021 raise InvalidValueType((spec,))
4022 return (choice, spec(obj))
4023 if isinstance(value, self.__class__):
4025 raise InvalidValueType((self.__class__, tuple))
4029 return self._value is not None and self._value[1].ready
4033 return self.expl_lenindef or (
4034 (self._value is not None) and
4035 self._value[1].bered
4039 obj = self.__class__(schema=self.specs)
4040 obj._expl = self._expl
4041 obj.default = self.default
4042 obj.optional = self.optional
4043 obj.offset = self.offset
4044 obj.llen = self.llen
4045 obj.vlen = self.vlen
4046 obj.expl_lenindef = self.expl_lenindef
4047 obj.lenindef = self.lenindef
4048 obj.ber_encoded = self.ber_encoded
4050 if value is not None:
4051 obj._value = (value[0], value[1].copy())
4054 def __eq__(self, their):
4055 if isinstance(their, tuple) and len(their) == 2:
4056 return self._value == their
4057 if not isinstance(their, self.__class__):
4060 self.specs == their.specs and
4061 self._value == their._value
4071 return self.__class__(
4074 expl=self._expl if expl is None else expl,
4075 default=self.default if default is None else default,
4076 optional=self.optional if optional is None else optional,
4081 self._assert_ready()
4082 return self._value[0]
4086 self._assert_ready()
4087 return self._value[1]
4089 def __getitem__(self, key):
4090 if key not in self.specs:
4091 raise ObjUnknown(key)
4092 if self._value is None:
4094 choice, value = self._value
4099 def __setitem__(self, key, value):
4100 spec = self.specs.get(key)
4102 raise ObjUnknown(key)
4103 if not isinstance(value, spec.__class__):
4104 raise InvalidValueType((spec.__class__,))
4105 self._value = (key, spec(value))
4113 return self._value[1].decoded if self.ready else False
4116 self._assert_ready()
4117 return self._value[1].encode()
4119 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4120 for choice, spec in iteritems(self.specs):
4121 sub_decode_path = decode_path + (choice,)
4127 decode_path=sub_decode_path,
4130 _ctx_immutable=False,
4137 klass=self.__class__,
4138 decode_path=decode_path,
4141 if tag_only: # pragma: no cover
4143 value, tail = spec.decode(
4147 decode_path=sub_decode_path,
4149 _ctx_immutable=False,
4151 obj = self.__class__(
4154 default=self.default,
4155 optional=self.optional,
4156 _decoded=(offset, 0, value.fulllen),
4158 obj._value = (choice, value)
4162 value = pp_console_row(next(self.pps()))
4164 value = "%s[%r]" % (value, self.value)
4167 def pps(self, decode_path=()):
4170 asn1_type_name=self.asn1_type_name,
4171 obj_name=self.__class__.__name__,
4172 decode_path=decode_path,
4173 value=self.choice if self.ready else None,
4174 optional=self.optional,
4175 default=self == self.default,
4176 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4177 expl=None if self._expl is None else tag_decode(self._expl),
4182 expl_lenindef=self.expl_lenindef,
4186 yield self.value.pps(decode_path=decode_path + (self.choice,))
4187 for pp in self.pps_lenindef(decode_path):
4191 class PrimitiveTypes(Choice):
4192 """Predefined ``CHOICE`` for all generic primitive types
4194 It could be useful for general decoding of some unspecified values:
4196 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4197 OCTET STRING 3 bytes 666f6f
4198 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4202 schema = tuple((klass.__name__, klass()) for klass in (
4227 """``ANY`` special type
4229 >>> Any(Integer(-123))
4231 >>> a = Any(OctetString(b"hello world").encode())
4232 ANY 040b68656c6c6f20776f726c64
4233 >>> hexenc(bytes(a))
4234 b'0x040x0bhello world'
4236 __slots__ = ("defined",)
4237 tag_default = tag_encode(0)
4238 asn1_type_name = "ANY"
4248 :param value: set the value. Either any kind of pyderasn's
4249 **ready** object, or bytes. Pay attention that
4250 **no** validation is performed is raw binary value
4252 :param bytes expl: override default tag with ``EXPLICIT`` one
4253 :param bool optional: is object ``OPTIONAL`` in sequence
4255 super(Any, self).__init__(None, expl, None, optional, _decoded)
4256 self._value = None if value is None else self._value_sanitize(value)
4259 def _value_sanitize(self, value):
4260 if isinstance(value, binary_type):
4262 if isinstance(value, self.__class__):
4264 if isinstance(value, Obj):
4265 return value.encode()
4266 raise InvalidValueType((self.__class__, Obj, binary_type))
4270 return self._value is not None
4274 if self.expl_lenindef or self.lenindef:
4276 if self.defined is None:
4278 return self.defined[1].bered
4281 obj = self.__class__()
4282 obj._value = self._value
4284 obj._expl = self._expl
4285 obj.optional = self.optional
4286 obj.offset = self.offset
4287 obj.llen = self.llen
4288 obj.vlen = self.vlen
4289 obj.expl_lenindef = self.expl_lenindef
4290 obj.lenindef = self.lenindef
4291 obj.ber_encoded = self.ber_encoded
4294 def __eq__(self, their):
4295 if isinstance(their, binary_type):
4296 return self._value == their
4297 if issubclass(their.__class__, Any):
4298 return self._value == their._value
4307 return self.__class__(
4309 expl=self._expl if expl is None else expl,
4310 optional=self.optional if optional is None else optional,
4313 def __bytes__(self):
4314 self._assert_ready()
4322 self._assert_ready()
4325 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4327 t, tlen, lv = tag_strip(tlv)
4328 except DecodeError as err:
4329 raise err.__class__(
4331 klass=self.__class__,
4332 decode_path=decode_path,
4336 l, llen, v = len_decode(lv)
4337 except LenIndefForm as err:
4338 if not ctx.get("bered", False):
4339 raise err.__class__(
4341 klass=self.__class__,
4342 decode_path=decode_path,
4345 llen, vlen, v = 1, 0, lv[1:]
4346 sub_offset = offset + tlen + llen
4348 while v[:EOC_LEN].tobytes() != EOC:
4349 chunk, v = Any().decode(
4352 decode_path=decode_path + (str(chunk_i),),
4355 _ctx_immutable=False,
4357 vlen += chunk.tlvlen
4358 sub_offset += chunk.tlvlen
4360 tlvlen = tlen + llen + vlen + EOC_LEN
4361 obj = self.__class__(
4362 value=tlv[:tlvlen].tobytes(),
4364 optional=self.optional,
4365 _decoded=(offset, 0, tlvlen),
4369 return obj, v[EOC_LEN:]
4370 except DecodeError as err:
4371 raise err.__class__(
4373 klass=self.__class__,
4374 decode_path=decode_path,
4378 raise NotEnoughData(
4379 "encoded length is longer than data",
4380 klass=self.__class__,
4381 decode_path=decode_path,
4384 tlvlen = tlen + llen + l
4385 v, tail = tlv[:tlvlen], v[l:]
4386 obj = self.__class__(
4389 optional=self.optional,
4390 _decoded=(offset, 0, tlvlen),
4396 return pp_console_row(next(self.pps()))
4398 def pps(self, decode_path=()):
4401 asn1_type_name=self.asn1_type_name,
4402 obj_name=self.__class__.__name__,
4403 decode_path=decode_path,
4404 blob=self._value if self.ready else None,
4405 optional=self.optional,
4406 default=self == self.default,
4407 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4408 expl=None if self._expl is None else tag_decode(self._expl),
4413 expl_offset=self.expl_offset if self.expled else None,
4414 expl_tlen=self.expl_tlen if self.expled else None,
4415 expl_llen=self.expl_llen if self.expled else None,
4416 expl_vlen=self.expl_vlen if self.expled else None,
4417 expl_lenindef=self.expl_lenindef,
4418 lenindef=self.lenindef,
4421 defined_by, defined = self.defined or (None, None)
4422 if defined_by is not None:
4424 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4426 for pp in self.pps_lenindef(decode_path):
4430 ########################################################################
4431 # ASN.1 constructed types
4432 ########################################################################
4434 def get_def_by_path(defines_by_path, sub_decode_path):
4435 """Get define by decode path
4437 for path, define in defines_by_path:
4438 if len(path) != len(sub_decode_path):
4440 for p1, p2 in zip(path, sub_decode_path):
4441 if (p1 != any) and (p1 != p2):
4447 def abs_decode_path(decode_path, rel_path):
4448 """Create an absolute decode path from current and relative ones
4450 :param decode_path: current decode path, starting point. Tuple of strings
4451 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4452 If first tuple's element is "/", then treat it as
4453 an absolute path, ignoring ``decode_path`` as
4454 starting point. Also this tuple can contain ".."
4455 elements, stripping the leading element from
4458 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4459 ("foo", "bar", "baz", "whatever")
4460 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4462 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4465 if rel_path[0] == "/":
4467 if rel_path[0] == "..":
4468 return abs_decode_path(decode_path[:-1], rel_path[1:])
4469 return decode_path + rel_path
4472 class Sequence(Obj):
4473 """``SEQUENCE`` structure type
4475 You have to make specification of sequence::
4477 class Extension(Sequence):
4479 ("extnID", ObjectIdentifier()),
4480 ("critical", Boolean(default=False)),
4481 ("extnValue", OctetString()),
4484 Then, you can work with it as with dictionary.
4486 >>> ext = Extension()
4487 >>> Extension().specs
4489 ('extnID', OBJECT IDENTIFIER),
4490 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4491 ('extnValue', OCTET STRING),
4493 >>> ext["extnID"] = "1.2.3"
4494 Traceback (most recent call last):
4495 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4496 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4498 You can determine if sequence is ready to be encoded:
4503 Traceback (most recent call last):
4504 pyderasn.ObjNotReady: object is not ready: extnValue
4505 >>> ext["extnValue"] = OctetString(b"foobar")
4509 Value you want to assign, must have the same **type** as in
4510 corresponding specification, but it can have different tags,
4511 optional/default attributes -- they will be taken from specification
4514 class TBSCertificate(Sequence):
4516 ("version", Version(expl=tag_ctxc(0), default="v1")),
4519 >>> tbs = TBSCertificate()
4520 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4522 Assign ``None`` to remove value from sequence.
4524 You can set values in Sequence during its initialization:
4526 >>> AlgorithmIdentifier((
4527 ("algorithm", ObjectIdentifier("1.2.3")),
4528 ("parameters", Any(Null()))
4530 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4532 You can determine if value exists/set in the sequence and take its value:
4534 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4537 OBJECT IDENTIFIER 1.2.3
4539 But pay attention that if value has default, then it won't be (not
4540 in) in the sequence (because ``DEFAULT`` must not be encoded in
4541 DER), but you can read its value:
4543 >>> "critical" in ext, ext["critical"]
4544 (False, BOOLEAN False)
4545 >>> ext["critical"] = Boolean(True)
4546 >>> "critical" in ext, ext["critical"]
4547 (True, BOOLEAN True)
4549 All defaulted values are always optional.
4551 .. _allow_default_values_ctx:
4553 DER prohibits default value encoding and will raise an error if
4554 default value is unexpectedly met during decode.
4555 If :ref:`bered <bered_ctx>` context option is set, then no error
4556 will be raised, but ``bered`` attribute set. You can disable strict
4557 defaulted values existence validation by setting
4558 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4560 Two sequences are equal if they have equal specification (schema),
4561 implicit/explicit tagging and the same values.
4563 __slots__ = ("specs",)
4564 tag_default = tag_encode(form=TagFormConstructed, num=16)
4565 asn1_type_name = "SEQUENCE"
4577 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4579 schema = getattr(self, "schema", ())
4581 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4584 if value is not None:
4585 if issubclass(value.__class__, Sequence):
4586 self._value = value._value
4587 elif hasattr(value, "__iter__"):
4588 for seq_key, seq_value in value:
4589 self[seq_key] = seq_value
4591 raise InvalidValueType((Sequence,))
4592 if default is not None:
4593 if not issubclass(default.__class__, Sequence):
4594 raise InvalidValueType((Sequence,))
4595 default_value = default._value
4596 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4597 default_obj.specs = self.specs
4598 default_obj._value = default_value
4599 self.default = default_obj
4601 self._value = default_obj.copy()._value
4605 for name, spec in iteritems(self.specs):
4606 value = self._value.get(name)
4618 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4620 return any(value.bered for value in itervalues(self._value))
4623 obj = self.__class__(schema=self.specs)
4625 obj._expl = self._expl
4626 obj.default = self.default
4627 obj.optional = self.optional
4628 obj.offset = self.offset
4629 obj.llen = self.llen
4630 obj.vlen = self.vlen
4631 obj.expl_lenindef = self.expl_lenindef
4632 obj.lenindef = self.lenindef
4633 obj.ber_encoded = self.ber_encoded
4634 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4637 def __eq__(self, their):
4638 if not isinstance(their, self.__class__):
4641 self.specs == their.specs and
4642 self.tag == their.tag and
4643 self._expl == their._expl and
4644 self._value == their._value
4655 return self.__class__(
4658 impl=self.tag if impl is None else impl,
4659 expl=self._expl if expl is None else expl,
4660 default=self.default if default is None else default,
4661 optional=self.optional if optional is None else optional,
4664 def __contains__(self, key):
4665 return key in self._value
4667 def __setitem__(self, key, value):
4668 spec = self.specs.get(key)
4670 raise ObjUnknown(key)
4672 self._value.pop(key, None)
4674 if not isinstance(value, spec.__class__):
4675 raise InvalidValueType((spec.__class__,))
4676 value = spec(value=value)
4677 if spec.default is not None and value == spec.default:
4678 self._value.pop(key, None)
4680 self._value[key] = value
4682 def __getitem__(self, key):
4683 value = self._value.get(key)
4684 if value is not None:
4686 spec = self.specs.get(key)
4688 raise ObjUnknown(key)
4689 if spec.default is not None:
4693 def _encoded_values(self):
4695 for name, spec in iteritems(self.specs):
4696 value = self._value.get(name)
4700 raise ObjNotReady(name)
4701 raws.append(value.encode())
4705 v = b"".join(self._encoded_values())
4706 return b"".join((self.tag, len_encode(len(v)), v))
4708 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4710 t, tlen, lv = tag_strip(tlv)
4711 except DecodeError as err:
4712 raise err.__class__(
4714 klass=self.__class__,
4715 decode_path=decode_path,
4720 klass=self.__class__,
4721 decode_path=decode_path,
4724 if tag_only: # pragma: no cover
4727 ctx_bered = ctx.get("bered", False)
4729 l, llen, v = len_decode(lv)
4730 except LenIndefForm as err:
4732 raise err.__class__(
4734 klass=self.__class__,
4735 decode_path=decode_path,
4738 l, llen, v = 0, 1, lv[1:]
4740 except DecodeError as err:
4741 raise err.__class__(
4743 klass=self.__class__,
4744 decode_path=decode_path,
4748 raise NotEnoughData(
4749 "encoded length is longer than data",
4750 klass=self.__class__,
4751 decode_path=decode_path,
4755 v, tail = v[:l], v[l:]
4757 sub_offset = offset + tlen + llen
4760 ctx_allow_default_values = ctx.get("allow_default_values", False)
4761 for name, spec in iteritems(self.specs):
4762 if spec.optional and (
4763 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4767 sub_decode_path = decode_path + (name,)
4769 value, v_tail = spec.decode(
4773 decode_path=sub_decode_path,
4775 _ctx_immutable=False,
4782 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4783 if defined is not None:
4784 defined_by, defined_spec = defined
4785 if issubclass(value.__class__, SequenceOf):
4786 for i, _value in enumerate(value):
4787 sub_sub_decode_path = sub_decode_path + (
4789 DecodePathDefBy(defined_by),
4791 defined_value, defined_tail = defined_spec.decode(
4792 memoryview(bytes(_value)),
4794 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4795 if value.expled else (value.tlen + value.llen)
4798 decode_path=sub_sub_decode_path,
4800 _ctx_immutable=False,
4802 if len(defined_tail) > 0:
4805 klass=self.__class__,
4806 decode_path=sub_sub_decode_path,
4809 _value.defined = (defined_by, defined_value)
4811 defined_value, defined_tail = defined_spec.decode(
4812 memoryview(bytes(value)),
4814 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4815 if value.expled else (value.tlen + value.llen)
4818 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4820 _ctx_immutable=False,
4822 if len(defined_tail) > 0:
4825 klass=self.__class__,
4826 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4829 value.defined = (defined_by, defined_value)
4831 value_len = value.fulllen
4833 sub_offset += value_len
4835 if spec.default is not None and value == spec.default:
4836 if ctx_bered or ctx_allow_default_values:
4840 "DEFAULT value met",
4841 klass=self.__class__,
4842 decode_path=sub_decode_path,
4845 values[name] = value
4847 spec_defines = getattr(spec, "defines", ())
4848 if len(spec_defines) == 0:
4849 defines_by_path = ctx.get("defines_by_path", ())
4850 if len(defines_by_path) > 0:
4851 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4852 if spec_defines is not None and len(spec_defines) > 0:
4853 for rel_path, schema in spec_defines:
4854 defined = schema.get(value, None)
4855 if defined is not None:
4856 ctx.setdefault("_defines", []).append((
4857 abs_decode_path(sub_decode_path[:-1], rel_path),
4861 if v[:EOC_LEN].tobytes() != EOC:
4864 klass=self.__class__,
4865 decode_path=decode_path,
4873 klass=self.__class__,
4874 decode_path=decode_path,
4877 obj = self.__class__(
4881 default=self.default,
4882 optional=self.optional,
4883 _decoded=(offset, llen, vlen),
4886 obj.lenindef = lenindef
4887 obj.ber_encoded = ber_encoded
4891 value = pp_console_row(next(self.pps()))
4893 for name in self.specs:
4894 _value = self._value.get(name)
4897 cols.append("%s: %s" % (name, repr(_value)))
4898 return "%s[%s]" % (value, "; ".join(cols))
4900 def pps(self, decode_path=()):
4903 asn1_type_name=self.asn1_type_name,
4904 obj_name=self.__class__.__name__,
4905 decode_path=decode_path,
4906 optional=self.optional,
4907 default=self == self.default,
4908 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4909 expl=None if self._expl is None else tag_decode(self._expl),
4914 expl_offset=self.expl_offset if self.expled else None,
4915 expl_tlen=self.expl_tlen if self.expled else None,
4916 expl_llen=self.expl_llen if self.expled else None,
4917 expl_vlen=self.expl_vlen if self.expled else None,
4918 expl_lenindef=self.expl_lenindef,
4919 lenindef=self.lenindef,
4920 ber_encoded=self.ber_encoded,
4923 for name in self.specs:
4924 value = self._value.get(name)
4927 yield value.pps(decode_path=decode_path + (name,))
4928 for pp in self.pps_lenindef(decode_path):
4932 class Set(Sequence):
4933 """``SET`` structure type
4935 Its usage is identical to :py:class:`pyderasn.Sequence`.
4937 .. _allow_unordered_set_ctx:
4939 DER prohibits unordered values encoding and will raise an error
4940 during decode. If If :ref:`bered <bered_ctx>` context option is set,
4941 then no error will occure. Also you can disable strict values
4942 ordering check by setting ``"allow_unordered_set": True``
4943 :ref:`context <ctx>` option.
4946 tag_default = tag_encode(form=TagFormConstructed, num=17)
4947 asn1_type_name = "SET"
4950 raws = self._encoded_values()
4953 return b"".join((self.tag, len_encode(len(v)), v))
4955 def _specs_items(self):
4956 return iteritems(self.specs)
4958 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4960 t, tlen, lv = tag_strip(tlv)
4961 except DecodeError as err:
4962 raise err.__class__(
4964 klass=self.__class__,
4965 decode_path=decode_path,
4970 klass=self.__class__,
4971 decode_path=decode_path,
4977 ctx_bered = ctx.get("bered", False)
4979 l, llen, v = len_decode(lv)
4980 except LenIndefForm as err:
4982 raise err.__class__(
4984 klass=self.__class__,
4985 decode_path=decode_path,
4988 l, llen, v = 0, 1, lv[1:]
4990 except DecodeError as err:
4991 raise err.__class__(
4993 klass=self.__class__,
4994 decode_path=decode_path,
4998 raise NotEnoughData(
4999 "encoded length is longer than data",
5000 klass=self.__class__,
5004 v, tail = v[:l], v[l:]
5006 sub_offset = offset + tlen + llen
5009 ctx_allow_default_values = ctx.get("allow_default_values", False)
5010 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5011 value_prev = memoryview(v[:0])
5014 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5016 for name, spec in self._specs_items():
5017 sub_decode_path = decode_path + (name,)
5023 decode_path=sub_decode_path,
5026 _ctx_immutable=False,
5033 klass=self.__class__,
5034 decode_path=decode_path,
5037 value, v_tail = spec.decode(
5041 decode_path=sub_decode_path,
5043 _ctx_immutable=False,
5045 value_len = value.fulllen
5046 if value_prev.tobytes() > v[:value_len].tobytes():
5047 if ctx_bered or ctx_allow_unordered_set:
5051 "unordered " + self.asn1_type_name,
5052 klass=self.__class__,
5053 decode_path=sub_decode_path,
5056 if spec.default is None or value != spec.default:
5058 elif ctx_bered or ctx_allow_default_values:
5062 "DEFAULT value met",
5063 klass=self.__class__,
5064 decode_path=sub_decode_path,
5067 values[name] = value
5068 value_prev = v[:value_len]
5069 sub_offset += value_len
5072 obj = self.__class__(
5076 default=self.default,
5077 optional=self.optional,
5078 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5081 if v[:EOC_LEN].tobytes() != EOC:
5084 klass=self.__class__,
5085 decode_path=decode_path,
5093 "not all values are ready",
5094 klass=self.__class__,
5095 decode_path=decode_path,
5098 obj.ber_encoded = ber_encoded
5102 class SequenceOf(Obj):
5103 """``SEQUENCE OF`` sequence type
5105 For that kind of type you must specify the object it will carry on
5106 (bounds are for example here, not required)::
5108 class Ints(SequenceOf):
5113 >>> ints.append(Integer(123))
5114 >>> ints.append(Integer(234))
5116 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5117 >>> [int(i) for i in ints]
5119 >>> ints.append(Integer(345))
5120 Traceback (most recent call last):
5121 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5124 >>> ints[1] = Integer(345)
5126 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5128 Also you can initialize sequence with preinitialized values:
5130 >>> ints = Ints([Integer(123), Integer(234)])
5132 __slots__ = ("spec", "_bound_min", "_bound_max")
5133 tag_default = tag_encode(form=TagFormConstructed, num=16)
5134 asn1_type_name = "SEQUENCE OF"
5147 super(SequenceOf, self).__init__(
5155 schema = getattr(self, "schema", None)
5157 raise ValueError("schema must be specified")
5159 self._bound_min, self._bound_max = getattr(
5163 ) if bounds is None else bounds
5165 if value is not None:
5166 self._value = self._value_sanitize(value)
5167 if default is not None:
5168 default_value = self._value_sanitize(default)
5169 default_obj = self.__class__(
5174 default_obj._value = default_value
5175 self.default = default_obj
5177 self._value = default_obj.copy()._value
5179 def _value_sanitize(self, value):
5180 if issubclass(value.__class__, SequenceOf):
5181 value = value._value
5182 elif hasattr(value, "__iter__"):
5185 raise InvalidValueType((self.__class__, iter))
5186 if not self._bound_min <= len(value) <= self._bound_max:
5187 raise BoundsError(self._bound_min, len(value), self._bound_max)
5189 if not isinstance(v, self.spec.__class__):
5190 raise InvalidValueType((self.spec.__class__,))
5195 return all(v.ready for v in self._value)
5199 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5201 return any(v.bered for v in self._value)
5204 obj = self.__class__(schema=self.spec)
5205 obj._bound_min = self._bound_min
5206 obj._bound_max = self._bound_max
5208 obj._expl = self._expl
5209 obj.default = self.default
5210 obj.optional = self.optional
5211 obj.offset = self.offset
5212 obj.llen = self.llen
5213 obj.vlen = self.vlen
5214 obj.expl_lenindef = self.expl_lenindef
5215 obj.lenindef = self.lenindef
5216 obj.ber_encoded = self.ber_encoded
5217 obj._value = [v.copy() for v in self._value]
5220 def __eq__(self, their):
5221 if isinstance(their, self.__class__):
5223 self.spec == their.spec and
5224 self.tag == their.tag and
5225 self._expl == their._expl and
5226 self._value == their._value
5228 if hasattr(their, "__iter__"):
5229 return self._value == list(their)
5241 return self.__class__(
5245 (self._bound_min, self._bound_max)
5246 if bounds is None else bounds
5248 impl=self.tag if impl is None else impl,
5249 expl=self._expl if expl is None else expl,
5250 default=self.default if default is None else default,
5251 optional=self.optional if optional is None else optional,
5254 def __contains__(self, key):
5255 return key in self._value
5257 def append(self, value):
5258 if not isinstance(value, self.spec.__class__):
5259 raise InvalidValueType((self.spec.__class__,))
5260 if len(self._value) + 1 > self._bound_max:
5263 len(self._value) + 1,
5266 self._value.append(value)
5269 self._assert_ready()
5270 return iter(self._value)
5273 self._assert_ready()
5274 return len(self._value)
5276 def __setitem__(self, key, value):
5277 if not isinstance(value, self.spec.__class__):
5278 raise InvalidValueType((self.spec.__class__,))
5279 self._value[key] = self.spec(value=value)
5281 def __getitem__(self, key):
5282 return self._value[key]
5284 def _encoded_values(self):
5285 return [v.encode() for v in self._value]
5288 v = b"".join(self._encoded_values())
5289 return b"".join((self.tag, len_encode(len(v)), v))
5291 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5293 t, tlen, lv = tag_strip(tlv)
5294 except DecodeError as err:
5295 raise err.__class__(
5297 klass=self.__class__,
5298 decode_path=decode_path,
5303 klass=self.__class__,
5304 decode_path=decode_path,
5310 ctx_bered = ctx.get("bered", False)
5312 l, llen, v = len_decode(lv)
5313 except LenIndefForm as err:
5315 raise err.__class__(
5317 klass=self.__class__,
5318 decode_path=decode_path,
5321 l, llen, v = 0, 1, lv[1:]
5323 except DecodeError as err:
5324 raise err.__class__(
5326 klass=self.__class__,
5327 decode_path=decode_path,
5331 raise NotEnoughData(
5332 "encoded length is longer than data",
5333 klass=self.__class__,
5334 decode_path=decode_path,
5338 v, tail = v[:l], v[l:]
5340 sub_offset = offset + tlen + llen
5342 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5343 value_prev = memoryview(v[:0])
5347 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5349 sub_decode_path = decode_path + (str(len(_value)),)
5350 value, v_tail = spec.decode(
5354 decode_path=sub_decode_path,
5356 _ctx_immutable=False,
5358 value_len = value.fulllen
5360 if value_prev.tobytes() > v[:value_len].tobytes():
5361 if ctx_bered or ctx_allow_unordered_set:
5365 "unordered " + self.asn1_type_name,
5366 klass=self.__class__,
5367 decode_path=sub_decode_path,
5370 value_prev = v[:value_len]
5371 _value.append(value)
5372 sub_offset += value_len
5376 obj = self.__class__(
5379 bounds=(self._bound_min, self._bound_max),
5382 default=self.default,
5383 optional=self.optional,
5384 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5386 except BoundsError as err:
5389 klass=self.__class__,
5390 decode_path=decode_path,
5394 if v[:EOC_LEN].tobytes() != EOC:
5397 klass=self.__class__,
5398 decode_path=decode_path,
5403 obj.ber_encoded = ber_encoded
5408 pp_console_row(next(self.pps())),
5409 ", ".join(repr(v) for v in self._value),
5412 def pps(self, decode_path=()):
5415 asn1_type_name=self.asn1_type_name,
5416 obj_name=self.__class__.__name__,
5417 decode_path=decode_path,
5418 optional=self.optional,
5419 default=self == self.default,
5420 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5421 expl=None if self._expl is None else tag_decode(self._expl),
5426 expl_offset=self.expl_offset if self.expled else None,
5427 expl_tlen=self.expl_tlen if self.expled else None,
5428 expl_llen=self.expl_llen if self.expled else None,
5429 expl_vlen=self.expl_vlen if self.expled else None,
5430 expl_lenindef=self.expl_lenindef,
5431 lenindef=self.lenindef,
5432 ber_encoded=self.ber_encoded,
5435 for i, value in enumerate(self._value):
5436 yield value.pps(decode_path=decode_path + (str(i),))
5437 for pp in self.pps_lenindef(decode_path):
5441 class SetOf(SequenceOf):
5442 """``SET OF`` sequence type
5444 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5447 tag_default = tag_encode(form=TagFormConstructed, num=17)
5448 asn1_type_name = "SET OF"
5451 raws = self._encoded_values()
5454 return b"".join((self.tag, len_encode(len(v)), v))
5456 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5457 return super(SetOf, self)._decode(
5463 ordering_check=True,
5467 def obj_by_path(pypath): # pragma: no cover
5468 """Import object specified as string Python path
5470 Modules must be separated from classes/functions with ``:``.
5472 >>> obj_by_path("foo.bar:Baz")
5473 <class 'foo.bar.Baz'>
5474 >>> obj_by_path("foo.bar:Baz.boo")
5475 <classmethod 'foo.bar.Baz.boo'>
5477 mod, objs = pypath.rsplit(":", 1)
5478 from importlib import import_module
5479 obj = import_module(mod)
5480 for obj_name in objs.split("."):
5481 obj = getattr(obj, obj_name)
5485 def generic_decoder(): # pragma: no cover
5486 # All of this below is a big hack with self references
5487 choice = PrimitiveTypes()
5488 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5489 choice.specs["SetOf"] = SetOf(schema=choice)
5490 for i in six_xrange(31):
5491 choice.specs["SequenceOf%d" % i] = SequenceOf(
5495 choice.specs["Any"] = Any()
5497 # Class name equals to type name, to omit it from output
5498 class SEQUENCEOF(SequenceOf):
5506 with_decode_path=False,
5507 decode_path_only=(),
5509 def _pprint_pps(pps):
5511 if hasattr(pp, "_fields"):
5513 decode_path_only != () and
5514 pp.decode_path[:len(decode_path_only)] != decode_path_only
5517 if pp.asn1_type_name == Choice.asn1_type_name:
5519 pp_kwargs = pp._asdict()
5520 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5521 pp = _pp(**pp_kwargs)
5522 yield pp_console_row(
5527 with_colours=with_colours,
5528 with_decode_path=with_decode_path,
5529 decode_path_len_decrease=len(decode_path_only),
5531 for row in pp_console_blob(
5533 decode_path_len_decrease=len(decode_path_only),
5537 for row in _pprint_pps(pp):
5539 return "\n".join(_pprint_pps(obj.pps()))
5540 return SEQUENCEOF(), pprint_any
5543 def main(): # pragma: no cover
5545 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5546 parser.add_argument(
5550 help="Skip that number of bytes from the beginning",
5552 parser.add_argument(
5554 help="Python path to dictionary with OIDs",
5556 parser.add_argument(
5558 help="Python path to schema definition to use",
5560 parser.add_argument(
5561 "--defines-by-path",
5562 help="Python path to decoder's defines_by_path",
5564 parser.add_argument(
5566 action="store_true",
5567 help="Disallow BER encoding",
5569 parser.add_argument(
5570 "--print-decode-path",
5571 action="store_true",
5572 help="Print decode paths",
5574 parser.add_argument(
5575 "--decode-path-only",
5576 help="Print only specified decode path",
5578 parser.add_argument(
5580 action="store_true",
5581 help="Allow explicit tag out-of-bound",
5583 parser.add_argument(
5585 type=argparse.FileType("rb"),
5586 help="Path to DER file you want to decode",
5588 args = parser.parse_args()
5589 args.DERFile.seek(args.skip)
5590 der = memoryview(args.DERFile.read())
5591 args.DERFile.close()
5592 oids = obj_by_path(args.oids) if args.oids else {}
5594 schema = obj_by_path(args.schema)
5595 from functools import partial
5596 pprinter = partial(pprint, big_blobs=True)
5598 schema, pprinter = generic_decoder()
5600 "bered": not args.nobered,
5601 "allow_expl_oob": args.allow_expl_oob,
5603 if args.defines_by_path is not None:
5604 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5605 obj, tail = schema().decode(der, ctx=ctx)
5609 with_colours=True if environ.get("NO_COLOR") is None else False,
5610 with_decode_path=args.print_decode_path,
5612 () if args.decode_path_only is None else
5613 tuple(args.decode_path_only.split(":"))
5617 print("\nTrailing data: %s" % hexenc(tail))
5620 if __name__ == "__main__":