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
244 Example certificate::
246 >>> print(pprint(crt))
247 0 [1,3,1604] Certificate SEQUENCE
248 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
249 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
250 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
251 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
252 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
253 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
255 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
256 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
257 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
258 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
259 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
260 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
261 . . . . . . . 13:02:45:53
263 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
264 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
265 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
267 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
268 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
269 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
274 Let's parse that output, human::
276 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
277 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
278 0 1 2 3 4 5 6 7 8 9 10 11
282 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
288 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
294 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
299 Offset of the object, where its DER/BER encoding begins.
300 Pay attention that it does **not** include explicit tag.
302 If explicit tag exists, then this is its length (tag + encoded length).
304 Length of object's tag. For example CHOICE does not have its own tag,
307 Length of encoded length.
309 Length of encoded value.
311 Visual indentation to show the depth of object in the hierarchy.
313 Object's name inside SEQUENCE/CHOICE.
315 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
316 here. "IMPLICIT" is omitted.
318 Object's class name, if set. Omitted if it is just an ordinary simple
319 value (like with ``algorithm`` in example above).
323 Object's value, if set. Can consist of multiple words (like OCTET/BIT
324 STRINGs above). We see ``v3`` value in Version, because it is named.
325 ``rdnSequence`` is the choice of CHOICE type.
327 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
328 default one, specified in the schema.
330 Shows does object contains any kind of BER encoded data (possibly
331 Sequence holding BER-encoded underlying value).
333 Only applicable to BER encoded data. Indefinite length encoding mark.
335 Only applicable to BER encoded data. If object has BER-specific
336 encoding, then ``BER`` will be shown. It does not depend on indefinite
337 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
338 (and its derivatives), ``SET``, ``SET OF`` could be BERed.
346 ASN.1 structures often have ANY and OCTET STRING fields, that are
347 DEFINED BY some previously met ObjectIdentifier. This library provides
348 ability to specify mapping between some OID and field that must be
349 decoded with specific specification.
354 :py:class:`pyderasn.ObjectIdentifier` field inside
355 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
356 necessary for decoding structures. For example, CMS (:rfc:`5652`)
359 class ContentInfo(Sequence):
361 ("contentType", ContentType(defines=((("content",), {
362 id_digestedData: DigestedData(),
363 id_signedData: SignedData(),
365 ("content", Any(expl=tag_ctxc(0))),
368 ``contentType`` field tells that it defines that ``content`` must be
369 decoded with ``SignedData`` specification, if ``contentType`` equals to
370 ``id-signedData``. The same applies to ``DigestedData``. If
371 ``contentType`` contains unknown OID, then no automatic decoding is
374 You can specify multiple fields, that will be autodecoded -- that is why
375 ``defines`` kwarg is a sequence. You can specify defined field
376 relatively or absolutely to current decode path. For example ``defines``
377 for AlgorithmIdentifier of X.509's
378 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
382 id_ecPublicKey: ECParameters(),
383 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
385 (("..", "subjectPublicKey"), {
386 id_rsaEncryption: RSAPublicKey(),
387 id_GostR3410_2001: OctetString(),
391 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
392 autodecode its parameters inside SPKI's algorithm and its public key
395 Following types can be automatically decoded (DEFINED BY):
397 * :py:class:`pyderasn.Any`
398 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
399 * :py:class:`pyderasn.OctetString`
400 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
401 ``Any``/``BitString``/``OctetString``-s
403 When any of those fields is automatically decoded, then ``.defined``
404 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
405 was defined, ``value`` contains corresponding decoded value. For example
406 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
408 .. _defines_by_path_ctx:
410 defines_by_path context option
411 ______________________________
413 Sometimes you either can not or do not want to explicitly set *defines*
414 in the scheme. You can dynamically apply those definitions when calling
415 ``.decode()`` method.
417 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
418 value must be sequence of following tuples::
420 (decode_path, defines)
422 where ``decode_path`` is a tuple holding so-called decode path to the
423 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
424 ``defines``, holding exactly the same value as accepted in its keyword
427 For example, again for CMS, you want to automatically decode
428 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
429 structures it may hold. Also, automatically decode ``controlSequence``
432 content_info, tail = ContentInfo().decode(data, defines_by_path=(
435 ((("content",), {id_signedData: SignedData()}),),
440 DecodePathDefBy(id_signedData),
445 id_cct_PKIData: PKIData(),
446 id_cct_PKIResponse: PKIResponse(),
452 DecodePathDefBy(id_signedData),
455 DecodePathDefBy(id_cct_PKIResponse),
461 id_cmc_recipientNonce: RecipientNonce(),
462 id_cmc_senderNonce: SenderNonce(),
463 id_cmc_statusInfoV2: CMCStatusInfoV2(),
464 id_cmc_transactionId: TransactionId(),
469 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
470 First function is useful for path construction when some automatic
471 decoding is already done. ``any`` means literally any value it meet --
472 useful for SEQUENCE/SET OF-s.
479 By default PyDERASN accepts only DER encoded data. It always encodes to
480 DER. But you can optionally enable BER decoding with setting ``bered``
481 :ref:`context <ctx>` argument to True. Indefinite lengths and
482 constructed primitive types should be parsed successfully.
484 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
485 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
486 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``
488 * If object has an indefinite length encoding, then its ``lenindef``
489 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
490 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
492 * If object has an indefinite length encoded explicit tag, then
493 ``expl_lenindef`` is set to True.
494 * If object has either any of BER-related encoding (explicit tag
495 indefinite length, object's indefinite length, BER-encoding) or any
496 underlying component has that kind of encoding, then ``bered``
497 attribute is set to True. For example SignedData CMS can have
498 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
499 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
501 EOC (end-of-contents) token's length is taken in advance in object's
504 .. _allow_expl_oob_ctx:
506 Allow explicit tag out-of-bound
507 -------------------------------
509 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
510 one value, more than one object. If you set ``allow_expl_oob`` context
511 option to True, then no error will be raised and that invalid encoding
512 will be silently further processed. But pay attention that offsets and
513 lengths will be invalid in that case.
517 This option should be used only for skipping some decode errors, just
518 to see the decoded structure somehow.
525 .. autoclass:: pyderasn.Boolean
530 .. autoclass:: pyderasn.Integer
535 .. autoclass:: pyderasn.BitString
540 .. autoclass:: pyderasn.OctetString
545 .. autoclass:: pyderasn.Null
550 .. autoclass:: pyderasn.ObjectIdentifier
555 .. autoclass:: pyderasn.Enumerated
559 .. autoclass:: pyderasn.CommonString
563 .. autoclass:: pyderasn.NumericString
567 .. autoclass:: pyderasn.PrintableString
571 .. autoclass:: pyderasn.UTCTime
572 :members: __init__, todatetime
576 .. autoclass:: pyderasn.GeneralizedTime
583 .. autoclass:: pyderasn.Choice
588 .. autoclass:: PrimitiveTypes
592 .. autoclass:: pyderasn.Any
600 .. autoclass:: pyderasn.Sequence
605 .. autoclass:: pyderasn.Set
610 .. autoclass:: pyderasn.SequenceOf
615 .. autoclass:: pyderasn.SetOf
621 .. autofunction:: pyderasn.abs_decode_path
622 .. autofunction:: pyderasn.colonize_hex
623 .. autofunction:: pyderasn.hexenc
624 .. autofunction:: pyderasn.hexdec
625 .. autofunction:: pyderasn.tag_encode
626 .. autofunction:: pyderasn.tag_decode
627 .. autofunction:: pyderasn.tag_ctxp
628 .. autofunction:: pyderasn.tag_ctxc
629 .. autoclass:: pyderasn.Obj
630 .. autoclass:: pyderasn.DecodeError
632 .. autoclass:: pyderasn.NotEnoughData
633 .. autoclass:: pyderasn.LenIndefForm
634 .. autoclass:: pyderasn.TagMismatch
635 .. autoclass:: pyderasn.InvalidLength
636 .. autoclass:: pyderasn.InvalidOID
637 .. autoclass:: pyderasn.ObjUnknown
638 .. autoclass:: pyderasn.ObjNotReady
639 .. autoclass:: pyderasn.InvalidValueType
640 .. autoclass:: pyderasn.BoundsError
643 from codecs import getdecoder
644 from codecs import getencoder
645 from collections import namedtuple
646 from collections import OrderedDict
647 from copy import copy
648 from datetime import datetime
649 from math import ceil
650 from os import environ
651 from string import ascii_letters
652 from string import digits
654 from six import add_metaclass
655 from six import binary_type
656 from six import byte2int
657 from six import indexbytes
658 from six import int2byte
659 from six import integer_types
660 from six import iterbytes
661 from six import iteritems
662 from six import itervalues
664 from six import string_types
665 from six import text_type
666 from six import unichr as six_unichr
667 from six.moves import xrange as six_xrange
671 from termcolor import colored
672 except ImportError: # pragma: no cover
673 def colored(what, *args):
717 "TagClassApplication",
721 "TagFormConstructed",
732 TagClassUniversal = 0
733 TagClassApplication = 1 << 6
734 TagClassContext = 1 << 7
735 TagClassPrivate = 1 << 6 | 1 << 7
737 TagFormConstructed = 1 << 5
740 TagClassApplication: "APPLICATION ",
741 TagClassPrivate: "PRIVATE ",
742 TagClassUniversal: "UNIV ",
746 LENINDEF = b"\x80" # length indefinite mark
747 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
750 ########################################################################
752 ########################################################################
754 class ASN1Error(ValueError):
758 class DecodeError(ASN1Error):
759 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
761 :param str msg: reason of decode failing
762 :param klass: optional exact DecodeError inherited class (like
763 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
764 :py:exc:`InvalidLength`)
765 :param decode_path: tuple of strings. It contains human
766 readable names of the fields through which
767 decoding process has passed
768 :param int offset: binary offset where failure happened
770 super(DecodeError, self).__init__()
773 self.decode_path = decode_path
779 "" if self.klass is None else self.klass.__name__,
781 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
782 if len(self.decode_path) > 0 else ""
784 ("(at %d)" % self.offset) if self.offset > 0 else "",
790 return "%s(%s)" % (self.__class__.__name__, self)
793 class NotEnoughData(DecodeError):
797 class LenIndefForm(DecodeError):
801 class TagMismatch(DecodeError):
805 class InvalidLength(DecodeError):
809 class InvalidOID(DecodeError):
813 class ObjUnknown(ASN1Error):
814 def __init__(self, name):
815 super(ObjUnknown, self).__init__()
819 return "object is unknown: %s" % self.name
822 return "%s(%s)" % (self.__class__.__name__, self)
825 class ObjNotReady(ASN1Error):
826 def __init__(self, name):
827 super(ObjNotReady, self).__init__()
831 return "object is not ready: %s" % self.name
834 return "%s(%s)" % (self.__class__.__name__, self)
837 class InvalidValueType(ASN1Error):
838 def __init__(self, expected_types):
839 super(InvalidValueType, self).__init__()
840 self.expected_types = expected_types
843 return "invalid value type, expected: %s" % ", ".join(
844 [repr(t) for t in self.expected_types]
848 return "%s(%s)" % (self.__class__.__name__, self)
851 class BoundsError(ASN1Error):
852 def __init__(self, bound_min, value, bound_max):
853 super(BoundsError, self).__init__()
854 self.bound_min = bound_min
856 self.bound_max = bound_max
859 return "unsatisfied bounds: %s <= %s <= %s" % (
866 return "%s(%s)" % (self.__class__.__name__, self)
869 ########################################################################
871 ########################################################################
873 _hexdecoder = getdecoder("hex")
874 _hexencoder = getencoder("hex")
878 """Binary data to hexadecimal string convert
880 return _hexdecoder(data)[0]
884 """Hexadecimal string to binary data convert
886 return _hexencoder(data)[0].decode("ascii")
889 def int_bytes_len(num, byte_len=8):
892 return int(ceil(float(num.bit_length()) / byte_len))
895 def zero_ended_encode(num):
896 octets = bytearray(int_bytes_len(num, 7))
898 octets[i] = num & 0x7F
902 octets[i] = 0x80 | (num & 0x7F)
908 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
909 """Encode tag to binary form
911 :param int num: tag's number
912 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
913 :py:data:`pyderasn.TagClassContext`,
914 :py:data:`pyderasn.TagClassApplication`,
915 :py:data:`pyderasn.TagClassPrivate`)
916 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
917 :py:data:`pyderasn.TagFormConstructed`)
921 return int2byte(klass | form | num)
922 # [XX|X|11111][1.......][1.......] ... [0.......]
923 return int2byte(klass | form | 31) + zero_ended_encode(num)
927 """Decode tag from binary form
931 No validation is performed, assuming that it has already passed.
933 It returns tuple with three integers, as
934 :py:func:`pyderasn.tag_encode` accepts.
936 first_octet = byte2int(tag)
937 klass = first_octet & 0xC0
938 form = first_octet & 0x20
939 if first_octet & 0x1F < 0x1F:
940 return (klass, form, first_octet & 0x1F)
942 for octet in iterbytes(tag[1:]):
945 return (klass, form, num)
949 """Create CONTEXT PRIMITIVE tag
951 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
955 """Create CONTEXT CONSTRUCTED tag
957 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
961 """Take off tag from the data
963 :returns: (encoded tag, tag length, remaining data)
966 raise NotEnoughData("no data at all")
967 if byte2int(data) & 0x1F < 31:
968 return data[:1], 1, data[1:]
973 raise DecodeError("unfinished tag")
974 if indexbytes(data, i) & 0x80 == 0:
977 return data[:i], i, data[i:]
983 octets = bytearray(int_bytes_len(l) + 1)
984 octets[0] = 0x80 | (len(octets) - 1)
985 for i in six_xrange(len(octets) - 1, 0, -1):
991 def len_decode(data):
994 :returns: (decoded length, length's length, remaining data)
995 :raises LenIndefForm: if indefinite form encoding is met
998 raise NotEnoughData("no data at all")
999 first_octet = byte2int(data)
1000 if first_octet & 0x80 == 0:
1001 return first_octet, 1, data[1:]
1002 octets_num = first_octet & 0x7F
1003 if octets_num + 1 > len(data):
1004 raise NotEnoughData("encoded length is longer than data")
1006 raise LenIndefForm()
1007 if byte2int(data[1:]) == 0:
1008 raise DecodeError("leading zeros")
1010 for v in iterbytes(data[1:1 + octets_num]):
1013 raise DecodeError("long form instead of short one")
1014 return l, 1 + octets_num, data[1 + octets_num:]
1017 ########################################################################
1019 ########################################################################
1021 class AutoAddSlots(type):
1022 def __new__(mcs, name, bases, _dict):
1023 _dict["__slots__"] = _dict.get("__slots__", ())
1024 return type.__new__(mcs, name, bases, _dict)
1027 @add_metaclass(AutoAddSlots)
1029 """Common ASN.1 object class
1031 All ASN.1 types are inherited from it. It has metaclass that
1032 automatically adds ``__slots__`` to all inherited classes.
1056 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1057 self._expl = getattr(self, "expl", None) if expl is None else expl
1058 if self.tag != self.tag_default and self._expl is not None:
1059 raise ValueError("implicit and explicit tags can not be set simultaneously")
1060 if default is not None:
1062 self.optional = optional
1063 self.offset, self.llen, self.vlen = _decoded
1065 self.expl_lenindef = False
1066 self.lenindef = False
1067 self.ber_encoded = False
1070 def ready(self): # pragma: no cover
1071 """Is object ready to be encoded?
1073 raise NotImplementedError()
1075 def _assert_ready(self):
1077 raise ObjNotReady(self.__class__.__name__)
1081 """Is either object or any elements inside is BER encoded?
1083 return self.expl_lenindef or self.lenindef or self.ber_encoded
1087 """Is object decoded?
1089 return (self.llen + self.vlen) > 0
1091 def copy(self): # pragma: no cover
1092 """Make a copy of object, safe to be mutated
1094 raise NotImplementedError()
1098 return len(self.tag)
1102 return self.tlen + self.llen + self.vlen
1104 def __str__(self): # pragma: no cover
1105 return self.__bytes__() if PY2 else self.__unicode__()
1107 def __ne__(self, their):
1108 return not(self == their)
1110 def __gt__(self, their): # pragma: no cover
1111 return not(self < their)
1113 def __le__(self, their): # pragma: no cover
1114 return (self == their) or (self < their)
1116 def __ge__(self, their): # pragma: no cover
1117 return (self == their) or (self > their)
1119 def _encode(self): # pragma: no cover
1120 raise NotImplementedError()
1122 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1123 raise NotImplementedError()
1126 raw = self._encode()
1127 if self._expl is None:
1129 return b"".join((self._expl, len_encode(len(raw)), raw))
1139 _ctx_immutable=True,
1143 :param data: either binary or memoryview
1144 :param int offset: initial data's offset
1145 :param bool leavemm: do we need to leave memoryview of remaining
1146 data as is, or convert it to bytes otherwise
1147 :param ctx: optional :ref:`context <ctx>` governing decoding process
1148 :param tag_only: decode only the tag, without length and contents
1149 (used only in Choice and Set structures, trying to
1150 determine if tag satisfies the scheme)
1151 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1152 :returns: (Obj, remaining data)
1156 elif _ctx_immutable:
1158 tlv = memoryview(data)
1159 if self._expl is None:
1160 result = self._decode(
1163 decode_path=decode_path,
1172 t, tlen, lv = tag_strip(tlv)
1173 except DecodeError as err:
1174 raise err.__class__(
1176 klass=self.__class__,
1177 decode_path=decode_path,
1182 klass=self.__class__,
1183 decode_path=decode_path,
1187 l, llen, v = len_decode(lv)
1188 except LenIndefForm as err:
1189 if not ctx.get("bered", False):
1190 raise err.__class__(
1192 klass=self.__class__,
1193 decode_path=decode_path,
1197 offset += tlen + llen
1198 result = self._decode(
1201 decode_path=decode_path,
1205 if tag_only: # pragma: no cover
1208 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1209 if eoc_expected.tobytes() != EOC:
1212 klass=self.__class__,
1213 decode_path=decode_path,
1217 obj.expl_lenindef = True
1218 except DecodeError as err:
1219 raise err.__class__(
1221 klass=self.__class__,
1222 decode_path=decode_path,
1227 raise NotEnoughData(
1228 "encoded length is longer than data",
1229 klass=self.__class__,
1230 decode_path=decode_path,
1233 result = self._decode(
1235 offset=offset + tlen + llen,
1236 decode_path=decode_path,
1240 if tag_only: # pragma: no cover
1243 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1245 "explicit tag out-of-bound, longer than data",
1246 klass=self.__class__,
1247 decode_path=decode_path,
1250 return obj, (tail if leavemm else tail.tobytes())
1254 return self._expl is not None
1261 def expl_tlen(self):
1262 return len(self._expl)
1265 def expl_llen(self):
1266 if self.expl_lenindef:
1268 return len(len_encode(self.tlvlen))
1271 def expl_offset(self):
1272 return self.offset - self.expl_tlen - self.expl_llen
1275 def expl_vlen(self):
1279 def expl_tlvlen(self):
1280 return self.expl_tlen + self.expl_llen + self.expl_vlen
1283 def fulloffset(self):
1284 return self.expl_offset if self.expled else self.offset
1288 return self.expl_tlvlen if self.expled else self.tlvlen
1290 def pps_lenindef(self, decode_path):
1291 if self.lenindef and not (
1292 getattr(self, "defined", None) is not None and
1293 self.defined[1].lenindef
1296 asn1_type_name="EOC",
1298 decode_path=decode_path,
1300 self.offset + self.tlvlen -
1301 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1309 if self.expl_lenindef:
1311 asn1_type_name="EOC",
1312 obj_name="EXPLICIT",
1313 decode_path=decode_path,
1314 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1323 class DecodePathDefBy(object):
1324 """DEFINED BY representation inside decode path
1326 __slots__ = ("defined_by",)
1328 def __init__(self, defined_by):
1329 self.defined_by = defined_by
1331 def __ne__(self, their):
1332 return not(self == their)
1334 def __eq__(self, their):
1335 if not isinstance(their, self.__class__):
1337 return self.defined_by == their.defined_by
1340 return "DEFINED BY " + str(self.defined_by)
1343 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1346 ########################################################################
1348 ########################################################################
1350 PP = namedtuple("PP", (
1378 asn1_type_name="unknown",
1395 expl_lenindef=False,
1426 def _colourize(what, colour, with_colours, attrs=("bold",)):
1427 return colored(what, colour, attrs=attrs) if with_colours else what
1430 def colonize_hex(hexed):
1431 """Separate hexadecimal string with colons
1433 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1442 with_decode_path=False,
1443 decode_path_len_decrease=0,
1450 " " if pp.expl_offset is None else
1451 ("-%d" % (pp.offset - pp.expl_offset))
1453 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1455 col = _colourize(col, "red", with_colours, ())
1456 col += _colourize("B", "red", with_colours) if pp.bered else " "
1458 col = "[%d,%d,%4d]%s" % (
1462 LENINDEF_PP_CHAR if pp.lenindef else " "
1464 col = _colourize(col, "green", with_colours, ())
1466 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1467 if decode_path_len > 0:
1468 cols.append(" ." * decode_path_len)
1469 ent = pp.decode_path[-1]
1470 if isinstance(ent, DecodePathDefBy):
1471 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1472 value = str(ent.defined_by)
1474 oids is not None and
1475 ent.defined_by.asn1_type_name ==
1476 ObjectIdentifier.asn1_type_name and
1479 cols.append(_colourize("%s:" % oids[value], "green", with_colours))
1481 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1483 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1484 if pp.expl is not None:
1485 klass, _, num = pp.expl
1486 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1487 cols.append(_colourize(col, "blue", with_colours))
1488 if pp.impl is not None:
1489 klass, _, num = pp.impl
1490 col = "[%s%d]" % (TagClassReprs[klass], num)
1491 cols.append(_colourize(col, "blue", with_colours))
1492 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1493 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1495 cols.append(_colourize("BER", "red", with_colours))
1496 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1497 if pp.value is not None:
1499 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1501 oids is not None and
1502 pp.asn1_type_name == ObjectIdentifier.asn1_type_name and
1505 cols.append(_colourize("(%s)" % oids[value], "green", with_colours))
1506 if pp.asn1_type_name == Integer.asn1_type_name:
1507 hex_repr = hex(int(pp.obj._value))[2:].upper()
1508 if len(hex_repr) % 2 != 0:
1509 hex_repr = "0" + hex_repr
1510 cols.append(_colourize(
1511 "(%s)" % colonize_hex(hex_repr),
1516 if isinstance(pp.blob, binary_type):
1517 cols.append(hexenc(pp.blob))
1518 elif isinstance(pp.blob, tuple):
1519 cols.append(", ".join(pp.blob))
1521 cols.append(_colourize("OPTIONAL", "red", with_colours))
1523 cols.append(_colourize("DEFAULT", "red", with_colours))
1524 if with_decode_path:
1525 cols.append(_colourize(
1526 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1530 return " ".join(cols)
1533 def pp_console_blob(pp, decode_path_len_decrease=0):
1534 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1535 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1536 if decode_path_len > 0:
1537 cols.append(" ." * (decode_path_len + 1))
1538 if isinstance(pp.blob, binary_type):
1539 blob = hexenc(pp.blob).upper()
1540 for i in six_xrange(0, len(blob), 32):
1541 chunk = blob[i:i + 32]
1542 yield " ".join(cols + [colonize_hex(chunk)])
1543 elif isinstance(pp.blob, tuple):
1544 yield " ".join(cols + [", ".join(pp.blob)])
1552 with_decode_path=False,
1553 decode_path_only=(),
1555 """Pretty print object
1557 :param Obj obj: object you want to pretty print
1558 :param oids: ``OID <-> humand readable string`` dictionary. When OID
1559 from it is met, then its humand readable form is printed
1560 :param big_blobs: if large binary objects are met (like OctetString
1561 values), do we need to print them too, on separate
1563 :param with_colours: colourize output, if ``termcolor`` library
1565 :param with_decode_path: print decode path
1566 :param decode_path_only: print only that specified decode path
1568 def _pprint_pps(pps):
1570 if hasattr(pp, "_fields"):
1572 decode_path_only != () and
1574 str(p) for p in pp.decode_path[:len(decode_path_only)]
1575 ) != decode_path_only
1579 yield pp_console_row(
1584 with_colours=with_colours,
1585 with_decode_path=with_decode_path,
1586 decode_path_len_decrease=len(decode_path_only),
1588 for row in pp_console_blob(
1590 decode_path_len_decrease=len(decode_path_only),
1594 yield pp_console_row(
1599 with_colours=with_colours,
1600 with_decode_path=with_decode_path,
1601 decode_path_len_decrease=len(decode_path_only),
1604 for row in _pprint_pps(pp):
1606 return "\n".join(_pprint_pps(obj.pps()))
1609 ########################################################################
1610 # ASN.1 primitive types
1611 ########################################################################
1614 """``BOOLEAN`` boolean type
1616 >>> b = Boolean(True)
1618 >>> b == Boolean(True)
1624 tag_default = tag_encode(1)
1625 asn1_type_name = "BOOLEAN"
1637 :param value: set the value. Either boolean type, or
1638 :py:class:`pyderasn.Boolean` object
1639 :param bytes impl: override default tag with ``IMPLICIT`` one
1640 :param bytes expl: override default tag with ``EXPLICIT`` one
1641 :param default: set default value. Type same as in ``value``
1642 :param bool optional: is object ``OPTIONAL`` in sequence
1644 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1645 self._value = None if value is None else self._value_sanitize(value)
1646 if default is not None:
1647 default = self._value_sanitize(default)
1648 self.default = self.__class__(
1654 self._value = default
1656 def _value_sanitize(self, value):
1657 if isinstance(value, bool):
1659 if issubclass(value.__class__, Boolean):
1661 raise InvalidValueType((self.__class__, bool))
1665 return self._value is not None
1668 obj = self.__class__()
1669 obj._value = self._value
1671 obj._expl = self._expl
1672 obj.default = self.default
1673 obj.optional = self.optional
1674 obj.offset = self.offset
1675 obj.llen = self.llen
1676 obj.vlen = self.vlen
1677 obj.expl_lenindef = self.expl_lenindef
1678 obj.lenindef = self.lenindef
1679 obj.ber_encoded = self.ber_encoded
1682 def __nonzero__(self):
1683 self._assert_ready()
1687 self._assert_ready()
1690 def __eq__(self, their):
1691 if isinstance(their, bool):
1692 return self._value == their
1693 if not issubclass(their.__class__, Boolean):
1696 self._value == their._value and
1697 self.tag == their.tag and
1698 self._expl == their._expl
1709 return self.__class__(
1711 impl=self.tag if impl is None else impl,
1712 expl=self._expl if expl is None else expl,
1713 default=self.default if default is None else default,
1714 optional=self.optional if optional is None else optional,
1718 self._assert_ready()
1722 (b"\xFF" if self._value else b"\x00"),
1725 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1727 t, _, lv = tag_strip(tlv)
1728 except DecodeError as err:
1729 raise err.__class__(
1731 klass=self.__class__,
1732 decode_path=decode_path,
1737 klass=self.__class__,
1738 decode_path=decode_path,
1744 l, _, v = len_decode(lv)
1745 except DecodeError as err:
1746 raise err.__class__(
1748 klass=self.__class__,
1749 decode_path=decode_path,
1753 raise InvalidLength(
1754 "Boolean's length must be equal to 1",
1755 klass=self.__class__,
1756 decode_path=decode_path,
1760 raise NotEnoughData(
1761 "encoded length is longer than data",
1762 klass=self.__class__,
1763 decode_path=decode_path,
1766 first_octet = byte2int(v)
1768 if first_octet == 0:
1770 elif first_octet == 0xFF:
1772 elif ctx.get("bered", False):
1777 "unacceptable Boolean value",
1778 klass=self.__class__,
1779 decode_path=decode_path,
1782 obj = self.__class__(
1786 default=self.default,
1787 optional=self.optional,
1788 _decoded=(offset, 1, 1),
1790 obj.ber_encoded = ber_encoded
1794 return pp_console_row(next(self.pps()))
1796 def pps(self, decode_path=()):
1799 asn1_type_name=self.asn1_type_name,
1800 obj_name=self.__class__.__name__,
1801 decode_path=decode_path,
1802 value=str(self._value) if self.ready else None,
1803 optional=self.optional,
1804 default=self == self.default,
1805 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1806 expl=None if self._expl is None else tag_decode(self._expl),
1811 expl_offset=self.expl_offset if self.expled else None,
1812 expl_tlen=self.expl_tlen if self.expled else None,
1813 expl_llen=self.expl_llen if self.expled else None,
1814 expl_vlen=self.expl_vlen if self.expled else None,
1815 expl_lenindef=self.expl_lenindef,
1816 ber_encoded=self.ber_encoded,
1819 for pp in self.pps_lenindef(decode_path):
1824 """``INTEGER`` integer type
1826 >>> b = Integer(-123)
1828 >>> b == Integer(-123)
1833 >>> Integer(2, bounds=(1, 3))
1835 >>> Integer(5, bounds=(1, 3))
1836 Traceback (most recent call last):
1837 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1841 class Version(Integer):
1848 >>> v = Version("v1")
1855 {'v3': 2, 'v1': 0, 'v2': 1}
1857 __slots__ = ("specs", "_bound_min", "_bound_max")
1858 tag_default = tag_encode(2)
1859 asn1_type_name = "INTEGER"
1873 :param value: set the value. Either integer type, named value
1874 (if ``schema`` is specified in the class), or
1875 :py:class:`pyderasn.Integer` object
1876 :param bounds: set ``(MIN, MAX)`` value constraint.
1877 (-inf, +inf) by default
1878 :param bytes impl: override default tag with ``IMPLICIT`` one
1879 :param bytes expl: override default tag with ``EXPLICIT`` one
1880 :param default: set default value. Type same as in ``value``
1881 :param bool optional: is object ``OPTIONAL`` in sequence
1883 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1885 specs = getattr(self, "schema", {}) if _specs is None else _specs
1886 self.specs = specs if isinstance(specs, dict) else dict(specs)
1887 self._bound_min, self._bound_max = getattr(
1890 (float("-inf"), float("+inf")),
1891 ) if bounds is None else bounds
1892 if value is not None:
1893 self._value = self._value_sanitize(value)
1894 if default is not None:
1895 default = self._value_sanitize(default)
1896 self.default = self.__class__(
1902 if self._value is None:
1903 self._value = default
1905 def _value_sanitize(self, value):
1906 if isinstance(value, integer_types):
1908 elif issubclass(value.__class__, Integer):
1909 value = value._value
1910 elif isinstance(value, str):
1911 value = self.specs.get(value)
1913 raise ObjUnknown("integer value: %s" % value)
1915 raise InvalidValueType((self.__class__, int, str))
1916 if not self._bound_min <= value <= self._bound_max:
1917 raise BoundsError(self._bound_min, value, self._bound_max)
1922 return self._value is not None
1925 obj = self.__class__(_specs=self.specs)
1926 obj._value = self._value
1927 obj._bound_min = self._bound_min
1928 obj._bound_max = self._bound_max
1930 obj._expl = self._expl
1931 obj.default = self.default
1932 obj.optional = self.optional
1933 obj.offset = self.offset
1934 obj.llen = self.llen
1935 obj.vlen = self.vlen
1936 obj.expl_lenindef = self.expl_lenindef
1937 obj.lenindef = self.lenindef
1938 obj.ber_encoded = self.ber_encoded
1942 self._assert_ready()
1943 return int(self._value)
1946 self._assert_ready()
1949 bytes(self._expl or b"") +
1950 str(self._value).encode("ascii"),
1953 def __eq__(self, their):
1954 if isinstance(their, integer_types):
1955 return self._value == their
1956 if not issubclass(their.__class__, Integer):
1959 self._value == their._value and
1960 self.tag == their.tag and
1961 self._expl == their._expl
1964 def __lt__(self, their):
1965 return self._value < their._value
1969 for name, value in iteritems(self.specs):
1970 if value == self._value:
1982 return self.__class__(
1985 (self._bound_min, self._bound_max)
1986 if bounds is None else bounds
1988 impl=self.tag if impl is None else impl,
1989 expl=self._expl if expl is None else expl,
1990 default=self.default if default is None else default,
1991 optional=self.optional if optional is None else optional,
1996 self._assert_ready()
2000 octets = bytearray([0])
2004 octets = bytearray()
2006 octets.append((value & 0xFF) ^ 0xFF)
2008 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2011 octets = bytearray()
2013 octets.append(value & 0xFF)
2015 if octets[-1] & 0x80 > 0:
2018 octets = bytes(octets)
2020 bytes_len = ceil(value.bit_length() / 8) or 1
2023 octets = value.to_bytes(
2028 except OverflowError:
2032 return b"".join((self.tag, len_encode(len(octets)), octets))
2034 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2036 t, _, lv = tag_strip(tlv)
2037 except DecodeError as err:
2038 raise err.__class__(
2040 klass=self.__class__,
2041 decode_path=decode_path,
2046 klass=self.__class__,
2047 decode_path=decode_path,
2053 l, llen, v = len_decode(lv)
2054 except DecodeError as err:
2055 raise err.__class__(
2057 klass=self.__class__,
2058 decode_path=decode_path,
2062 raise NotEnoughData(
2063 "encoded length is longer than data",
2064 klass=self.__class__,
2065 decode_path=decode_path,
2069 raise NotEnoughData(
2071 klass=self.__class__,
2072 decode_path=decode_path,
2075 v, tail = v[:l], v[l:]
2076 first_octet = byte2int(v)
2078 second_octet = byte2int(v[1:])
2080 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2081 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2084 "non normalized integer",
2085 klass=self.__class__,
2086 decode_path=decode_path,
2091 if first_octet & 0x80 > 0:
2092 octets = bytearray()
2093 for octet in bytearray(v):
2094 octets.append(octet ^ 0xFF)
2095 for octet in octets:
2096 value = (value << 8) | octet
2100 for octet in bytearray(v):
2101 value = (value << 8) | octet
2103 value = int.from_bytes(v, byteorder="big", signed=True)
2105 obj = self.__class__(
2107 bounds=(self._bound_min, self._bound_max),
2110 default=self.default,
2111 optional=self.optional,
2113 _decoded=(offset, llen, l),
2115 except BoundsError as err:
2118 klass=self.__class__,
2119 decode_path=decode_path,
2125 return pp_console_row(next(self.pps()))
2127 def pps(self, decode_path=()):
2130 asn1_type_name=self.asn1_type_name,
2131 obj_name=self.__class__.__name__,
2132 decode_path=decode_path,
2133 value=(self.named or str(self._value)) if self.ready else None,
2134 optional=self.optional,
2135 default=self == self.default,
2136 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2137 expl=None if self._expl is None else tag_decode(self._expl),
2142 expl_offset=self.expl_offset if self.expled else None,
2143 expl_tlen=self.expl_tlen if self.expled else None,
2144 expl_llen=self.expl_llen if self.expled else None,
2145 expl_vlen=self.expl_vlen if self.expled else None,
2146 expl_lenindef=self.expl_lenindef,
2149 for pp in self.pps_lenindef(decode_path):
2153 SET01 = frozenset(("0", "1"))
2156 class BitString(Obj):
2157 """``BIT STRING`` bit string type
2159 >>> BitString(b"hello world")
2160 BIT STRING 88 bits 68656c6c6f20776f726c64
2163 >>> b == b"hello world"
2168 >>> BitString("'0A3B5F291CD'H")
2169 BIT STRING 44 bits 0a3b5f291cd0
2170 >>> b = BitString("'010110000000'B")
2171 BIT STRING 12 bits 5800
2174 >>> b[0], b[1], b[2], b[3]
2175 (False, True, False, True)
2179 [False, True, False, True, True, False, False, False, False, False, False, False]
2183 class KeyUsage(BitString):
2185 ("digitalSignature", 0),
2186 ("nonRepudiation", 1),
2187 ("keyEncipherment", 2),
2190 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2191 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2193 ['nonRepudiation', 'keyEncipherment']
2195 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2199 Pay attention that BIT STRING can be encoded both in primitive
2200 and constructed forms. Decoder always checks constructed form tag
2201 additionally to specified primitive one. If BER decoding is
2202 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2203 of DER restrictions.
2205 __slots__ = ("tag_constructed", "specs", "defined")
2206 tag_default = tag_encode(3)
2207 asn1_type_name = "BIT STRING"
2220 :param value: set the value. Either binary type, tuple of named
2221 values (if ``schema`` is specified in the class),
2222 string in ``'XXX...'B`` form, or
2223 :py:class:`pyderasn.BitString` object
2224 :param bytes impl: override default tag with ``IMPLICIT`` one
2225 :param bytes expl: override default tag with ``EXPLICIT`` one
2226 :param default: set default value. Type same as in ``value``
2227 :param bool optional: is object ``OPTIONAL`` in sequence
2229 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2230 specs = getattr(self, "schema", {}) if _specs is None else _specs
2231 self.specs = specs if isinstance(specs, dict) else dict(specs)
2232 self._value = None if value is None else self._value_sanitize(value)
2233 if default is not None:
2234 default = self._value_sanitize(default)
2235 self.default = self.__class__(
2241 self._value = default
2243 tag_klass, _, tag_num = tag_decode(self.tag)
2244 self.tag_constructed = tag_encode(
2246 form=TagFormConstructed,
2250 def _bits2octets(self, bits):
2251 if len(self.specs) > 0:
2252 bits = bits.rstrip("0")
2254 bits += "0" * ((8 - (bit_len % 8)) % 8)
2255 octets = bytearray(len(bits) // 8)
2256 for i in six_xrange(len(octets)):
2257 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2258 return bit_len, bytes(octets)
2260 def _value_sanitize(self, value):
2261 if isinstance(value, (string_types, binary_type)):
2263 isinstance(value, string_types) and
2264 value.startswith("'")
2266 if value.endswith("'B"):
2268 if not frozenset(value) <= SET01:
2269 raise ValueError("B's coding contains unacceptable chars")
2270 return self._bits2octets(value)
2271 elif value.endswith("'H"):
2275 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2277 if isinstance(value, binary_type):
2278 return (len(value) * 8, value)
2280 raise InvalidValueType((self.__class__, string_types, binary_type))
2281 if isinstance(value, tuple):
2284 isinstance(value[0], integer_types) and
2285 isinstance(value[1], binary_type)
2290 bit = self.specs.get(name)
2292 raise ObjUnknown("BitString value: %s" % name)
2295 return self._bits2octets("")
2296 bits = frozenset(bits)
2297 return self._bits2octets("".join(
2298 ("1" if bit in bits else "0")
2299 for bit in six_xrange(max(bits) + 1)
2301 if issubclass(value.__class__, BitString):
2303 raise InvalidValueType((self.__class__, binary_type, string_types))
2307 return self._value is not None
2310 obj = self.__class__(_specs=self.specs)
2312 if value is not None:
2313 value = (value[0], value[1])
2316 obj._expl = self._expl
2317 obj.default = self.default
2318 obj.optional = self.optional
2319 obj.offset = self.offset
2320 obj.llen = self.llen
2321 obj.vlen = self.vlen
2322 obj.expl_lenindef = self.expl_lenindef
2323 obj.lenindef = self.lenindef
2324 obj.ber_encoded = self.ber_encoded
2328 self._assert_ready()
2329 for i in six_xrange(self._value[0]):
2334 self._assert_ready()
2335 return self._value[0]
2337 def __bytes__(self):
2338 self._assert_ready()
2339 return self._value[1]
2341 def __eq__(self, their):
2342 if isinstance(their, bytes):
2343 return self._value[1] == their
2344 if not issubclass(their.__class__, BitString):
2347 self._value == their._value and
2348 self.tag == their.tag and
2349 self._expl == their._expl
2354 return [name for name, bit in iteritems(self.specs) if self[bit]]
2364 return self.__class__(
2366 impl=self.tag if impl is None else impl,
2367 expl=self._expl if expl is None else expl,
2368 default=self.default if default is None else default,
2369 optional=self.optional if optional is None else optional,
2373 def __getitem__(self, key):
2374 if isinstance(key, int):
2375 bit_len, octets = self._value
2379 byte2int(memoryview(octets)[key // 8:]) >>
2382 if isinstance(key, string_types):
2383 value = self.specs.get(key)
2385 raise ObjUnknown("BitString value: %s" % key)
2387 raise InvalidValueType((int, str))
2390 self._assert_ready()
2391 bit_len, octets = self._value
2394 len_encode(len(octets) + 1),
2395 int2byte((8 - bit_len % 8) % 8),
2399 def _decode_chunk(self, lv, offset, decode_path, ctx):
2401 l, llen, v = len_decode(lv)
2402 except DecodeError as err:
2403 raise err.__class__(
2405 klass=self.__class__,
2406 decode_path=decode_path,
2410 raise NotEnoughData(
2411 "encoded length is longer than data",
2412 klass=self.__class__,
2413 decode_path=decode_path,
2417 raise NotEnoughData(
2419 klass=self.__class__,
2420 decode_path=decode_path,
2423 pad_size = byte2int(v)
2424 if l == 1 and pad_size != 0:
2426 "invalid empty value",
2427 klass=self.__class__,
2428 decode_path=decode_path,
2434 klass=self.__class__,
2435 decode_path=decode_path,
2438 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2441 klass=self.__class__,
2442 decode_path=decode_path,
2445 v, tail = v[:l], v[l:]
2446 obj = self.__class__(
2447 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2450 default=self.default,
2451 optional=self.optional,
2453 _decoded=(offset, llen, l),
2457 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2459 t, tlen, lv = tag_strip(tlv)
2460 except DecodeError as err:
2461 raise err.__class__(
2463 klass=self.__class__,
2464 decode_path=decode_path,
2468 if tag_only: # pragma: no cover
2470 return self._decode_chunk(lv, offset, decode_path, ctx)
2471 if t == self.tag_constructed:
2472 if not ctx.get("bered", False):
2474 "unallowed BER constructed encoding",
2475 klass=self.__class__,
2476 decode_path=decode_path,
2479 if tag_only: # pragma: no cover
2483 l, llen, v = len_decode(lv)
2484 except LenIndefForm:
2485 llen, l, v = 1, 0, lv[1:]
2487 except DecodeError as err:
2488 raise err.__class__(
2490 klass=self.__class__,
2491 decode_path=decode_path,
2495 raise NotEnoughData(
2496 "encoded length is longer than data",
2497 klass=self.__class__,
2498 decode_path=decode_path,
2501 if not lenindef and l == 0:
2502 raise NotEnoughData(
2504 klass=self.__class__,
2505 decode_path=decode_path,
2509 sub_offset = offset + tlen + llen
2513 if v[:EOC_LEN].tobytes() == EOC:
2520 "chunk out of bounds",
2521 klass=self.__class__,
2522 decode_path=decode_path + (str(len(chunks) - 1),),
2523 offset=chunks[-1].offset,
2525 sub_decode_path = decode_path + (str(len(chunks)),)
2527 chunk, v_tail = BitString().decode(
2530 decode_path=sub_decode_path,
2533 _ctx_immutable=False,
2537 "expected BitString encoded chunk",
2538 klass=self.__class__,
2539 decode_path=sub_decode_path,
2542 chunks.append(chunk)
2543 sub_offset += chunk.tlvlen
2544 vlen += chunk.tlvlen
2546 if len(chunks) == 0:
2549 klass=self.__class__,
2550 decode_path=decode_path,
2555 for chunk_i, chunk in enumerate(chunks[:-1]):
2556 if chunk.bit_len % 8 != 0:
2558 "BitString chunk is not multiple of 8 bits",
2559 klass=self.__class__,
2560 decode_path=decode_path + (str(chunk_i),),
2561 offset=chunk.offset,
2563 values.append(bytes(chunk))
2564 bit_len += chunk.bit_len
2565 chunk_last = chunks[-1]
2566 values.append(bytes(chunk_last))
2567 bit_len += chunk_last.bit_len
2568 obj = self.__class__(
2569 value=(bit_len, b"".join(values)),
2572 default=self.default,
2573 optional=self.optional,
2575 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2577 obj.lenindef = lenindef
2578 obj.ber_encoded = True
2579 return obj, (v[EOC_LEN:] if lenindef else v)
2581 klass=self.__class__,
2582 decode_path=decode_path,
2587 return pp_console_row(next(self.pps()))
2589 def pps(self, decode_path=()):
2593 bit_len, blob = self._value
2594 value = "%d bits" % bit_len
2595 if len(self.specs) > 0:
2596 blob = tuple(self.named)
2599 asn1_type_name=self.asn1_type_name,
2600 obj_name=self.__class__.__name__,
2601 decode_path=decode_path,
2604 optional=self.optional,
2605 default=self == self.default,
2606 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2607 expl=None if self._expl is None else tag_decode(self._expl),
2612 expl_offset=self.expl_offset if self.expled else None,
2613 expl_tlen=self.expl_tlen if self.expled else None,
2614 expl_llen=self.expl_llen if self.expled else None,
2615 expl_vlen=self.expl_vlen if self.expled else None,
2616 expl_lenindef=self.expl_lenindef,
2617 lenindef=self.lenindef,
2618 ber_encoded=self.ber_encoded,
2621 defined_by, defined = self.defined or (None, None)
2622 if defined_by is not None:
2624 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2626 for pp in self.pps_lenindef(decode_path):
2630 class OctetString(Obj):
2631 """``OCTET STRING`` binary string type
2633 >>> s = OctetString(b"hello world")
2634 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2635 >>> s == OctetString(b"hello world")
2640 >>> OctetString(b"hello", bounds=(4, 4))
2641 Traceback (most recent call last):
2642 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2643 >>> OctetString(b"hell", bounds=(4, 4))
2644 OCTET STRING 4 bytes 68656c6c
2648 Pay attention that OCTET STRING can be encoded both in primitive
2649 and constructed forms. Decoder always checks constructed form tag
2650 additionally to specified primitive one. If BER decoding is
2651 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2652 of DER restrictions.
2654 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2655 tag_default = tag_encode(4)
2656 asn1_type_name = "OCTET STRING"
2669 :param value: set the value. Either binary type, or
2670 :py:class:`pyderasn.OctetString` object
2671 :param bounds: set ``(MIN, MAX)`` value size constraint.
2672 (-inf, +inf) by default
2673 :param bytes impl: override default tag with ``IMPLICIT`` one
2674 :param bytes expl: override default tag with ``EXPLICIT`` one
2675 :param default: set default value. Type same as in ``value``
2676 :param bool optional: is object ``OPTIONAL`` in sequence
2678 super(OctetString, self).__init__(
2686 self._bound_min, self._bound_max = getattr(
2690 ) if bounds is None else bounds
2691 if value is not None:
2692 self._value = self._value_sanitize(value)
2693 if default is not None:
2694 default = self._value_sanitize(default)
2695 self.default = self.__class__(
2700 if self._value is None:
2701 self._value = default
2703 tag_klass, _, tag_num = tag_decode(self.tag)
2704 self.tag_constructed = tag_encode(
2706 form=TagFormConstructed,
2710 def _value_sanitize(self, value):
2711 if isinstance(value, binary_type):
2713 elif issubclass(value.__class__, OctetString):
2714 value = value._value
2716 raise InvalidValueType((self.__class__, bytes))
2717 if not self._bound_min <= len(value) <= self._bound_max:
2718 raise BoundsError(self._bound_min, len(value), self._bound_max)
2723 return self._value is not None
2726 obj = self.__class__()
2727 obj._value = self._value
2728 obj._bound_min = self._bound_min
2729 obj._bound_max = self._bound_max
2731 obj._expl = self._expl
2732 obj.default = self.default
2733 obj.optional = self.optional
2734 obj.offset = self.offset
2735 obj.llen = self.llen
2736 obj.vlen = self.vlen
2737 obj.expl_lenindef = self.expl_lenindef
2738 obj.lenindef = self.lenindef
2739 obj.ber_encoded = self.ber_encoded
2742 def __bytes__(self):
2743 self._assert_ready()
2746 def __eq__(self, their):
2747 if isinstance(their, binary_type):
2748 return self._value == their
2749 if not issubclass(their.__class__, OctetString):
2752 self._value == their._value and
2753 self.tag == their.tag and
2754 self._expl == their._expl
2757 def __lt__(self, their):
2758 return self._value < their._value
2769 return self.__class__(
2772 (self._bound_min, self._bound_max)
2773 if bounds is None else bounds
2775 impl=self.tag if impl is None else impl,
2776 expl=self._expl if expl is None else expl,
2777 default=self.default if default is None else default,
2778 optional=self.optional if optional is None else optional,
2782 self._assert_ready()
2785 len_encode(len(self._value)),
2789 def _decode_chunk(self, lv, offset, decode_path, ctx):
2791 l, llen, v = len_decode(lv)
2792 except DecodeError as err:
2793 raise err.__class__(
2795 klass=self.__class__,
2796 decode_path=decode_path,
2800 raise NotEnoughData(
2801 "encoded length is longer than data",
2802 klass=self.__class__,
2803 decode_path=decode_path,
2806 v, tail = v[:l], v[l:]
2808 obj = self.__class__(
2810 bounds=(self._bound_min, self._bound_max),
2813 default=self.default,
2814 optional=self.optional,
2815 _decoded=(offset, llen, l),
2817 except DecodeError as err:
2820 klass=self.__class__,
2821 decode_path=decode_path,
2824 except BoundsError as err:
2827 klass=self.__class__,
2828 decode_path=decode_path,
2833 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2835 t, tlen, lv = tag_strip(tlv)
2836 except DecodeError as err:
2837 raise err.__class__(
2839 klass=self.__class__,
2840 decode_path=decode_path,
2846 return self._decode_chunk(lv, offset, decode_path, ctx)
2847 if t == self.tag_constructed:
2848 if not ctx.get("bered", False):
2850 "unallowed BER constructed encoding",
2851 klass=self.__class__,
2852 decode_path=decode_path,
2859 l, llen, v = len_decode(lv)
2860 except LenIndefForm:
2861 llen, l, v = 1, 0, lv[1:]
2863 except DecodeError as err:
2864 raise err.__class__(
2866 klass=self.__class__,
2867 decode_path=decode_path,
2871 raise NotEnoughData(
2872 "encoded length is longer than data",
2873 klass=self.__class__,
2874 decode_path=decode_path,
2878 sub_offset = offset + tlen + llen
2882 if v[:EOC_LEN].tobytes() == EOC:
2889 "chunk out of bounds",
2890 klass=self.__class__,
2891 decode_path=decode_path + (str(len(chunks) - 1),),
2892 offset=chunks[-1].offset,
2894 sub_decode_path = decode_path + (str(len(chunks)),)
2896 chunk, v_tail = OctetString().decode(
2899 decode_path=sub_decode_path,
2902 _ctx_immutable=False,
2906 "expected OctetString encoded chunk",
2907 klass=self.__class__,
2908 decode_path=sub_decode_path,
2911 chunks.append(chunk)
2912 sub_offset += chunk.tlvlen
2913 vlen += chunk.tlvlen
2916 obj = self.__class__(
2917 value=b"".join(bytes(chunk) for chunk in chunks),
2918 bounds=(self._bound_min, self._bound_max),
2921 default=self.default,
2922 optional=self.optional,
2923 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2925 except DecodeError as err:
2928 klass=self.__class__,
2929 decode_path=decode_path,
2932 except BoundsError as err:
2935 klass=self.__class__,
2936 decode_path=decode_path,
2939 obj.lenindef = lenindef
2940 obj.ber_encoded = True
2941 return obj, (v[EOC_LEN:] if lenindef else v)
2943 klass=self.__class__,
2944 decode_path=decode_path,
2949 return pp_console_row(next(self.pps()))
2951 def pps(self, decode_path=()):
2954 asn1_type_name=self.asn1_type_name,
2955 obj_name=self.__class__.__name__,
2956 decode_path=decode_path,
2957 value=("%d bytes" % len(self._value)) if self.ready else None,
2958 blob=self._value if self.ready else None,
2959 optional=self.optional,
2960 default=self == self.default,
2961 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2962 expl=None if self._expl is None else tag_decode(self._expl),
2967 expl_offset=self.expl_offset if self.expled else None,
2968 expl_tlen=self.expl_tlen if self.expled else None,
2969 expl_llen=self.expl_llen if self.expled else None,
2970 expl_vlen=self.expl_vlen if self.expled else None,
2971 expl_lenindef=self.expl_lenindef,
2972 lenindef=self.lenindef,
2973 ber_encoded=self.ber_encoded,
2976 defined_by, defined = self.defined or (None, None)
2977 if defined_by is not None:
2979 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2981 for pp in self.pps_lenindef(decode_path):
2986 """``NULL`` null object
2994 tag_default = tag_encode(5)
2995 asn1_type_name = "NULL"
2999 value=None, # unused, but Sequence passes it
3006 :param bytes impl: override default tag with ``IMPLICIT`` one
3007 :param bytes expl: override default tag with ``EXPLICIT`` one
3008 :param bool optional: is object ``OPTIONAL`` in sequence
3010 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3018 obj = self.__class__()
3020 obj._expl = self._expl
3021 obj.default = self.default
3022 obj.optional = self.optional
3023 obj.offset = self.offset
3024 obj.llen = self.llen
3025 obj.vlen = self.vlen
3026 obj.expl_lenindef = self.expl_lenindef
3027 obj.lenindef = self.lenindef
3028 obj.ber_encoded = self.ber_encoded
3031 def __eq__(self, their):
3032 if not issubclass(their.__class__, Null):
3035 self.tag == their.tag and
3036 self._expl == their._expl
3046 return self.__class__(
3047 impl=self.tag if impl is None else impl,
3048 expl=self._expl if expl is None else expl,
3049 optional=self.optional if optional is None else optional,
3053 return self.tag + len_encode(0)
3055 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3057 t, _, lv = tag_strip(tlv)
3058 except DecodeError as err:
3059 raise err.__class__(
3061 klass=self.__class__,
3062 decode_path=decode_path,
3067 klass=self.__class__,
3068 decode_path=decode_path,
3071 if tag_only: # pragma: no cover
3074 l, _, v = len_decode(lv)
3075 except DecodeError as err:
3076 raise err.__class__(
3078 klass=self.__class__,
3079 decode_path=decode_path,
3083 raise InvalidLength(
3084 "Null must have zero length",
3085 klass=self.__class__,
3086 decode_path=decode_path,
3089 obj = self.__class__(
3092 optional=self.optional,
3093 _decoded=(offset, 1, 0),
3098 return pp_console_row(next(self.pps()))
3100 def pps(self, decode_path=()):
3103 asn1_type_name=self.asn1_type_name,
3104 obj_name=self.__class__.__name__,
3105 decode_path=decode_path,
3106 optional=self.optional,
3107 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3108 expl=None if self._expl is None else tag_decode(self._expl),
3113 expl_offset=self.expl_offset if self.expled else None,
3114 expl_tlen=self.expl_tlen if self.expled else None,
3115 expl_llen=self.expl_llen if self.expled else None,
3116 expl_vlen=self.expl_vlen if self.expled else None,
3117 expl_lenindef=self.expl_lenindef,
3120 for pp in self.pps_lenindef(decode_path):
3124 class ObjectIdentifier(Obj):
3125 """``OBJECT IDENTIFIER`` OID type
3127 >>> oid = ObjectIdentifier((1, 2, 3))
3128 OBJECT IDENTIFIER 1.2.3
3129 >>> oid == ObjectIdentifier("1.2.3")
3135 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3136 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3138 >>> str(ObjectIdentifier((3, 1)))
3139 Traceback (most recent call last):
3140 pyderasn.InvalidOID: unacceptable first arc value
3142 __slots__ = ("defines",)
3143 tag_default = tag_encode(6)
3144 asn1_type_name = "OBJECT IDENTIFIER"
3157 :param value: set the value. Either tuples of integers,
3158 string of "."-concatenated integers, or
3159 :py:class:`pyderasn.ObjectIdentifier` object
3160 :param defines: sequence of tuples. Each tuple has two elements.
3161 First one is relative to current one decode
3162 path, aiming to the field defined by that OID.
3163 Read about relative path in
3164 :py:func:`pyderasn.abs_decode_path`. Second
3165 tuple element is ``{OID: pyderasn.Obj()}``
3166 dictionary, mapping between current OID value
3167 and structure applied to defined field.
3168 :ref:`Read about DEFINED BY <definedby>`
3169 :param bytes impl: override default tag with ``IMPLICIT`` one
3170 :param bytes expl: override default tag with ``EXPLICIT`` one
3171 :param default: set default value. Type same as in ``value``
3172 :param bool optional: is object ``OPTIONAL`` in sequence
3174 super(ObjectIdentifier, self).__init__(
3182 if value is not None:
3183 self._value = self._value_sanitize(value)
3184 if default is not None:
3185 default = self._value_sanitize(default)
3186 self.default = self.__class__(
3191 if self._value is None:
3192 self._value = default
3193 self.defines = defines
3195 def __add__(self, their):
3196 if isinstance(their, self.__class__):
3197 return self.__class__(self._value + their._value)
3198 if isinstance(their, tuple):
3199 return self.__class__(self._value + their)
3200 raise InvalidValueType((self.__class__, tuple))
3202 def _value_sanitize(self, value):
3203 if issubclass(value.__class__, ObjectIdentifier):
3205 if isinstance(value, string_types):
3207 value = tuple(int(arc) for arc in value.split("."))
3209 raise InvalidOID("unacceptable arcs values")
3210 if isinstance(value, tuple):
3212 raise InvalidOID("less than 2 arcs")
3213 first_arc = value[0]
3214 if first_arc in (0, 1):
3215 if not (0 <= value[1] <= 39):
3216 raise InvalidOID("second arc is too wide")
3217 elif first_arc == 2:
3220 raise InvalidOID("unacceptable first arc value")
3222 raise InvalidValueType((self.__class__, str, tuple))
3226 return self._value is not None
3229 obj = self.__class__()
3230 obj._value = self._value
3231 obj.defines = self.defines
3233 obj._expl = self._expl
3234 obj.default = self.default
3235 obj.optional = self.optional
3236 obj.offset = self.offset
3237 obj.llen = self.llen
3238 obj.vlen = self.vlen
3239 obj.expl_lenindef = self.expl_lenindef
3240 obj.lenindef = self.lenindef
3241 obj.ber_encoded = self.ber_encoded
3245 self._assert_ready()
3246 return iter(self._value)
3249 return ".".join(str(arc) for arc in self._value or ())
3252 self._assert_ready()
3255 bytes(self._expl or b"") +
3256 str(self._value).encode("ascii"),
3259 def __eq__(self, their):
3260 if isinstance(their, tuple):
3261 return self._value == their
3262 if not issubclass(their.__class__, ObjectIdentifier):
3265 self.tag == their.tag and
3266 self._expl == their._expl and
3267 self._value == their._value
3270 def __lt__(self, their):
3271 return self._value < their._value
3282 return self.__class__(
3284 defines=self.defines if defines is None else defines,
3285 impl=self.tag if impl is None else impl,
3286 expl=self._expl if expl is None else expl,
3287 default=self.default if default is None else default,
3288 optional=self.optional if optional is None else optional,
3292 self._assert_ready()
3294 first_value = value[1]
3295 first_arc = value[0]
3298 elif first_arc == 1:
3300 elif first_arc == 2:
3302 else: # pragma: no cover
3303 raise RuntimeError("invalid arc is stored")
3304 octets = [zero_ended_encode(first_value)]
3305 for arc in value[2:]:
3306 octets.append(zero_ended_encode(arc))
3307 v = b"".join(octets)
3308 return b"".join((self.tag, len_encode(len(v)), v))
3310 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3312 t, _, lv = tag_strip(tlv)
3313 except DecodeError as err:
3314 raise err.__class__(
3316 klass=self.__class__,
3317 decode_path=decode_path,
3322 klass=self.__class__,
3323 decode_path=decode_path,
3326 if tag_only: # pragma: no cover
3329 l, llen, v = len_decode(lv)
3330 except DecodeError as err:
3331 raise err.__class__(
3333 klass=self.__class__,
3334 decode_path=decode_path,
3338 raise NotEnoughData(
3339 "encoded length is longer than data",
3340 klass=self.__class__,
3341 decode_path=decode_path,
3345 raise NotEnoughData(
3347 klass=self.__class__,
3348 decode_path=decode_path,
3351 v, tail = v[:l], v[l:]
3358 octet = indexbytes(v, i)
3359 if i == 0 and octet == 0x80:
3360 if ctx.get("bered", False):
3363 raise DecodeError("non normalized arc encoding")
3364 arc = (arc << 7) | (octet & 0x7F)
3365 if octet & 0x80 == 0:
3373 klass=self.__class__,
3374 decode_path=decode_path,
3378 second_arc = arcs[0]
3379 if 0 <= second_arc <= 39:
3381 elif 40 <= second_arc <= 79:
3387 obj = self.__class__(
3388 value=tuple([first_arc, second_arc] + arcs[1:]),
3391 default=self.default,
3392 optional=self.optional,
3393 _decoded=(offset, llen, l),
3396 obj.ber_encoded = True
3400 return pp_console_row(next(self.pps()))
3402 def pps(self, decode_path=()):
3405 asn1_type_name=self.asn1_type_name,
3406 obj_name=self.__class__.__name__,
3407 decode_path=decode_path,
3408 value=str(self) if self.ready else None,
3409 optional=self.optional,
3410 default=self == self.default,
3411 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3412 expl=None if self._expl is None else tag_decode(self._expl),
3417 expl_offset=self.expl_offset if self.expled else None,
3418 expl_tlen=self.expl_tlen if self.expled else None,
3419 expl_llen=self.expl_llen if self.expled else None,
3420 expl_vlen=self.expl_vlen if self.expled else None,
3421 expl_lenindef=self.expl_lenindef,
3422 ber_encoded=self.ber_encoded,
3425 for pp in self.pps_lenindef(decode_path):
3429 class Enumerated(Integer):
3430 """``ENUMERATED`` integer type
3432 This type is identical to :py:class:`pyderasn.Integer`, but requires
3433 schema to be specified and does not accept values missing from it.
3436 tag_default = tag_encode(10)
3437 asn1_type_name = "ENUMERATED"
3448 bounds=None, # dummy argument, workability for Integer.decode
3450 super(Enumerated, self).__init__(
3459 if len(self.specs) == 0:
3460 raise ValueError("schema must be specified")
3462 def _value_sanitize(self, value):
3463 if isinstance(value, self.__class__):
3464 value = value._value
3465 elif isinstance(value, integer_types):
3466 for _value in itervalues(self.specs):
3471 "unknown integer value: %s" % value,
3472 klass=self.__class__,
3474 elif isinstance(value, string_types):
3475 value = self.specs.get(value)
3477 raise ObjUnknown("integer value: %s" % value)
3479 raise InvalidValueType((self.__class__, int, str))
3483 obj = self.__class__(_specs=self.specs)
3484 obj._value = self._value
3485 obj._bound_min = self._bound_min
3486 obj._bound_max = self._bound_max
3488 obj._expl = self._expl
3489 obj.default = self.default
3490 obj.optional = self.optional
3491 obj.offset = self.offset
3492 obj.llen = self.llen
3493 obj.vlen = self.vlen
3494 obj.expl_lenindef = self.expl_lenindef
3495 obj.lenindef = self.lenindef
3496 obj.ber_encoded = self.ber_encoded
3508 return self.__class__(
3510 impl=self.tag if impl is None else impl,
3511 expl=self._expl if expl is None else expl,
3512 default=self.default if default is None else default,
3513 optional=self.optional if optional is None else optional,
3518 class CommonString(OctetString):
3519 """Common class for all strings
3521 Everything resembles :py:class:`pyderasn.OctetString`, except
3522 ability to deal with unicode text strings.
3524 >>> hexenc("привет мир".encode("utf-8"))
3525 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3526 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3528 >>> s = UTF8String("привет мир")
3529 UTF8String UTF8String привет мир
3531 'привет мир'
3532 >>> hexenc(bytes(s))
3533 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3535 >>> PrintableString("привет мир")
3536 Traceback (most recent call last):
3537 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3539 >>> BMPString("ада", bounds=(2, 2))
3540 Traceback (most recent call last):
3541 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3542 >>> s = BMPString("ад", bounds=(2, 2))
3545 >>> hexenc(bytes(s))
3553 * - :py:class:`pyderasn.UTF8String`
3555 * - :py:class:`pyderasn.NumericString`
3557 * - :py:class:`pyderasn.PrintableString`
3559 * - :py:class:`pyderasn.TeletexString`
3561 * - :py:class:`pyderasn.T61String`
3563 * - :py:class:`pyderasn.VideotexString`
3565 * - :py:class:`pyderasn.IA5String`
3567 * - :py:class:`pyderasn.GraphicString`
3569 * - :py:class:`pyderasn.VisibleString`
3571 * - :py:class:`pyderasn.ISO646String`
3573 * - :py:class:`pyderasn.GeneralString`
3575 * - :py:class:`pyderasn.UniversalString`
3577 * - :py:class:`pyderasn.BMPString`
3580 __slots__ = ("encoding",)
3582 def _value_sanitize(self, value):
3584 value_decoded = None
3585 if isinstance(value, self.__class__):
3586 value_raw = value._value
3587 elif isinstance(value, text_type):
3588 value_decoded = value
3589 elif isinstance(value, binary_type):
3592 raise InvalidValueType((self.__class__, text_type, binary_type))
3595 value_decoded.encode(self.encoding)
3596 if value_raw is None else value_raw
3599 value_raw.decode(self.encoding)
3600 if value_decoded is None else value_decoded
3602 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3603 raise DecodeError(str(err))
3604 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3612 def __eq__(self, their):
3613 if isinstance(their, binary_type):
3614 return self._value == their
3615 if isinstance(their, text_type):
3616 return self._value == their.encode(self.encoding)
3617 if not isinstance(their, self.__class__):
3620 self._value == their._value and
3621 self.tag == their.tag and
3622 self._expl == their._expl
3625 def __unicode__(self):
3627 return self._value.decode(self.encoding)
3628 return text_type(self._value)
3631 return pp_console_row(next(self.pps(no_unicode=PY2)))
3633 def pps(self, decode_path=(), no_unicode=False):
3636 value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
3639 asn1_type_name=self.asn1_type_name,
3640 obj_name=self.__class__.__name__,
3641 decode_path=decode_path,
3643 optional=self.optional,
3644 default=self == self.default,
3645 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3646 expl=None if self._expl is None else tag_decode(self._expl),
3651 expl_offset=self.expl_offset if self.expled else None,
3652 expl_tlen=self.expl_tlen if self.expled else None,
3653 expl_llen=self.expl_llen if self.expled else None,
3654 expl_vlen=self.expl_vlen if self.expled else None,
3655 expl_lenindef=self.expl_lenindef,
3656 ber_encoded=self.ber_encoded,
3659 for pp in self.pps_lenindef(decode_path):
3663 class UTF8String(CommonString):
3665 tag_default = tag_encode(12)
3667 asn1_type_name = "UTF8String"
3670 class AllowableCharsMixin(object):
3672 def allowable_chars(self):
3674 return self._allowable_chars
3675 return frozenset(six_unichr(c) for c in self._allowable_chars)
3678 class NumericString(AllowableCharsMixin, CommonString):
3681 Its value is properly sanitized: only ASCII digits with spaces can
3684 >>> NumericString().allowable_chars
3685 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3688 tag_default = tag_encode(18)
3690 asn1_type_name = "NumericString"
3691 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3693 def _value_sanitize(self, value):
3694 value = super(NumericString, self)._value_sanitize(value)
3695 if not frozenset(value) <= self._allowable_chars:
3696 raise DecodeError("non-numeric value")
3700 class PrintableString(AllowableCharsMixin, CommonString):
3703 Its value is properly sanitized: see X.680 41.4 table 10.
3705 >>> PrintableString().allowable_chars
3706 frozenset([' ', "'", ..., 'z'])
3709 tag_default = tag_encode(19)
3711 asn1_type_name = "PrintableString"
3712 _allowable_chars = frozenset(
3713 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3716 def _value_sanitize(self, value):
3717 value = super(PrintableString, self)._value_sanitize(value)
3718 if not frozenset(value) <= self._allowable_chars:
3719 raise DecodeError("non-printable value")
3723 class TeletexString(CommonString):
3725 tag_default = tag_encode(20)
3727 asn1_type_name = "TeletexString"
3730 class T61String(TeletexString):
3732 asn1_type_name = "T61String"
3735 class VideotexString(CommonString):
3737 tag_default = tag_encode(21)
3738 encoding = "iso-8859-1"
3739 asn1_type_name = "VideotexString"
3742 class IA5String(CommonString):
3744 tag_default = tag_encode(22)
3746 asn1_type_name = "IA5"
3749 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3750 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3751 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3754 class UTCTime(CommonString):
3755 """``UTCTime`` datetime type
3757 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3758 UTCTime UTCTime 2017-09-30T22:07:50
3764 datetime.datetime(2017, 9, 30, 22, 7, 50)
3765 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3766 datetime.datetime(1957, 9, 30, 22, 7, 50)
3770 BER encoding is unsupported.
3773 tag_default = tag_encode(23)
3775 asn1_type_name = "UTCTime"
3785 bounds=None, # dummy argument, workability for OctetString.decode
3788 :param value: set the value. Either datetime type, or
3789 :py:class:`pyderasn.UTCTime` object
3790 :param bytes impl: override default tag with ``IMPLICIT`` one
3791 :param bytes expl: override default tag with ``EXPLICIT`` one
3792 :param default: set default value. Type same as in ``value``
3793 :param bool optional: is object ``OPTIONAL`` in sequence
3795 super(UTCTime, self).__init__(
3803 if value is not None:
3804 self._value = self._value_sanitize(value)
3805 if default is not None:
3806 default = self._value_sanitize(default)
3807 self.default = self.__class__(
3812 if self._value is None:
3813 self._value = default
3815 def _strptime(self, value):
3816 # datetime.strptime's format: %y%m%d%H%M%SZ
3817 if len(value) != LEN_YYMMDDHHMMSSZ:
3818 raise ValueError("invalid UTCTime length")
3819 if value[-1] != "Z":
3820 raise ValueError("non UTC timezone")
3822 2000 + int(value[:2]), # %y
3823 int(value[2:4]), # %m
3824 int(value[4:6]), # %d
3825 int(value[6:8]), # %H
3826 int(value[8:10]), # %M
3827 int(value[10:12]), # %S
3830 def _value_sanitize(self, value):
3831 if isinstance(value, binary_type):
3833 value_decoded = value.decode("ascii")
3834 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3835 raise DecodeError("invalid UTCTime encoding")
3837 self._strptime(value_decoded)
3838 except (TypeError, ValueError) as err:
3839 raise DecodeError("invalid UTCTime format: %r" % err)
3841 if isinstance(value, self.__class__):
3843 if isinstance(value, datetime):
3844 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3845 raise InvalidValueType((self.__class__, datetime))
3847 def __eq__(self, their):
3848 if isinstance(their, binary_type):
3849 return self._value == their
3850 if isinstance(their, datetime):
3851 return self.todatetime() == their
3852 if not isinstance(their, self.__class__):
3855 self._value == their._value and
3856 self.tag == their.tag and
3857 self._expl == their._expl
3860 def todatetime(self):
3861 """Convert to datetime
3865 Pay attention that UTCTime can not hold full year, so all years
3866 having < 50 years are treated as 20xx, 19xx otherwise, according
3867 to X.509 recomendation.
3869 value = self._strptime(self._value.decode("ascii"))
3870 year = value.year % 100
3872 year=(2000 + year) if year < 50 else (1900 + year),
3876 minute=value.minute,
3877 second=value.second,
3881 return pp_console_row(next(self.pps()))
3883 def pps(self, decode_path=()):
3886 asn1_type_name=self.asn1_type_name,
3887 obj_name=self.__class__.__name__,
3888 decode_path=decode_path,
3889 value=self.todatetime().isoformat() if self.ready else None,
3890 optional=self.optional,
3891 default=self == self.default,
3892 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3893 expl=None if self._expl is None else tag_decode(self._expl),
3898 expl_offset=self.expl_offset if self.expled else None,
3899 expl_tlen=self.expl_tlen if self.expled else None,
3900 expl_llen=self.expl_llen if self.expled else None,
3901 expl_vlen=self.expl_vlen if self.expled else None,
3902 expl_lenindef=self.expl_lenindef,
3903 ber_encoded=self.ber_encoded,
3906 for pp in self.pps_lenindef(decode_path):
3910 class GeneralizedTime(UTCTime):
3911 """``GeneralizedTime`` datetime type
3913 This type is similar to :py:class:`pyderasn.UTCTime`.
3915 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3916 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
3918 '20170930220750.000123Z'
3919 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
3920 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
3924 BER encoding is unsupported.
3928 Only microsecond fractions are supported.
3929 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
3930 higher precision values.
3933 tag_default = tag_encode(24)
3934 asn1_type_name = "GeneralizedTime"
3936 def _strptime(self, value):
3938 if l == LEN_YYYYMMDDHHMMSSZ:
3939 # datetime.strptime's format: %y%m%d%H%M%SZ
3940 if value[-1] != "Z":
3941 raise ValueError("non UTC timezone")
3943 int(value[:4]), # %Y
3944 int(value[4:6]), # %m
3945 int(value[6:8]), # %d
3946 int(value[8:10]), # %H
3947 int(value[10:12]), # %M
3948 int(value[12:14]), # %S
3950 if l >= LEN_YYYYMMDDHHMMSSDMZ:
3951 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
3952 if value[-1] != "Z":
3953 raise ValueError("non UTC timezone")
3954 if value[14] != ".":
3955 raise ValueError("no fractions separator")
3958 raise ValueError("trailing zero")
3961 raise ValueError("only microsecond fractions are supported")
3962 us = int(us + ("0" * (6 - us_len)))
3964 int(value[:4]), # %Y
3965 int(value[4:6]), # %m
3966 int(value[6:8]), # %d
3967 int(value[8:10]), # %H
3968 int(value[10:12]), # %M
3969 int(value[12:14]), # %S
3973 raise ValueError("invalid GeneralizedTime length")
3975 def _value_sanitize(self, value):
3976 if isinstance(value, binary_type):
3978 value_decoded = value.decode("ascii")
3979 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3980 raise DecodeError("invalid GeneralizedTime encoding")
3982 self._strptime(value_decoded)
3983 except (TypeError, ValueError) as err:
3985 "invalid GeneralizedTime format: %r" % err,
3986 klass=self.__class__,
3989 if isinstance(value, self.__class__):
3991 if isinstance(value, datetime):
3992 encoded = value.strftime("%Y%m%d%H%M%S")
3993 if value.microsecond > 0:
3994 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
3995 return (encoded + "Z").encode("ascii")
3996 raise InvalidValueType((self.__class__, datetime))
3998 def todatetime(self):
3999 return self._strptime(self._value.decode("ascii"))
4002 class GraphicString(CommonString):
4004 tag_default = tag_encode(25)
4005 encoding = "iso-8859-1"
4006 asn1_type_name = "GraphicString"
4009 class VisibleString(CommonString):
4011 tag_default = tag_encode(26)
4013 asn1_type_name = "VisibleString"
4016 class ISO646String(VisibleString):
4018 asn1_type_name = "ISO646String"
4021 class GeneralString(CommonString):
4023 tag_default = tag_encode(27)
4024 encoding = "iso-8859-1"
4025 asn1_type_name = "GeneralString"
4028 class UniversalString(CommonString):
4030 tag_default = tag_encode(28)
4031 encoding = "utf-32-be"
4032 asn1_type_name = "UniversalString"
4035 class BMPString(CommonString):
4037 tag_default = tag_encode(30)
4038 encoding = "utf-16-be"
4039 asn1_type_name = "BMPString"
4043 """``CHOICE`` special type
4047 class GeneralName(Choice):
4049 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4050 ("dNSName", IA5String(impl=tag_ctxp(2))),
4053 >>> gn = GeneralName()
4055 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4056 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4057 >>> gn["dNSName"] = IA5String("bar.baz")
4058 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4059 >>> gn["rfc822Name"]
4062 [2] IA5String IA5 bar.baz
4065 >>> gn.value == gn["dNSName"]
4068 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4070 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4071 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4073 __slots__ = ("specs",)
4075 asn1_type_name = "CHOICE"
4088 :param value: set the value. Either ``(choice, value)`` tuple, or
4089 :py:class:`pyderasn.Choice` object
4090 :param bytes impl: can not be set, do **not** use it
4091 :param bytes expl: override default tag with ``EXPLICIT`` one
4092 :param default: set default value. Type same as in ``value``
4093 :param bool optional: is object ``OPTIONAL`` in sequence
4095 if impl is not None:
4096 raise ValueError("no implicit tag allowed for CHOICE")
4097 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4099 schema = getattr(self, "schema", ())
4100 if len(schema) == 0:
4101 raise ValueError("schema must be specified")
4103 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4106 if value is not None:
4107 self._value = self._value_sanitize(value)
4108 if default is not None:
4109 default_value = self._value_sanitize(default)
4110 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4111 default_obj.specs = self.specs
4112 default_obj._value = default_value
4113 self.default = default_obj
4115 self._value = default_obj.copy()._value
4117 def _value_sanitize(self, value):
4118 if isinstance(value, tuple) and len(value) == 2:
4120 spec = self.specs.get(choice)
4122 raise ObjUnknown(choice)
4123 if not isinstance(obj, spec.__class__):
4124 raise InvalidValueType((spec,))
4125 return (choice, spec(obj))
4126 if isinstance(value, self.__class__):
4128 raise InvalidValueType((self.__class__, tuple))
4132 return self._value is not None and self._value[1].ready
4136 return self.expl_lenindef or (
4137 (self._value is not None) and
4138 self._value[1].bered
4142 obj = self.__class__(schema=self.specs)
4143 obj._expl = self._expl
4144 obj.default = self.default
4145 obj.optional = self.optional
4146 obj.offset = self.offset
4147 obj.llen = self.llen
4148 obj.vlen = self.vlen
4149 obj.expl_lenindef = self.expl_lenindef
4150 obj.lenindef = self.lenindef
4151 obj.ber_encoded = self.ber_encoded
4153 if value is not None:
4154 obj._value = (value[0], value[1].copy())
4157 def __eq__(self, their):
4158 if isinstance(their, tuple) and len(their) == 2:
4159 return self._value == their
4160 if not isinstance(their, self.__class__):
4163 self.specs == their.specs and
4164 self._value == their._value
4174 return self.__class__(
4177 expl=self._expl if expl is None else expl,
4178 default=self.default if default is None else default,
4179 optional=self.optional if optional is None else optional,
4184 self._assert_ready()
4185 return self._value[0]
4189 self._assert_ready()
4190 return self._value[1]
4192 def __getitem__(self, key):
4193 if key not in self.specs:
4194 raise ObjUnknown(key)
4195 if self._value is None:
4197 choice, value = self._value
4202 def __setitem__(self, key, value):
4203 spec = self.specs.get(key)
4205 raise ObjUnknown(key)
4206 if not isinstance(value, spec.__class__):
4207 raise InvalidValueType((spec.__class__,))
4208 self._value = (key, spec(value))
4216 return self._value[1].decoded if self.ready else False
4219 self._assert_ready()
4220 return self._value[1].encode()
4222 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4223 for choice, spec in iteritems(self.specs):
4224 sub_decode_path = decode_path + (choice,)
4230 decode_path=sub_decode_path,
4233 _ctx_immutable=False,
4240 klass=self.__class__,
4241 decode_path=decode_path,
4244 if tag_only: # pragma: no cover
4246 value, tail = spec.decode(
4250 decode_path=sub_decode_path,
4252 _ctx_immutable=False,
4254 obj = self.__class__(
4257 default=self.default,
4258 optional=self.optional,
4259 _decoded=(offset, 0, value.fulllen),
4261 obj._value = (choice, value)
4265 value = pp_console_row(next(self.pps()))
4267 value = "%s[%r]" % (value, self.value)
4270 def pps(self, decode_path=()):
4273 asn1_type_name=self.asn1_type_name,
4274 obj_name=self.__class__.__name__,
4275 decode_path=decode_path,
4276 value=self.choice if self.ready else None,
4277 optional=self.optional,
4278 default=self == self.default,
4279 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4280 expl=None if self._expl is None else tag_decode(self._expl),
4285 expl_lenindef=self.expl_lenindef,
4289 yield self.value.pps(decode_path=decode_path + (self.choice,))
4290 for pp in self.pps_lenindef(decode_path):
4294 class PrimitiveTypes(Choice):
4295 """Predefined ``CHOICE`` for all generic primitive types
4297 It could be useful for general decoding of some unspecified values:
4299 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4300 OCTET STRING 3 bytes 666f6f
4301 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4305 schema = tuple((klass.__name__, klass()) for klass in (
4330 """``ANY`` special type
4332 >>> Any(Integer(-123))
4334 >>> a = Any(OctetString(b"hello world").encode())
4335 ANY 040b68656c6c6f20776f726c64
4336 >>> hexenc(bytes(a))
4337 b'0x040x0bhello world'
4339 __slots__ = ("defined",)
4340 tag_default = tag_encode(0)
4341 asn1_type_name = "ANY"
4351 :param value: set the value. Either any kind of pyderasn's
4352 **ready** object, or bytes. Pay attention that
4353 **no** validation is performed is raw binary value
4355 :param bytes expl: override default tag with ``EXPLICIT`` one
4356 :param bool optional: is object ``OPTIONAL`` in sequence
4358 super(Any, self).__init__(None, expl, None, optional, _decoded)
4359 self._value = None if value is None else self._value_sanitize(value)
4362 def _value_sanitize(self, value):
4363 if isinstance(value, binary_type):
4365 if isinstance(value, self.__class__):
4367 if isinstance(value, Obj):
4368 return value.encode()
4369 raise InvalidValueType((self.__class__, Obj, binary_type))
4373 return self._value is not None
4377 if self.expl_lenindef or self.lenindef:
4379 if self.defined is None:
4381 return self.defined[1].bered
4384 obj = self.__class__()
4385 obj._value = self._value
4387 obj._expl = self._expl
4388 obj.optional = self.optional
4389 obj.offset = self.offset
4390 obj.llen = self.llen
4391 obj.vlen = self.vlen
4392 obj.expl_lenindef = self.expl_lenindef
4393 obj.lenindef = self.lenindef
4394 obj.ber_encoded = self.ber_encoded
4397 def __eq__(self, their):
4398 if isinstance(their, binary_type):
4399 return self._value == their
4400 if issubclass(their.__class__, Any):
4401 return self._value == their._value
4410 return self.__class__(
4412 expl=self._expl if expl is None else expl,
4413 optional=self.optional if optional is None else optional,
4416 def __bytes__(self):
4417 self._assert_ready()
4425 self._assert_ready()
4428 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4430 t, tlen, lv = tag_strip(tlv)
4431 except DecodeError as err:
4432 raise err.__class__(
4434 klass=self.__class__,
4435 decode_path=decode_path,
4439 l, llen, v = len_decode(lv)
4440 except LenIndefForm as err:
4441 if not ctx.get("bered", False):
4442 raise err.__class__(
4444 klass=self.__class__,
4445 decode_path=decode_path,
4448 llen, vlen, v = 1, 0, lv[1:]
4449 sub_offset = offset + tlen + llen
4451 while v[:EOC_LEN].tobytes() != EOC:
4452 chunk, v = Any().decode(
4455 decode_path=decode_path + (str(chunk_i),),
4458 _ctx_immutable=False,
4460 vlen += chunk.tlvlen
4461 sub_offset += chunk.tlvlen
4463 tlvlen = tlen + llen + vlen + EOC_LEN
4464 obj = self.__class__(
4465 value=tlv[:tlvlen].tobytes(),
4467 optional=self.optional,
4468 _decoded=(offset, 0, tlvlen),
4472 return obj, v[EOC_LEN:]
4473 except DecodeError as err:
4474 raise err.__class__(
4476 klass=self.__class__,
4477 decode_path=decode_path,
4481 raise NotEnoughData(
4482 "encoded length is longer than data",
4483 klass=self.__class__,
4484 decode_path=decode_path,
4487 tlvlen = tlen + llen + l
4488 v, tail = tlv[:tlvlen], v[l:]
4489 obj = self.__class__(
4492 optional=self.optional,
4493 _decoded=(offset, 0, tlvlen),
4499 return pp_console_row(next(self.pps()))
4501 def pps(self, decode_path=()):
4504 asn1_type_name=self.asn1_type_name,
4505 obj_name=self.__class__.__name__,
4506 decode_path=decode_path,
4507 blob=self._value if self.ready else None,
4508 optional=self.optional,
4509 default=self == self.default,
4510 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4511 expl=None if self._expl is None else tag_decode(self._expl),
4516 expl_offset=self.expl_offset if self.expled else None,
4517 expl_tlen=self.expl_tlen if self.expled else None,
4518 expl_llen=self.expl_llen if self.expled else None,
4519 expl_vlen=self.expl_vlen if self.expled else None,
4520 expl_lenindef=self.expl_lenindef,
4521 lenindef=self.lenindef,
4524 defined_by, defined = self.defined or (None, None)
4525 if defined_by is not None:
4527 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4529 for pp in self.pps_lenindef(decode_path):
4533 ########################################################################
4534 # ASN.1 constructed types
4535 ########################################################################
4537 def get_def_by_path(defines_by_path, sub_decode_path):
4538 """Get define by decode path
4540 for path, define in defines_by_path:
4541 if len(path) != len(sub_decode_path):
4543 for p1, p2 in zip(path, sub_decode_path):
4544 if (p1 != any) and (p1 != p2):
4550 def abs_decode_path(decode_path, rel_path):
4551 """Create an absolute decode path from current and relative ones
4553 :param decode_path: current decode path, starting point. Tuple of strings
4554 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4555 If first tuple's element is "/", then treat it as
4556 an absolute path, ignoring ``decode_path`` as
4557 starting point. Also this tuple can contain ".."
4558 elements, stripping the leading element from
4561 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4562 ("foo", "bar", "baz", "whatever")
4563 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4565 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4568 if rel_path[0] == "/":
4570 if rel_path[0] == "..":
4571 return abs_decode_path(decode_path[:-1], rel_path[1:])
4572 return decode_path + rel_path
4575 class Sequence(Obj):
4576 """``SEQUENCE`` structure type
4578 You have to make specification of sequence::
4580 class Extension(Sequence):
4582 ("extnID", ObjectIdentifier()),
4583 ("critical", Boolean(default=False)),
4584 ("extnValue", OctetString()),
4587 Then, you can work with it as with dictionary.
4589 >>> ext = Extension()
4590 >>> Extension().specs
4592 ('extnID', OBJECT IDENTIFIER),
4593 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4594 ('extnValue', OCTET STRING),
4596 >>> ext["extnID"] = "1.2.3"
4597 Traceback (most recent call last):
4598 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4599 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4601 You can determine if sequence is ready to be encoded:
4606 Traceback (most recent call last):
4607 pyderasn.ObjNotReady: object is not ready: extnValue
4608 >>> ext["extnValue"] = OctetString(b"foobar")
4612 Value you want to assign, must have the same **type** as in
4613 corresponding specification, but it can have different tags,
4614 optional/default attributes -- they will be taken from specification
4617 class TBSCertificate(Sequence):
4619 ("version", Version(expl=tag_ctxc(0), default="v1")),
4622 >>> tbs = TBSCertificate()
4623 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4625 Assign ``None`` to remove value from sequence.
4627 You can set values in Sequence during its initialization:
4629 >>> AlgorithmIdentifier((
4630 ("algorithm", ObjectIdentifier("1.2.3")),
4631 ("parameters", Any(Null()))
4633 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4635 You can determine if value exists/set in the sequence and take its value:
4637 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4640 OBJECT IDENTIFIER 1.2.3
4642 But pay attention that if value has default, then it won't be (not
4643 in) in the sequence (because ``DEFAULT`` must not be encoded in
4644 DER), but you can read its value:
4646 >>> "critical" in ext, ext["critical"]
4647 (False, BOOLEAN False)
4648 >>> ext["critical"] = Boolean(True)
4649 >>> "critical" in ext, ext["critical"]
4650 (True, BOOLEAN True)
4652 All defaulted values are always optional.
4654 .. _allow_default_values_ctx:
4656 DER prohibits default value encoding and will raise an error if
4657 default value is unexpectedly met during decode.
4658 If :ref:`bered <bered_ctx>` context option is set, then no error
4659 will be raised, but ``bered`` attribute set. You can disable strict
4660 defaulted values existence validation by setting
4661 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4663 Two sequences are equal if they have equal specification (schema),
4664 implicit/explicit tagging and the same values.
4666 __slots__ = ("specs",)
4667 tag_default = tag_encode(form=TagFormConstructed, num=16)
4668 asn1_type_name = "SEQUENCE"
4680 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4682 schema = getattr(self, "schema", ())
4684 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4687 if value is not None:
4688 if issubclass(value.__class__, Sequence):
4689 self._value = value._value
4690 elif hasattr(value, "__iter__"):
4691 for seq_key, seq_value in value:
4692 self[seq_key] = seq_value
4694 raise InvalidValueType((Sequence,))
4695 if default is not None:
4696 if not issubclass(default.__class__, Sequence):
4697 raise InvalidValueType((Sequence,))
4698 default_value = default._value
4699 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4700 default_obj.specs = self.specs
4701 default_obj._value = default_value
4702 self.default = default_obj
4704 self._value = default_obj.copy()._value
4708 for name, spec in iteritems(self.specs):
4709 value = self._value.get(name)
4721 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4723 return any(value.bered for value in itervalues(self._value))
4726 obj = self.__class__(schema=self.specs)
4728 obj._expl = self._expl
4729 obj.default = self.default
4730 obj.optional = self.optional
4731 obj.offset = self.offset
4732 obj.llen = self.llen
4733 obj.vlen = self.vlen
4734 obj.expl_lenindef = self.expl_lenindef
4735 obj.lenindef = self.lenindef
4736 obj.ber_encoded = self.ber_encoded
4737 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4740 def __eq__(self, their):
4741 if not isinstance(their, self.__class__):
4744 self.specs == their.specs and
4745 self.tag == their.tag and
4746 self._expl == their._expl and
4747 self._value == their._value
4758 return self.__class__(
4761 impl=self.tag if impl is None else impl,
4762 expl=self._expl if expl is None else expl,
4763 default=self.default if default is None else default,
4764 optional=self.optional if optional is None else optional,
4767 def __contains__(self, key):
4768 return key in self._value
4770 def __setitem__(self, key, value):
4771 spec = self.specs.get(key)
4773 raise ObjUnknown(key)
4775 self._value.pop(key, None)
4777 if not isinstance(value, spec.__class__):
4778 raise InvalidValueType((spec.__class__,))
4779 value = spec(value=value)
4780 if spec.default is not None and value == spec.default:
4781 self._value.pop(key, None)
4783 self._value[key] = value
4785 def __getitem__(self, key):
4786 value = self._value.get(key)
4787 if value is not None:
4789 spec = self.specs.get(key)
4791 raise ObjUnknown(key)
4792 if spec.default is not None:
4796 def _encoded_values(self):
4798 for name, spec in iteritems(self.specs):
4799 value = self._value.get(name)
4803 raise ObjNotReady(name)
4804 raws.append(value.encode())
4808 v = b"".join(self._encoded_values())
4809 return b"".join((self.tag, len_encode(len(v)), v))
4811 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4813 t, tlen, lv = tag_strip(tlv)
4814 except DecodeError as err:
4815 raise err.__class__(
4817 klass=self.__class__,
4818 decode_path=decode_path,
4823 klass=self.__class__,
4824 decode_path=decode_path,
4827 if tag_only: # pragma: no cover
4830 ctx_bered = ctx.get("bered", False)
4832 l, llen, v = len_decode(lv)
4833 except LenIndefForm as err:
4835 raise err.__class__(
4837 klass=self.__class__,
4838 decode_path=decode_path,
4841 l, llen, v = 0, 1, lv[1:]
4843 except DecodeError as err:
4844 raise err.__class__(
4846 klass=self.__class__,
4847 decode_path=decode_path,
4851 raise NotEnoughData(
4852 "encoded length is longer than data",
4853 klass=self.__class__,
4854 decode_path=decode_path,
4858 v, tail = v[:l], v[l:]
4860 sub_offset = offset + tlen + llen
4863 ctx_allow_default_values = ctx.get("allow_default_values", False)
4864 for name, spec in iteritems(self.specs):
4865 if spec.optional and (
4866 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4870 sub_decode_path = decode_path + (name,)
4872 value, v_tail = spec.decode(
4876 decode_path=sub_decode_path,
4878 _ctx_immutable=False,
4885 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4886 if defined is not None:
4887 defined_by, defined_spec = defined
4888 if issubclass(value.__class__, SequenceOf):
4889 for i, _value in enumerate(value):
4890 sub_sub_decode_path = sub_decode_path + (
4892 DecodePathDefBy(defined_by),
4894 defined_value, defined_tail = defined_spec.decode(
4895 memoryview(bytes(_value)),
4897 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4898 if value.expled else (value.tlen + value.llen)
4901 decode_path=sub_sub_decode_path,
4903 _ctx_immutable=False,
4905 if len(defined_tail) > 0:
4908 klass=self.__class__,
4909 decode_path=sub_sub_decode_path,
4912 _value.defined = (defined_by, defined_value)
4914 defined_value, defined_tail = defined_spec.decode(
4915 memoryview(bytes(value)),
4917 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4918 if value.expled else (value.tlen + value.llen)
4921 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4923 _ctx_immutable=False,
4925 if len(defined_tail) > 0:
4928 klass=self.__class__,
4929 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
4932 value.defined = (defined_by, defined_value)
4934 value_len = value.fulllen
4936 sub_offset += value_len
4938 if spec.default is not None and value == spec.default:
4939 if ctx_bered or ctx_allow_default_values:
4943 "DEFAULT value met",
4944 klass=self.__class__,
4945 decode_path=sub_decode_path,
4948 values[name] = value
4950 spec_defines = getattr(spec, "defines", ())
4951 if len(spec_defines) == 0:
4952 defines_by_path = ctx.get("defines_by_path", ())
4953 if len(defines_by_path) > 0:
4954 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
4955 if spec_defines is not None and len(spec_defines) > 0:
4956 for rel_path, schema in spec_defines:
4957 defined = schema.get(value, None)
4958 if defined is not None:
4959 ctx.setdefault("_defines", []).append((
4960 abs_decode_path(sub_decode_path[:-1], rel_path),
4964 if v[:EOC_LEN].tobytes() != EOC:
4967 klass=self.__class__,
4968 decode_path=decode_path,
4976 klass=self.__class__,
4977 decode_path=decode_path,
4980 obj = self.__class__(
4984 default=self.default,
4985 optional=self.optional,
4986 _decoded=(offset, llen, vlen),
4989 obj.lenindef = lenindef
4990 obj.ber_encoded = ber_encoded
4994 value = pp_console_row(next(self.pps()))
4996 for name in self.specs:
4997 _value = self._value.get(name)
5000 cols.append("%s: %s" % (name, repr(_value)))
5001 return "%s[%s]" % (value, "; ".join(cols))
5003 def pps(self, decode_path=()):
5006 asn1_type_name=self.asn1_type_name,
5007 obj_name=self.__class__.__name__,
5008 decode_path=decode_path,
5009 optional=self.optional,
5010 default=self == self.default,
5011 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5012 expl=None if self._expl is None else tag_decode(self._expl),
5017 expl_offset=self.expl_offset if self.expled else None,
5018 expl_tlen=self.expl_tlen if self.expled else None,
5019 expl_llen=self.expl_llen if self.expled else None,
5020 expl_vlen=self.expl_vlen if self.expled else None,
5021 expl_lenindef=self.expl_lenindef,
5022 lenindef=self.lenindef,
5023 ber_encoded=self.ber_encoded,
5026 for name in self.specs:
5027 value = self._value.get(name)
5030 yield value.pps(decode_path=decode_path + (name,))
5031 for pp in self.pps_lenindef(decode_path):
5035 class Set(Sequence):
5036 """``SET`` structure type
5038 Its usage is identical to :py:class:`pyderasn.Sequence`.
5040 .. _allow_unordered_set_ctx:
5042 DER prohibits unordered values encoding and will raise an error
5043 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5044 then no error will occure. Also you can disable strict values
5045 ordering check by setting ``"allow_unordered_set": True``
5046 :ref:`context <ctx>` option.
5049 tag_default = tag_encode(form=TagFormConstructed, num=17)
5050 asn1_type_name = "SET"
5053 raws = self._encoded_values()
5056 return b"".join((self.tag, len_encode(len(v)), v))
5058 def _specs_items(self):
5059 return iteritems(self.specs)
5061 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5063 t, tlen, lv = tag_strip(tlv)
5064 except DecodeError as err:
5065 raise err.__class__(
5067 klass=self.__class__,
5068 decode_path=decode_path,
5073 klass=self.__class__,
5074 decode_path=decode_path,
5080 ctx_bered = ctx.get("bered", False)
5082 l, llen, v = len_decode(lv)
5083 except LenIndefForm as err:
5085 raise err.__class__(
5087 klass=self.__class__,
5088 decode_path=decode_path,
5091 l, llen, v = 0, 1, lv[1:]
5093 except DecodeError as err:
5094 raise err.__class__(
5096 klass=self.__class__,
5097 decode_path=decode_path,
5101 raise NotEnoughData(
5102 "encoded length is longer than data",
5103 klass=self.__class__,
5107 v, tail = v[:l], v[l:]
5109 sub_offset = offset + tlen + llen
5112 ctx_allow_default_values = ctx.get("allow_default_values", False)
5113 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5114 value_prev = memoryview(v[:0])
5117 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5119 for name, spec in self._specs_items():
5120 sub_decode_path = decode_path + (name,)
5126 decode_path=sub_decode_path,
5129 _ctx_immutable=False,
5136 klass=self.__class__,
5137 decode_path=decode_path,
5140 value, v_tail = spec.decode(
5144 decode_path=sub_decode_path,
5146 _ctx_immutable=False,
5148 value_len = value.fulllen
5149 if value_prev.tobytes() > v[:value_len].tobytes():
5150 if ctx_bered or ctx_allow_unordered_set:
5154 "unordered " + self.asn1_type_name,
5155 klass=self.__class__,
5156 decode_path=sub_decode_path,
5159 if spec.default is None or value != spec.default:
5161 elif ctx_bered or ctx_allow_default_values:
5165 "DEFAULT value met",
5166 klass=self.__class__,
5167 decode_path=sub_decode_path,
5170 values[name] = value
5171 value_prev = v[:value_len]
5172 sub_offset += value_len
5175 obj = self.__class__(
5179 default=self.default,
5180 optional=self.optional,
5181 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5184 if v[:EOC_LEN].tobytes() != EOC:
5187 klass=self.__class__,
5188 decode_path=decode_path,
5196 "not all values are ready",
5197 klass=self.__class__,
5198 decode_path=decode_path,
5201 obj.ber_encoded = ber_encoded
5205 class SequenceOf(Obj):
5206 """``SEQUENCE OF`` sequence type
5208 For that kind of type you must specify the object it will carry on
5209 (bounds are for example here, not required)::
5211 class Ints(SequenceOf):
5216 >>> ints.append(Integer(123))
5217 >>> ints.append(Integer(234))
5219 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5220 >>> [int(i) for i in ints]
5222 >>> ints.append(Integer(345))
5223 Traceback (most recent call last):
5224 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5227 >>> ints[1] = Integer(345)
5229 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5231 Also you can initialize sequence with preinitialized values:
5233 >>> ints = Ints([Integer(123), Integer(234)])
5235 __slots__ = ("spec", "_bound_min", "_bound_max")
5236 tag_default = tag_encode(form=TagFormConstructed, num=16)
5237 asn1_type_name = "SEQUENCE OF"
5250 super(SequenceOf, self).__init__(
5258 schema = getattr(self, "schema", None)
5260 raise ValueError("schema must be specified")
5262 self._bound_min, self._bound_max = getattr(
5266 ) if bounds is None else bounds
5268 if value is not None:
5269 self._value = self._value_sanitize(value)
5270 if default is not None:
5271 default_value = self._value_sanitize(default)
5272 default_obj = self.__class__(
5277 default_obj._value = default_value
5278 self.default = default_obj
5280 self._value = default_obj.copy()._value
5282 def _value_sanitize(self, value):
5283 if issubclass(value.__class__, SequenceOf):
5284 value = value._value
5285 elif hasattr(value, "__iter__"):
5288 raise InvalidValueType((self.__class__, iter))
5289 if not self._bound_min <= len(value) <= self._bound_max:
5290 raise BoundsError(self._bound_min, len(value), self._bound_max)
5292 if not isinstance(v, self.spec.__class__):
5293 raise InvalidValueType((self.spec.__class__,))
5298 return all(v.ready for v in self._value)
5302 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5304 return any(v.bered for v in self._value)
5307 obj = self.__class__(schema=self.spec)
5308 obj._bound_min = self._bound_min
5309 obj._bound_max = self._bound_max
5311 obj._expl = self._expl
5312 obj.default = self.default
5313 obj.optional = self.optional
5314 obj.offset = self.offset
5315 obj.llen = self.llen
5316 obj.vlen = self.vlen
5317 obj.expl_lenindef = self.expl_lenindef
5318 obj.lenindef = self.lenindef
5319 obj.ber_encoded = self.ber_encoded
5320 obj._value = [v.copy() for v in self._value]
5323 def __eq__(self, their):
5324 if isinstance(their, self.__class__):
5326 self.spec == their.spec and
5327 self.tag == their.tag and
5328 self._expl == their._expl and
5329 self._value == their._value
5331 if hasattr(their, "__iter__"):
5332 return self._value == list(their)
5344 return self.__class__(
5348 (self._bound_min, self._bound_max)
5349 if bounds is None else bounds
5351 impl=self.tag if impl is None else impl,
5352 expl=self._expl if expl is None else expl,
5353 default=self.default if default is None else default,
5354 optional=self.optional if optional is None else optional,
5357 def __contains__(self, key):
5358 return key in self._value
5360 def append(self, value):
5361 if not isinstance(value, self.spec.__class__):
5362 raise InvalidValueType((self.spec.__class__,))
5363 if len(self._value) + 1 > self._bound_max:
5366 len(self._value) + 1,
5369 self._value.append(value)
5372 self._assert_ready()
5373 return iter(self._value)
5376 self._assert_ready()
5377 return len(self._value)
5379 def __setitem__(self, key, value):
5380 if not isinstance(value, self.spec.__class__):
5381 raise InvalidValueType((self.spec.__class__,))
5382 self._value[key] = self.spec(value=value)
5384 def __getitem__(self, key):
5385 return self._value[key]
5387 def _encoded_values(self):
5388 return [v.encode() for v in self._value]
5391 v = b"".join(self._encoded_values())
5392 return b"".join((self.tag, len_encode(len(v)), v))
5394 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5396 t, tlen, lv = tag_strip(tlv)
5397 except DecodeError as err:
5398 raise err.__class__(
5400 klass=self.__class__,
5401 decode_path=decode_path,
5406 klass=self.__class__,
5407 decode_path=decode_path,
5413 ctx_bered = ctx.get("bered", False)
5415 l, llen, v = len_decode(lv)
5416 except LenIndefForm as err:
5418 raise err.__class__(
5420 klass=self.__class__,
5421 decode_path=decode_path,
5424 l, llen, v = 0, 1, lv[1:]
5426 except DecodeError as err:
5427 raise err.__class__(
5429 klass=self.__class__,
5430 decode_path=decode_path,
5434 raise NotEnoughData(
5435 "encoded length is longer than data",
5436 klass=self.__class__,
5437 decode_path=decode_path,
5441 v, tail = v[:l], v[l:]
5443 sub_offset = offset + tlen + llen
5445 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5446 value_prev = memoryview(v[:0])
5450 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5452 sub_decode_path = decode_path + (str(len(_value)),)
5453 value, v_tail = spec.decode(
5457 decode_path=sub_decode_path,
5459 _ctx_immutable=False,
5461 value_len = value.fulllen
5463 if value_prev.tobytes() > v[:value_len].tobytes():
5464 if ctx_bered or ctx_allow_unordered_set:
5468 "unordered " + self.asn1_type_name,
5469 klass=self.__class__,
5470 decode_path=sub_decode_path,
5473 value_prev = v[:value_len]
5474 _value.append(value)
5475 sub_offset += value_len
5479 obj = self.__class__(
5482 bounds=(self._bound_min, self._bound_max),
5485 default=self.default,
5486 optional=self.optional,
5487 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5489 except BoundsError as err:
5492 klass=self.__class__,
5493 decode_path=decode_path,
5497 if v[:EOC_LEN].tobytes() != EOC:
5500 klass=self.__class__,
5501 decode_path=decode_path,
5506 obj.ber_encoded = ber_encoded
5511 pp_console_row(next(self.pps())),
5512 ", ".join(repr(v) for v in self._value),
5515 def pps(self, decode_path=()):
5518 asn1_type_name=self.asn1_type_name,
5519 obj_name=self.__class__.__name__,
5520 decode_path=decode_path,
5521 optional=self.optional,
5522 default=self == self.default,
5523 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5524 expl=None if self._expl is None else tag_decode(self._expl),
5529 expl_offset=self.expl_offset if self.expled else None,
5530 expl_tlen=self.expl_tlen if self.expled else None,
5531 expl_llen=self.expl_llen if self.expled else None,
5532 expl_vlen=self.expl_vlen if self.expled else None,
5533 expl_lenindef=self.expl_lenindef,
5534 lenindef=self.lenindef,
5535 ber_encoded=self.ber_encoded,
5538 for i, value in enumerate(self._value):
5539 yield value.pps(decode_path=decode_path + (str(i),))
5540 for pp in self.pps_lenindef(decode_path):
5544 class SetOf(SequenceOf):
5545 """``SET OF`` sequence type
5547 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5550 tag_default = tag_encode(form=TagFormConstructed, num=17)
5551 asn1_type_name = "SET OF"
5554 raws = self._encoded_values()
5557 return b"".join((self.tag, len_encode(len(v)), v))
5559 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5560 return super(SetOf, self)._decode(
5566 ordering_check=True,
5570 def obj_by_path(pypath): # pragma: no cover
5571 """Import object specified as string Python path
5573 Modules must be separated from classes/functions with ``:``.
5575 >>> obj_by_path("foo.bar:Baz")
5576 <class 'foo.bar.Baz'>
5577 >>> obj_by_path("foo.bar:Baz.boo")
5578 <classmethod 'foo.bar.Baz.boo'>
5580 mod, objs = pypath.rsplit(":", 1)
5581 from importlib import import_module
5582 obj = import_module(mod)
5583 for obj_name in objs.split("."):
5584 obj = getattr(obj, obj_name)
5588 def generic_decoder(): # pragma: no cover
5589 # All of this below is a big hack with self references
5590 choice = PrimitiveTypes()
5591 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5592 choice.specs["SetOf"] = SetOf(schema=choice)
5593 for i in six_xrange(31):
5594 choice.specs["SequenceOf%d" % i] = SequenceOf(
5598 choice.specs["Any"] = Any()
5600 # Class name equals to type name, to omit it from output
5601 class SEQUENCEOF(SequenceOf):
5609 with_decode_path=False,
5610 decode_path_only=(),
5612 def _pprint_pps(pps):
5614 if hasattr(pp, "_fields"):
5616 decode_path_only != () and
5617 pp.decode_path[:len(decode_path_only)] != decode_path_only
5620 if pp.asn1_type_name == Choice.asn1_type_name:
5622 pp_kwargs = pp._asdict()
5623 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5624 pp = _pp(**pp_kwargs)
5625 yield pp_console_row(
5630 with_colours=with_colours,
5631 with_decode_path=with_decode_path,
5632 decode_path_len_decrease=len(decode_path_only),
5634 for row in pp_console_blob(
5636 decode_path_len_decrease=len(decode_path_only),
5640 for row in _pprint_pps(pp):
5642 return "\n".join(_pprint_pps(obj.pps()))
5643 return SEQUENCEOF(), pprint_any
5646 def main(): # pragma: no cover
5648 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5649 parser.add_argument(
5653 help="Skip that number of bytes from the beginning",
5655 parser.add_argument(
5657 help="Python path to dictionary with OIDs",
5659 parser.add_argument(
5661 help="Python path to schema definition to use",
5663 parser.add_argument(
5664 "--defines-by-path",
5665 help="Python path to decoder's defines_by_path",
5667 parser.add_argument(
5669 action="store_true",
5670 help="Disallow BER encoding",
5672 parser.add_argument(
5673 "--print-decode-path",
5674 action="store_true",
5675 help="Print decode paths",
5677 parser.add_argument(
5678 "--decode-path-only",
5679 help="Print only specified decode path",
5681 parser.add_argument(
5683 action="store_true",
5684 help="Allow explicit tag out-of-bound",
5686 parser.add_argument(
5688 type=argparse.FileType("rb"),
5689 help="Path to DER file you want to decode",
5691 args = parser.parse_args()
5692 args.DERFile.seek(args.skip)
5693 der = memoryview(args.DERFile.read())
5694 args.DERFile.close()
5695 oids = obj_by_path(args.oids) if args.oids else {}
5697 schema = obj_by_path(args.schema)
5698 from functools import partial
5699 pprinter = partial(pprint, big_blobs=True)
5701 schema, pprinter = generic_decoder()
5703 "bered": not args.nobered,
5704 "allow_expl_oob": args.allow_expl_oob,
5706 if args.defines_by_path is not None:
5707 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5708 obj, tail = schema().decode(der, ctx=ctx)
5712 with_colours=True if environ.get("NO_COLOR") is None else False,
5713 with_decode_path=args.print_decode_path,
5715 () if args.decode_path_only is None else
5716 tuple(args.decode_path_only.split(":"))
5720 print("\nTrailing data: %s" % hexenc(tail))
5723 if __name__ == "__main__":