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)
3666 tag_default = tag_encode(23)
3668 asn1_type_name = "UTCTime"
3678 bounds=None, # dummy argument, workability for OctetString.decode
3681 :param value: set the value. Either datetime type, or
3682 :py:class:`pyderasn.UTCTime` object
3683 :param bytes impl: override default tag with ``IMPLICIT`` one
3684 :param bytes expl: override default tag with ``EXPLICIT`` one
3685 :param default: set default value. Type same as in ``value``
3686 :param bool optional: is object ``OPTIONAL`` in sequence
3688 super(UTCTime, self).__init__(
3696 if value is not None:
3697 self._value = self._value_sanitize(value)
3698 if default is not None:
3699 default = self._value_sanitize(default)
3700 self.default = self.__class__(
3705 if self._value is None:
3706 self._value = default
3708 def _strptime(self, value):
3709 # datetime.strptime's format: %y%m%d%H%M%SZ
3710 if len(value) != LEN_YYMMDDHHMMSSZ:
3711 raise ValueError("invalid UTCTime length")
3712 if value[-1] != "Z":
3713 raise ValueError("non UTC timezone")
3715 2000 + int(value[:2]), # %y
3716 int(value[2:4]), # %m
3717 int(value[4:6]), # %d
3718 int(value[6:8]), # %H
3719 int(value[8:10]), # %M
3720 int(value[10:12]), # %S
3723 def _value_sanitize(self, value):
3724 if isinstance(value, binary_type):
3726 value_decoded = value.decode("ascii")
3727 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3728 raise DecodeError("invalid UTCTime encoding")
3730 self._strptime(value_decoded)
3731 except (TypeError, ValueError) as err:
3732 raise DecodeError("invalid UTCTime format: %r" % err)
3734 if isinstance(value, self.__class__):
3736 if isinstance(value, datetime):
3737 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3738 raise InvalidValueType((self.__class__, datetime))
3740 def __eq__(self, their):
3741 if isinstance(their, binary_type):
3742 return self._value == their
3743 if isinstance(their, datetime):
3744 return self.todatetime() == their
3745 if not isinstance(their, self.__class__):
3748 self._value == their._value and
3749 self.tag == their.tag and
3750 self._expl == their._expl
3753 def todatetime(self):
3754 """Convert to datetime
3758 Pay attention that UTCTime can not hold full year, so all years
3759 having < 50 years are treated as 20xx, 19xx otherwise, according
3760 to X.509 recomendation.
3762 value = self._strptime(self._value.decode("ascii"))
3763 year = value.year % 100
3765 year=(2000 + year) if year < 50 else (1900 + year),
3769 minute=value.minute,
3770 second=value.second,
3774 return pp_console_row(next(self.pps()))
3776 def pps(self, decode_path=()):
3779 asn1_type_name=self.asn1_type_name,
3780 obj_name=self.__class__.__name__,
3781 decode_path=decode_path,
3782 value=self.todatetime().isoformat() if self.ready else None,
3783 optional=self.optional,
3784 default=self == self.default,
3785 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3786 expl=None if self._expl is None else tag_decode(self._expl),
3791 expl_offset=self.expl_offset if self.expled else None,
3792 expl_tlen=self.expl_tlen if self.expled else None,
3793 expl_llen=self.expl_llen if self.expled else None,
3794 expl_vlen=self.expl_vlen if self.expled else None,
3795 expl_lenindef=self.expl_lenindef,
3796 ber_encoded=self.ber_encoded,
3799 for pp in self.pps_lenindef(decode_path):
3803 class GeneralizedTime(UTCTime):
3804 """``GeneralizedTime`` datetime type
3806 This type is similar to :py:class:`pyderasn.UTCTime`.
3808 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3809 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3811 '20170930220750.000123Z'
3812 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3813 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3817 Only microsecond fractions are supported.
3818 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
3819 higher precision values.
3822 tag_default = tag_encode(24)
3823 asn1_type_name = "GeneralizedTime"
3825 def _strptime(self, value):
3827 if l == LEN_YYYYMMDDHHMMSSZ:
3828 # datetime.strptime's format: %y%m%d%H%M%SZ
3829 if value[-1] != "Z":
3830 raise ValueError("non UTC timezone")
3832 int(value[:4]), # %Y
3833 int(value[4:6]), # %m
3834 int(value[6:8]), # %d
3835 int(value[8:10]), # %H
3836 int(value[10:12]), # %M
3837 int(value[12:14]), # %S
3839 if l >= LEN_YYYYMMDDHHMMSSDMZ:
3840 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
3841 if value[-1] != "Z":
3842 raise ValueError("non UTC timezone")
3843 if value[14] != ".":
3844 raise ValueError("no fractions separator")
3847 raise ValueError("trailing zero")
3850 raise ValueError("only microsecond fractions are supported")
3851 us = int(us + ("0" * (6 - us_len)))
3853 int(value[:4]), # %Y
3854 int(value[4:6]), # %m
3855 int(value[6:8]), # %d
3856 int(value[8:10]), # %H
3857 int(value[10:12]), # %M
3858 int(value[12:14]), # %S
3862 raise ValueError("invalid GeneralizedTime length")
3864 def _value_sanitize(self, value):
3865 if isinstance(value, binary_type):
3867 value_decoded = value.decode("ascii")
3868 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3869 raise DecodeError("invalid GeneralizedTime encoding")
3871 self._strptime(value_decoded)
3872 except (TypeError, ValueError) as err:
3874 "invalid GeneralizedTime format: %r" % err,
3875 klass=self.__class__,
3878 if isinstance(value, self.__class__):
3880 if isinstance(value, datetime):
3881 encoded = value.strftime("%Y%m%d%H%M%S")
3882 if value.microsecond > 0:
3883 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
3884 return (encoded + "Z").encode("ascii")
3885 raise InvalidValueType((self.__class__, datetime))
3887 def todatetime(self):
3888 return self._strptime(self._value.decode("ascii"))
3891 class GraphicString(CommonString):
3893 tag_default = tag_encode(25)
3894 encoding = "iso-8859-1"
3895 asn1_type_name = "GraphicString"
3898 class VisibleString(CommonString):
3900 tag_default = tag_encode(26)
3902 asn1_type_name = "VisibleString"
3905 class ISO646String(VisibleString):
3907 asn1_type_name = "ISO646String"
3910 class GeneralString(CommonString):
3912 tag_default = tag_encode(27)
3913 encoding = "iso-8859-1"
3914 asn1_type_name = "GeneralString"
3917 class UniversalString(CommonString):
3919 tag_default = tag_encode(28)
3920 encoding = "utf-32-be"
3921 asn1_type_name = "UniversalString"
3924 class BMPString(CommonString):
3926 tag_default = tag_encode(30)
3927 encoding = "utf-16-be"
3928 asn1_type_name = "BMPString"
3932 """``CHOICE`` special type
3936 class GeneralName(Choice):
3938 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
3939 ("dNSName", IA5String(impl=tag_ctxp(2))),
3942 >>> gn = GeneralName()
3944 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
3945 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3946 >>> gn["dNSName"] = IA5String("bar.baz")
3947 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
3948 >>> gn["rfc822Name"]
3951 [2] IA5String IA5 bar.baz
3954 >>> gn.value == gn["dNSName"]
3957 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
3959 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
3960 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
3962 __slots__ = ("specs",)
3964 asn1_type_name = "CHOICE"
3977 :param value: set the value. Either ``(choice, value)`` tuple, or
3978 :py:class:`pyderasn.Choice` object
3979 :param bytes impl: can not be set, do **not** use it
3980 :param bytes expl: override default tag with ``EXPLICIT`` one
3981 :param default: set default value. Type same as in ``value``
3982 :param bool optional: is object ``OPTIONAL`` in sequence
3984 if impl is not None:
3985 raise ValueError("no implicit tag allowed for CHOICE")
3986 super(Choice, self).__init__(None, expl, default, optional, _decoded)
3988 schema = getattr(self, "schema", ())
3989 if len(schema) == 0:
3990 raise ValueError("schema must be specified")
3992 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
3995 if value is not None:
3996 self._value = self._value_sanitize(value)
3997 if default is not None:
3998 default_value = self._value_sanitize(default)
3999 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4000 default_obj.specs = self.specs
4001 default_obj._value = default_value
4002 self.default = default_obj
4004 self._value = default_obj.copy()._value
4006 def _value_sanitize(self, value):
4007 if isinstance(value, tuple) and len(value) == 2:
4009 spec = self.specs.get(choice)
4011 raise ObjUnknown(choice)
4012 if not isinstance(obj, spec.__class__):
4013 raise InvalidValueType((spec,))
4014 return (choice, spec(obj))
4015 if isinstance(value, self.__class__):
4017 raise InvalidValueType((self.__class__, tuple))
4021 return self._value is not None and self._value[1].ready
4025 return self.expl_lenindef or (
4026 (self._value is not None) and
4027 self._value[1].bered
4031 obj = self.__class__(schema=self.specs)
4032 obj._expl = self._expl
4033 obj.default = self.default
4034 obj.optional = self.optional
4035 obj.offset = self.offset
4036 obj.llen = self.llen
4037 obj.vlen = self.vlen
4038 obj.expl_lenindef = self.expl_lenindef
4039 obj.lenindef = self.lenindef
4040 obj.ber_encoded = self.ber_encoded
4042 if value is not None:
4043 obj._value = (value[0], value[1].copy())
4046 def __eq__(self, their):
4047 if isinstance(their, tuple) and len(their) == 2:
4048 return self._value == their
4049 if not isinstance(their, self.__class__):
4052 self.specs == their.specs and
4053 self._value == their._value
4063 return self.__class__(
4066 expl=self._expl if expl is None else expl,
4067 default=self.default if default is None else default,
4068 optional=self.optional if optional is None else optional,
4073 self._assert_ready()
4074 return self._value[0]
4078 self._assert_ready()
4079 return self._value[1]
4081 def __getitem__(self, key):
4082 if key not in self.specs:
4083 raise ObjUnknown(key)
4084 if self._value is None:
4086 choice, value = self._value
4091 def __setitem__(self, key, value):
4092 spec = self.specs.get(key)
4094 raise ObjUnknown(key)
4095 if not isinstance(value, spec.__class__):
4096 raise InvalidValueType((spec.__class__,))
4097 self._value = (key, spec(value))
4105 return self._value[1].decoded if self.ready else False
4108 self._assert_ready()
4109 return self._value[1].encode()
4111 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4112 for choice, spec in iteritems(self.specs):
4113 sub_decode_path = decode_path + (choice,)
4119 decode_path=sub_decode_path,
4122 _ctx_immutable=False,
4129 klass=self.__class__,
4130 decode_path=decode_path,
4133 if tag_only: # pragma: no cover
4135 value, tail = spec.decode(
4139 decode_path=sub_decode_path,
4141 _ctx_immutable=False,
4143 obj = self.__class__(
4146 default=self.default,
4147 optional=self.optional,
4148 _decoded=(offset, 0, value.fulllen),
4150 obj._value = (choice, value)
4154 value = pp_console_row(next(self.pps()))
4156 value = "%s[%r]" % (value, self.value)
4159 def pps(self, decode_path=()):
4162 asn1_type_name=self.asn1_type_name,
4163 obj_name=self.__class__.__name__,
4164 decode_path=decode_path,
4165 value=self.choice if self.ready else None,
4166 optional=self.optional,
4167 default=self == self.default,
4168 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4169 expl=None if self._expl is None else tag_decode(self._expl),
4174 expl_lenindef=self.expl_lenindef,
4178 yield self.value.pps(decode_path=decode_path + (self.choice,))
4179 for pp in self.pps_lenindef(decode_path):
4183 class PrimitiveTypes(Choice):
4184 """Predefined ``CHOICE`` for all generic primitive types
4186 It could be useful for general decoding of some unspecified values:
4188 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4189 OCTET STRING 3 bytes 666f6f
4190 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4194 schema = tuple((klass.__name__, klass()) for klass in (
4219 """``ANY`` special type
4221 >>> Any(Integer(-123))
4223 >>> a = Any(OctetString(b"hello world").encode())
4224 ANY 040b68656c6c6f20776f726c64
4225 >>> hexenc(bytes(a))
4226 b'0x040x0bhello world'
4228 __slots__ = ("defined",)
4229 tag_default = tag_encode(0)
4230 asn1_type_name = "ANY"
4240 :param value: set the value. Either any kind of pyderasn's
4241 **ready** object, or bytes. Pay attention that
4242 **no** validation is performed is raw binary value
4244 :param bytes expl: override default tag with ``EXPLICIT`` one
4245 :param bool optional: is object ``OPTIONAL`` in sequence
4247 super(Any, self).__init__(None, expl, None, optional, _decoded)
4248 self._value = None if value is None else self._value_sanitize(value)
4251 def _value_sanitize(self, value):
4252 if isinstance(value, binary_type):
4254 if isinstance(value, self.__class__):
4256 if isinstance(value, Obj):
4257 return value.encode()
4258 raise InvalidValueType((self.__class__, Obj, binary_type))
4262 return self._value is not None
4266 if self.expl_lenindef or self.lenindef:
4268 if self.defined is None:
4270 return self.defined[1].bered
4273 obj = self.__class__()
4274 obj._value = self._value
4276 obj._expl = self._expl
4277 obj.optional = self.optional
4278 obj.offset = self.offset
4279 obj.llen = self.llen
4280 obj.vlen = self.vlen
4281 obj.expl_lenindef = self.expl_lenindef
4282 obj.lenindef = self.lenindef
4283 obj.ber_encoded = self.ber_encoded
4286 def __eq__(self, their):
4287 if isinstance(their, binary_type):
4288 return self._value == their
4289 if issubclass(their.__class__, Any):
4290 return self._value == their._value
4299 return self.__class__(
4301 expl=self._expl if expl is None else expl,
4302 optional=self.optional if optional is None else optional,
4305 def __bytes__(self):
4306 self._assert_ready()
4314 self._assert_ready()
4317 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4319 t, tlen, lv = tag_strip(tlv)
4320 except DecodeError as err:
4321 raise err.__class__(
4323 klass=self.__class__,
4324 decode_path=decode_path,
4328 l, llen, v = len_decode(lv)
4329 except LenIndefForm as err:
4330 if not ctx.get("bered", False):
4331 raise err.__class__(
4333 klass=self.__class__,
4334 decode_path=decode_path,
4337 llen, vlen, v = 1, 0, lv[1:]
4338 sub_offset = offset + tlen + llen
4340 while v[:EOC_LEN].tobytes() != EOC:
4341 chunk, v = Any().decode(
4344 decode_path=decode_path + (str(chunk_i),),
4347 _ctx_immutable=False,
4349 vlen += chunk.tlvlen
4350 sub_offset += chunk.tlvlen
4352 tlvlen = tlen + llen + vlen + EOC_LEN
4353 obj = self.__class__(
4354 value=tlv[:tlvlen].tobytes(),
4356 optional=self.optional,
4357 _decoded=(offset, 0, tlvlen),
4361 return obj, v[EOC_LEN:]
4362 except DecodeError as err:
4363 raise err.__class__(
4365 klass=self.__class__,
4366 decode_path=decode_path,
4370 raise NotEnoughData(
4371 "encoded length is longer than data",
4372 klass=self.__class__,
4373 decode_path=decode_path,
4376 tlvlen = tlen + llen + l
4377 v, tail = tlv[:tlvlen], v[l:]
4378 obj = self.__class__(
4381 optional=self.optional,
4382 _decoded=(offset, 0, tlvlen),
4388 return pp_console_row(next(self.pps()))
4390 def pps(self, decode_path=()):
4393 asn1_type_name=self.asn1_type_name,
4394 obj_name=self.__class__.__name__,
4395 decode_path=decode_path,
4396 blob=self._value if self.ready else None,
4397 optional=self.optional,
4398 default=self == self.default,
4399 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4400 expl=None if self._expl is None else tag_decode(self._expl),
4405 expl_offset=self.expl_offset if self.expled else None,
4406 expl_tlen=self.expl_tlen if self.expled else None,
4407 expl_llen=self.expl_llen if self.expled else None,
4408 expl_vlen=self.expl_vlen if self.expled else None,
4409 expl_lenindef=self.expl_lenindef,
4410 lenindef=self.lenindef,
4413 defined_by, defined = self.defined or (None, None)
4414 if defined_by is not None:
4416 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4418 for pp in self.pps_lenindef(decode_path):
4422 ########################################################################
4423 # ASN.1 constructed types
4424 ########################################################################
4426 def get_def_by_path(defines_by_path, sub_decode_path):
4427 """Get define by decode path
4429 for path, define in defines_by_path:
4430 if len(path) != len(sub_decode_path):
4432 for p1, p2 in zip(path, sub_decode_path):
4433 if (p1 != any) and (p1 != p2):
4439 def abs_decode_path(decode_path, rel_path):
4440 """Create an absolute decode path from current and relative ones
4442 :param decode_path: current decode path, starting point. Tuple of strings
4443 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4444 If first tuple's element is "/", then treat it as
4445 an absolute path, ignoring ``decode_path`` as
4446 starting point. Also this tuple can contain ".."
4447 elements, stripping the leading element from
4450 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4451 ("foo", "bar", "baz", "whatever")
4452 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4454 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4457 if rel_path[0] == "/":
4459 if rel_path[0] == "..":
4460 return abs_decode_path(decode_path[:-1], rel_path[1:])
4461 return decode_path + rel_path
4464 class Sequence(Obj):
4465 """``SEQUENCE`` structure type
4467 You have to make specification of sequence::
4469 class Extension(Sequence):
4471 ("extnID", ObjectIdentifier()),
4472 ("critical", Boolean(default=False)),
4473 ("extnValue", OctetString()),
4476 Then, you can work with it as with dictionary.
4478 >>> ext = Extension()
4479 >>> Extension().specs
4481 ('extnID', OBJECT IDENTIFIER),
4482 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4483 ('extnValue', OCTET STRING),
4485 >>> ext["extnID"] = "1.2.3"
4486 Traceback (most recent call last):
4487 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4488 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4490 You can determine if sequence is ready to be encoded:
4495 Traceback (most recent call last):
4496 pyderasn.ObjNotReady: object is not ready: extnValue
4497 >>> ext["extnValue"] = OctetString(b"foobar")
4501 Value you want to assign, must have the same **type** as in
4502 corresponding specification, but it can have different tags,
4503 optional/default attributes -- they will be taken from specification
4506 class TBSCertificate(Sequence):
4508 ("version", Version(expl=tag_ctxc(0), default="v1")),
4511 >>> tbs = TBSCertificate()
4512 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4514 Assign ``None`` to remove value from sequence.
4516 You can set values in Sequence during its initialization:
4518 >>> AlgorithmIdentifier((
4519 ("algorithm", ObjectIdentifier("1.2.3")),
4520 ("parameters", Any(Null()))
4522 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4524 You can determine if value exists/set in the sequence and take its value:
4526 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4529 OBJECT IDENTIFIER 1.2.3
4531 But pay attention that if value has default, then it won't be (not
4532 in) in the sequence (because ``DEFAULT`` must not be encoded in
4533 DER), but you can read its value:
4535 >>> "critical" in ext, ext["critical"]
4536 (False, BOOLEAN False)
4537 >>> ext["critical"] = Boolean(True)
4538 >>> "critical" in ext, ext["critical"]
4539 (True, BOOLEAN True)
4541 All defaulted values are always optional.
4543 .. _allow_default_values_ctx:
4545 DER prohibits default value encoding and will raise an error if
4546 default value is unexpectedly met during decode.
4547 If :ref:`bered <bered_ctx>` context option is set, then no error
4548 will be raised, but ``bered`` attribute set. You can disable strict
4549 defaulted values existence validation by setting
4550 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4552 Two sequences are equal if they have equal specification (schema),
4553 implicit/explicit tagging and the same values.
4555 __slots__ = ("specs",)
4556 tag_default = tag_encode(form=TagFormConstructed, num=16)
4557 asn1_type_name = "SEQUENCE"
4569 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4571 schema = getattr(self, "schema", ())
4573 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4576 if value is not None:
4577 if issubclass(value.__class__, Sequence):
4578 self._value = value._value
4579 elif hasattr(value, "__iter__"):
4580 for seq_key, seq_value in value:
4581 self[seq_key] = seq_value
4583 raise InvalidValueType((Sequence,))
4584 if default is not None:
4585 if not issubclass(default.__class__, Sequence):
4586 raise InvalidValueType((Sequence,))
4587 default_value = default._value
4588 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4589 default_obj.specs = self.specs
4590 default_obj._value = default_value
4591 self.default = default_obj
4593 self._value = default_obj.copy()._value
4597 for name, spec in iteritems(self.specs):
4598 value = self._value.get(name)
4610 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4612 return any(value.bered for value in itervalues(self._value))
4615 obj = self.__class__(schema=self.specs)
4617 obj._expl = self._expl
4618 obj.default = self.default
4619 obj.optional = self.optional
4620 obj.offset = self.offset
4621 obj.llen = self.llen
4622 obj.vlen = self.vlen
4623 obj.expl_lenindef = self.expl_lenindef
4624 obj.lenindef = self.lenindef
4625 obj.ber_encoded = self.ber_encoded
4626 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4629 def __eq__(self, their):
4630 if not isinstance(their, self.__class__):
4633 self.specs == their.specs and
4634 self.tag == their.tag and
4635 self._expl == their._expl and
4636 self._value == their._value
4647 return self.__class__(
4650 impl=self.tag if impl is None else impl,
4651 expl=self._expl if expl is None else expl,
4652 default=self.default if default is None else default,
4653 optional=self.optional if optional is None else optional,
4656 def __contains__(self, key):
4657 return key in self._value
4659 def __setitem__(self, key, value):
4660 spec = self.specs.get(key)
4662 raise ObjUnknown(key)
4664 self._value.pop(key, None)
4666 if not isinstance(value, spec.__class__):
4667 raise InvalidValueType((spec.__class__,))
4668 value = spec(value=value)
4669 if spec.default is not None and value == spec.default:
4670 self._value.pop(key, None)
4672 self._value[key] = value
4674 def __getitem__(self, key):
4675 value = self._value.get(key)
4676 if value is not None:
4678 spec = self.specs.get(key)
4680 raise ObjUnknown(key)
4681 if spec.default is not None:
4685 def _encoded_values(self):
4687 for name, spec in iteritems(self.specs):
4688 value = self._value.get(name)
4692 raise ObjNotReady(name)
4693 raws.append(value.encode())
4697 v = b"".join(self._encoded_values())
4698 return b"".join((self.tag, len_encode(len(v)), v))
4700 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4702 t, tlen, lv = tag_strip(tlv)
4703 except DecodeError as err:
4704 raise err.__class__(
4706 klass=self.__class__,
4707 decode_path=decode_path,
4712 klass=self.__class__,
4713 decode_path=decode_path,
4716 if tag_only: # pragma: no cover
4719 ctx_bered = ctx.get("bered", False)
4721 l, llen, v = len_decode(lv)
4722 except LenIndefForm as err:
4724 raise err.__class__(
4726 klass=self.__class__,
4727 decode_path=decode_path,
4730 l, llen, v = 0, 1, lv[1:]
4732 except DecodeError as err:
4733 raise err.__class__(
4735 klass=self.__class__,
4736 decode_path=decode_path,
4740 raise NotEnoughData(
4741 "encoded length is longer than data",
4742 klass=self.__class__,
4743 decode_path=decode_path,
4747 v, tail = v[:l], v[l:]
4749 sub_offset = offset + tlen + llen
4752 ctx_allow_default_values = ctx.get("allow_default_values", False)
4753 for name, spec in iteritems(self.specs):
4754 if spec.optional and (
4755 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4759 sub_decode_path = decode_path + (name,)
4761 value, v_tail = spec.decode(
4765 decode_path=sub_decode_path,
4767 _ctx_immutable=False,
4774 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4775 if defined is not None:
4776 defined_by, defined_spec = defined
4777 if issubclass(value.__class__, SequenceOf):
4778 for i, _value in enumerate(value):
4779 sub_sub_decode_path = sub_decode_path + (
4781 DecodePathDefBy(defined_by),
4783 defined_value, defined_tail = defined_spec.decode(
4784 memoryview(bytes(_value)),
4786 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4787 if value.expled else (value.tlen + value.llen)
4790 decode_path=sub_sub_decode_path,
4792 _ctx_immutable=False,
4794 if len(defined_tail) > 0:
4797 klass=self.__class__,
4798 decode_path=sub_sub_decode_path,
4801 _value.defined = (defined_by, defined_value)
4803 defined_value, defined_tail = defined_spec.decode(
4804 memoryview(bytes(value)),
4806 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4807 if value.expled else (value.tlen + value.llen)
4810 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4812 _ctx_immutable=False,
4814 if len(defined_tail) > 0:
4817 klass=self.__class__,
4818 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4821 value.defined = (defined_by, defined_value)
4823 value_len = value.fulllen
4825 sub_offset += value_len
4827 if spec.default is not None and value == spec.default:
4828 if ctx_bered or ctx_allow_default_values:
4832 "DEFAULT value met",
4833 klass=self.__class__,
4834 decode_path=sub_decode_path,
4837 values[name] = value
4839 spec_defines = getattr(spec, "defines", ())
4840 if len(spec_defines) == 0:
4841 defines_by_path = ctx.get("defines_by_path", ())
4842 if len(defines_by_path) > 0:
4843 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4844 if spec_defines is not None and len(spec_defines) > 0:
4845 for rel_path, schema in spec_defines:
4846 defined = schema.get(value, None)
4847 if defined is not None:
4848 ctx.setdefault("_defines", []).append((
4849 abs_decode_path(sub_decode_path[:-1], rel_path),
4853 if v[:EOC_LEN].tobytes() != EOC:
4856 klass=self.__class__,
4857 decode_path=decode_path,
4865 klass=self.__class__,
4866 decode_path=decode_path,
4869 obj = self.__class__(
4873 default=self.default,
4874 optional=self.optional,
4875 _decoded=(offset, llen, vlen),
4878 obj.lenindef = lenindef
4879 obj.ber_encoded = ber_encoded
4883 value = pp_console_row(next(self.pps()))
4885 for name in self.specs:
4886 _value = self._value.get(name)
4889 cols.append("%s: %s" % (name, repr(_value)))
4890 return "%s[%s]" % (value, "; ".join(cols))
4892 def pps(self, decode_path=()):
4895 asn1_type_name=self.asn1_type_name,
4896 obj_name=self.__class__.__name__,
4897 decode_path=decode_path,
4898 optional=self.optional,
4899 default=self == self.default,
4900 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4901 expl=None if self._expl is None else tag_decode(self._expl),
4906 expl_offset=self.expl_offset if self.expled else None,
4907 expl_tlen=self.expl_tlen if self.expled else None,
4908 expl_llen=self.expl_llen if self.expled else None,
4909 expl_vlen=self.expl_vlen if self.expled else None,
4910 expl_lenindef=self.expl_lenindef,
4911 lenindef=self.lenindef,
4912 ber_encoded=self.ber_encoded,
4915 for name in self.specs:
4916 value = self._value.get(name)
4919 yield value.pps(decode_path=decode_path + (name,))
4920 for pp in self.pps_lenindef(decode_path):
4924 class Set(Sequence):
4925 """``SET`` structure type
4927 Its usage is identical to :py:class:`pyderasn.Sequence`.
4929 .. _allow_unordered_set_ctx:
4931 DER prohibits unordered values encoding and will raise an error
4932 during decode. If If :ref:`bered <bered_ctx>` context option is set,
4933 then no error will occure. Also you can disable strict values
4934 ordering check by setting ``"allow_unordered_set": True``
4935 :ref:`context <ctx>` option.
4938 tag_default = tag_encode(form=TagFormConstructed, num=17)
4939 asn1_type_name = "SET"
4942 raws = self._encoded_values()
4945 return b"".join((self.tag, len_encode(len(v)), v))
4947 def _specs_items(self):
4948 return iteritems(self.specs)
4950 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4952 t, tlen, lv = tag_strip(tlv)
4953 except DecodeError as err:
4954 raise err.__class__(
4956 klass=self.__class__,
4957 decode_path=decode_path,
4962 klass=self.__class__,
4963 decode_path=decode_path,
4969 ctx_bered = ctx.get("bered", False)
4971 l, llen, v = len_decode(lv)
4972 except LenIndefForm as err:
4974 raise err.__class__(
4976 klass=self.__class__,
4977 decode_path=decode_path,
4980 l, llen, v = 0, 1, lv[1:]
4982 except DecodeError as err:
4983 raise err.__class__(
4985 klass=self.__class__,
4986 decode_path=decode_path,
4990 raise NotEnoughData(
4991 "encoded length is longer than data",
4992 klass=self.__class__,
4996 v, tail = v[:l], v[l:]
4998 sub_offset = offset + tlen + llen
5001 ctx_allow_default_values = ctx.get("allow_default_values", False)
5002 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5003 value_prev = memoryview(v[:0])
5006 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5008 for name, spec in self._specs_items():
5009 sub_decode_path = decode_path + (name,)
5015 decode_path=sub_decode_path,
5018 _ctx_immutable=False,
5025 klass=self.__class__,
5026 decode_path=decode_path,
5029 value, v_tail = spec.decode(
5033 decode_path=sub_decode_path,
5035 _ctx_immutable=False,
5037 value_len = value.fulllen
5038 if value_prev.tobytes() > v[:value_len].tobytes():
5039 if ctx_bered or ctx_allow_unordered_set:
5043 "unordered " + self.asn1_type_name,
5044 klass=self.__class__,
5045 decode_path=sub_decode_path,
5048 if spec.default is None or value != spec.default:
5050 elif ctx_bered or ctx_allow_default_values:
5054 "DEFAULT value met",
5055 klass=self.__class__,
5056 decode_path=sub_decode_path,
5059 values[name] = value
5060 value_prev = v[:value_len]
5061 sub_offset += value_len
5064 obj = self.__class__(
5068 default=self.default,
5069 optional=self.optional,
5070 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5073 if v[:EOC_LEN].tobytes() != EOC:
5076 klass=self.__class__,
5077 decode_path=decode_path,
5085 "not all values are ready",
5086 klass=self.__class__,
5087 decode_path=decode_path,
5090 obj.ber_encoded = ber_encoded
5094 class SequenceOf(Obj):
5095 """``SEQUENCE OF`` sequence type
5097 For that kind of type you must specify the object it will carry on
5098 (bounds are for example here, not required)::
5100 class Ints(SequenceOf):
5105 >>> ints.append(Integer(123))
5106 >>> ints.append(Integer(234))
5108 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5109 >>> [int(i) for i in ints]
5111 >>> ints.append(Integer(345))
5112 Traceback (most recent call last):
5113 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5116 >>> ints[1] = Integer(345)
5118 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5120 Also you can initialize sequence with preinitialized values:
5122 >>> ints = Ints([Integer(123), Integer(234)])
5124 __slots__ = ("spec", "_bound_min", "_bound_max")
5125 tag_default = tag_encode(form=TagFormConstructed, num=16)
5126 asn1_type_name = "SEQUENCE OF"
5139 super(SequenceOf, self).__init__(
5147 schema = getattr(self, "schema", None)
5149 raise ValueError("schema must be specified")
5151 self._bound_min, self._bound_max = getattr(
5155 ) if bounds is None else bounds
5157 if value is not None:
5158 self._value = self._value_sanitize(value)
5159 if default is not None:
5160 default_value = self._value_sanitize(default)
5161 default_obj = self.__class__(
5166 default_obj._value = default_value
5167 self.default = default_obj
5169 self._value = default_obj.copy()._value
5171 def _value_sanitize(self, value):
5172 if issubclass(value.__class__, SequenceOf):
5173 value = value._value
5174 elif hasattr(value, "__iter__"):
5177 raise InvalidValueType((self.__class__, iter))
5178 if not self._bound_min <= len(value) <= self._bound_max:
5179 raise BoundsError(self._bound_min, len(value), self._bound_max)
5181 if not isinstance(v, self.spec.__class__):
5182 raise InvalidValueType((self.spec.__class__,))
5187 return all(v.ready for v in self._value)
5191 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5193 return any(v.bered for v in self._value)
5196 obj = self.__class__(schema=self.spec)
5197 obj._bound_min = self._bound_min
5198 obj._bound_max = self._bound_max
5200 obj._expl = self._expl
5201 obj.default = self.default
5202 obj.optional = self.optional
5203 obj.offset = self.offset
5204 obj.llen = self.llen
5205 obj.vlen = self.vlen
5206 obj.expl_lenindef = self.expl_lenindef
5207 obj.lenindef = self.lenindef
5208 obj.ber_encoded = self.ber_encoded
5209 obj._value = [v.copy() for v in self._value]
5212 def __eq__(self, their):
5213 if isinstance(their, self.__class__):
5215 self.spec == their.spec and
5216 self.tag == their.tag and
5217 self._expl == their._expl and
5218 self._value == their._value
5220 if hasattr(their, "__iter__"):
5221 return self._value == list(their)
5233 return self.__class__(
5237 (self._bound_min, self._bound_max)
5238 if bounds is None else bounds
5240 impl=self.tag if impl is None else impl,
5241 expl=self._expl if expl is None else expl,
5242 default=self.default if default is None else default,
5243 optional=self.optional if optional is None else optional,
5246 def __contains__(self, key):
5247 return key in self._value
5249 def append(self, value):
5250 if not isinstance(value, self.spec.__class__):
5251 raise InvalidValueType((self.spec.__class__,))
5252 if len(self._value) + 1 > self._bound_max:
5255 len(self._value) + 1,
5258 self._value.append(value)
5261 self._assert_ready()
5262 return iter(self._value)
5265 self._assert_ready()
5266 return len(self._value)
5268 def __setitem__(self, key, value):
5269 if not isinstance(value, self.spec.__class__):
5270 raise InvalidValueType((self.spec.__class__,))
5271 self._value[key] = self.spec(value=value)
5273 def __getitem__(self, key):
5274 return self._value[key]
5276 def _encoded_values(self):
5277 return [v.encode() for v in self._value]
5280 v = b"".join(self._encoded_values())
5281 return b"".join((self.tag, len_encode(len(v)), v))
5283 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5285 t, tlen, lv = tag_strip(tlv)
5286 except DecodeError as err:
5287 raise err.__class__(
5289 klass=self.__class__,
5290 decode_path=decode_path,
5295 klass=self.__class__,
5296 decode_path=decode_path,
5302 ctx_bered = ctx.get("bered", False)
5304 l, llen, v = len_decode(lv)
5305 except LenIndefForm as err:
5307 raise err.__class__(
5309 klass=self.__class__,
5310 decode_path=decode_path,
5313 l, llen, v = 0, 1, lv[1:]
5315 except DecodeError as err:
5316 raise err.__class__(
5318 klass=self.__class__,
5319 decode_path=decode_path,
5323 raise NotEnoughData(
5324 "encoded length is longer than data",
5325 klass=self.__class__,
5326 decode_path=decode_path,
5330 v, tail = v[:l], v[l:]
5332 sub_offset = offset + tlen + llen
5334 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5335 value_prev = memoryview(v[:0])
5339 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5341 sub_decode_path = decode_path + (str(len(_value)),)
5342 value, v_tail = spec.decode(
5346 decode_path=sub_decode_path,
5348 _ctx_immutable=False,
5350 value_len = value.fulllen
5352 if value_prev.tobytes() > v[:value_len].tobytes():
5353 if ctx_bered or ctx_allow_unordered_set:
5357 "unordered " + self.asn1_type_name,
5358 klass=self.__class__,
5359 decode_path=sub_decode_path,
5362 value_prev = v[:value_len]
5363 _value.append(value)
5364 sub_offset += value_len
5368 obj = self.__class__(
5371 bounds=(self._bound_min, self._bound_max),
5374 default=self.default,
5375 optional=self.optional,
5376 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5378 except BoundsError as err:
5381 klass=self.__class__,
5382 decode_path=decode_path,
5386 if v[:EOC_LEN].tobytes() != EOC:
5389 klass=self.__class__,
5390 decode_path=decode_path,
5395 obj.ber_encoded = ber_encoded
5400 pp_console_row(next(self.pps())),
5401 ", ".join(repr(v) for v in self._value),
5404 def pps(self, decode_path=()):
5407 asn1_type_name=self.asn1_type_name,
5408 obj_name=self.__class__.__name__,
5409 decode_path=decode_path,
5410 optional=self.optional,
5411 default=self == self.default,
5412 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5413 expl=None if self._expl is None else tag_decode(self._expl),
5418 expl_offset=self.expl_offset if self.expled else None,
5419 expl_tlen=self.expl_tlen if self.expled else None,
5420 expl_llen=self.expl_llen if self.expled else None,
5421 expl_vlen=self.expl_vlen if self.expled else None,
5422 expl_lenindef=self.expl_lenindef,
5423 lenindef=self.lenindef,
5424 ber_encoded=self.ber_encoded,
5427 for i, value in enumerate(self._value):
5428 yield value.pps(decode_path=decode_path + (str(i),))
5429 for pp in self.pps_lenindef(decode_path):
5433 class SetOf(SequenceOf):
5434 """``SET OF`` sequence type
5436 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5439 tag_default = tag_encode(form=TagFormConstructed, num=17)
5440 asn1_type_name = "SET OF"
5443 raws = self._encoded_values()
5446 return b"".join((self.tag, len_encode(len(v)), v))
5448 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5449 return super(SetOf, self)._decode(
5455 ordering_check=True,
5459 def obj_by_path(pypath): # pragma: no cover
5460 """Import object specified as string Python path
5462 Modules must be separated from classes/functions with ``:``.
5464 >>> obj_by_path("foo.bar:Baz")
5465 <class 'foo.bar.Baz'>
5466 >>> obj_by_path("foo.bar:Baz.boo")
5467 <classmethod 'foo.bar.Baz.boo'>
5469 mod, objs = pypath.rsplit(":", 1)
5470 from importlib import import_module
5471 obj = import_module(mod)
5472 for obj_name in objs.split("."):
5473 obj = getattr(obj, obj_name)
5477 def generic_decoder(): # pragma: no cover
5478 # All of this below is a big hack with self references
5479 choice = PrimitiveTypes()
5480 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5481 choice.specs["SetOf"] = SetOf(schema=choice)
5482 for i in six_xrange(31):
5483 choice.specs["SequenceOf%d" % i] = SequenceOf(
5487 choice.specs["Any"] = Any()
5489 # Class name equals to type name, to omit it from output
5490 class SEQUENCEOF(SequenceOf):
5498 with_decode_path=False,
5499 decode_path_only=(),
5501 def _pprint_pps(pps):
5503 if hasattr(pp, "_fields"):
5505 decode_path_only != () and
5506 pp.decode_path[:len(decode_path_only)] != decode_path_only
5509 if pp.asn1_type_name == Choice.asn1_type_name:
5511 pp_kwargs = pp._asdict()
5512 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5513 pp = _pp(**pp_kwargs)
5514 yield pp_console_row(
5519 with_colours=with_colours,
5520 with_decode_path=with_decode_path,
5521 decode_path_len_decrease=len(decode_path_only),
5523 for row in pp_console_blob(
5525 decode_path_len_decrease=len(decode_path_only),
5529 for row in _pprint_pps(pp):
5531 return "\n".join(_pprint_pps(obj.pps()))
5532 return SEQUENCEOF(), pprint_any
5535 def main(): # pragma: no cover
5537 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5538 parser.add_argument(
5542 help="Skip that number of bytes from the beginning",
5544 parser.add_argument(
5546 help="Python path to dictionary with OIDs",
5548 parser.add_argument(
5550 help="Python path to schema definition to use",
5552 parser.add_argument(
5553 "--defines-by-path",
5554 help="Python path to decoder's defines_by_path",
5556 parser.add_argument(
5558 action="store_true",
5559 help="Disallow BER encoding",
5561 parser.add_argument(
5562 "--print-decode-path",
5563 action="store_true",
5564 help="Print decode paths",
5566 parser.add_argument(
5567 "--decode-path-only",
5568 help="Print only specified decode path",
5570 parser.add_argument(
5572 action="store_true",
5573 help="Allow explicit tag out-of-bound",
5575 parser.add_argument(
5577 type=argparse.FileType("rb"),
5578 help="Path to DER file you want to decode",
5580 args = parser.parse_args()
5581 args.DERFile.seek(args.skip)
5582 der = memoryview(args.DERFile.read())
5583 args.DERFile.close()
5584 oids = obj_by_path(args.oids) if args.oids else {}
5586 schema = obj_by_path(args.schema)
5587 from functools import partial
5588 pprinter = partial(pprint, big_blobs=True)
5590 schema, pprinter = generic_decoder()
5592 "bered": not args.nobered,
5593 "allow_expl_oob": args.allow_expl_oob,
5595 if args.defines_by_path is not None:
5596 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5597 obj, tail = schema().decode(der, ctx=ctx)
5601 with_colours=True if environ.get("NO_COLOR") is None else False,
5602 with_decode_path=args.print_decode_path,
5604 () if args.decode_path_only is None else
5605 tuple(args.decode_path_only.split(":"))
5609 print("\nTrailing data: %s" % hexenc(tail))
5612 if __name__ == "__main__":