3 # cython: language_level=3
4 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
5 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, version 3 of the License.
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 <http://www.gnu.org/licenses/>.
18 """Python ASN.1 DER/BER codec with abstract structures
20 This library allows you to marshal various structures in ASN.1 DER
21 format, unmarshal them in BER/CER/DER ones.
25 >>> Integer().decod(raw) == i
28 There are primitive types, holding single values
29 (:py:class:`pyderasn.BitString`,
30 :py:class:`pyderasn.Boolean`,
31 :py:class:`pyderasn.Enumerated`,
32 :py:class:`pyderasn.GeneralizedTime`,
33 :py:class:`pyderasn.Integer`,
34 :py:class:`pyderasn.Null`,
35 :py:class:`pyderasn.ObjectIdentifier`,
36 :py:class:`pyderasn.OctetString`,
37 :py:class:`pyderasn.UTCTime`,
38 :py:class:`various strings <pyderasn.CommonString>`
39 (:py:class:`pyderasn.BMPString`,
40 :py:class:`pyderasn.GeneralString`,
41 :py:class:`pyderasn.GraphicString`,
42 :py:class:`pyderasn.IA5String`,
43 :py:class:`pyderasn.ISO646String`,
44 :py:class:`pyderasn.NumericString`,
45 :py:class:`pyderasn.PrintableString`,
46 :py:class:`pyderasn.T61String`,
47 :py:class:`pyderasn.TeletexString`,
48 :py:class:`pyderasn.UniversalString`,
49 :py:class:`pyderasn.UTF8String`,
50 :py:class:`pyderasn.VideotexString`,
51 :py:class:`pyderasn.VisibleString`)),
52 constructed types, holding multiple primitive types
53 (:py:class:`pyderasn.Sequence`,
54 :py:class:`pyderasn.SequenceOf`,
55 :py:class:`pyderasn.Set`,
56 :py:class:`pyderasn.SetOf`),
57 and special types like
58 :py:class:`pyderasn.Any` and
59 :py:class:`pyderasn.Choice`.
67 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
68 the default tag used during coding process. You can override it with
69 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
70 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
71 argument or ``expl`` class attribute). Both arguments take raw binary
72 string, containing that tag. You can **not** set implicit and explicit
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 are friendly to ``copy.copy()`` and copied objects can be
169 Also all objects can be safely ``pickle``-d, but pay attention that
170 pickling among different PyDERASN versions is prohibited.
177 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
178 ``offset`` optional argument could be used to set initial object's
179 offset in the binary data, for convenience. It returns decoded object
180 and remaining unmarshalled data (tail). Internally all work is done on
181 ``memoryview(data)``, and you can leave returning tail as a memoryview,
182 by specifying ``leavemm=True`` argument.
184 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
185 immediately checks and raises if there is non-empty tail.
187 When object is decoded, ``decoded`` property is true and you can safely
188 use following properties:
190 * ``offset`` -- position including initial offset where object's tag starts
191 * ``tlen`` -- length of object's tag
192 * ``llen`` -- length of object's length value
193 * ``vlen`` -- length of object's value
194 * ``tlvlen`` -- length of the whole object
196 Pay attention that those values do **not** include anything related to
197 explicit tag. If you want to know information about it, then use:
199 * ``expled`` -- to know if explicit tag is set
200 * ``expl_offset`` (it is lesser than ``offset``)
203 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
204 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
206 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
209 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
216 You can specify so called context keyword argument during
217 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
218 various options governing decoding process.
220 Currently available context options:
222 * :ref:`allow_default_values <allow_default_values_ctx>`
223 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
224 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
225 * :ref:`bered <bered_ctx>`
226 * :ref:`defines_by_path <defines_by_path_ctx>`
233 All objects have ``pps()`` method, that is a generator of
234 :py:class:`pyderasn.PP` namedtuple, holding various raw information
235 about the object. If ``pps`` is called on sequences, then all underlying
236 ``PP`` will be yielded.
238 You can use :py:func:`pyderasn.pp_console_row` function, converting
239 those ``PP`` to human readable string. Actually exactly it is used for
240 all object ``repr``. But it is easy to write custom formatters.
242 >>> from pyderasn import pprint
243 >>> encoded = Integer(-12345).encode()
244 >>> obj, tail = Integer().decode(encoded)
245 >>> print(pprint(obj))
246 0 [1,1, 2] INTEGER -12345
250 Example certificate::
252 >>> print(pprint(crt))
253 0 [1,3,1604] Certificate SEQUENCE
254 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
255 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
256 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
257 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
258 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
259 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
261 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
262 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
263 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
264 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
265 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
266 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
267 . . . . . . . 13:02:45:53
269 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
270 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
271 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
273 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
274 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
275 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
280 Let's parse that output, human::
282 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
283 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
284 0 1 2 3 4 5 6 7 8 9 10 11
288 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
294 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
300 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
305 Offset of the object, where its DER/BER encoding begins.
306 Pay attention that it does **not** include explicit tag.
308 If explicit tag exists, then this is its length (tag + encoded length).
310 Length of object's tag. For example CHOICE does not have its own tag,
313 Length of encoded length.
315 Length of encoded value.
317 Visual indentation to show the depth of object in the hierarchy.
319 Object's name inside SEQUENCE/CHOICE.
321 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
322 here. "IMPLICIT" is omitted.
324 Object's class name, if set. Omitted if it is just an ordinary simple
325 value (like with ``algorithm`` in example above).
329 Object's value, if set. Can consist of multiple words (like OCTET/BIT
330 STRINGs above). We see ``v3`` value in Version, because it is named.
331 ``rdnSequence`` is the choice of CHOICE type.
333 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
334 default one, specified in the schema.
336 Shows does object contains any kind of BER encoded data (possibly
337 Sequence holding BER-encoded underlying value).
339 Only applicable to BER encoded data. Indefinite length encoding mark.
341 Only applicable to BER encoded data. If object has BER-specific
342 encoding, then ``BER`` will be shown. It does not depend on indefinite
343 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
344 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
353 ASN.1 structures often have ANY and OCTET STRING fields, that are
354 DEFINED BY some previously met ObjectIdentifier. This library provides
355 ability to specify mapping between some OID and field that must be
356 decoded with specific specification.
363 :py:class:`pyderasn.ObjectIdentifier` field inside
364 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
365 necessary for decoding structures. For example, CMS (:rfc:`5652`)
368 class ContentInfo(Sequence):
370 ("contentType", ContentType(defines=((("content",), {
371 id_digestedData: DigestedData(),
372 id_signedData: SignedData(),
374 ("content", Any(expl=tag_ctxc(0))),
377 ``contentType`` field tells that it defines that ``content`` must be
378 decoded with ``SignedData`` specification, if ``contentType`` equals to
379 ``id-signedData``. The same applies to ``DigestedData``. If
380 ``contentType`` contains unknown OID, then no automatic decoding is
383 You can specify multiple fields, that will be autodecoded -- that is why
384 ``defines`` kwarg is a sequence. You can specify defined field
385 relatively or absolutely to current decode path. For example ``defines``
386 for AlgorithmIdentifier of X.509's
387 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
391 id_ecPublicKey: ECParameters(),
392 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
394 (("..", "subjectPublicKey"), {
395 id_rsaEncryption: RSAPublicKey(),
396 id_GostR3410_2001: OctetString(),
400 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
401 autodecode its parameters inside SPKI's algorithm and its public key
404 Following types can be automatically decoded (DEFINED BY):
406 * :py:class:`pyderasn.Any`
407 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
408 * :py:class:`pyderasn.OctetString`
409 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
410 ``Any``/``BitString``/``OctetString``-s
412 When any of those fields is automatically decoded, then ``.defined``
413 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
414 was defined, ``value`` contains corresponding decoded value. For example
415 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
417 .. _defines_by_path_ctx:
419 defines_by_path context option
420 ______________________________
422 Sometimes you either can not or do not want to explicitly set *defines*
423 in the scheme. You can dynamically apply those definitions when calling
424 ``.decode()`` method.
426 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
427 value must be sequence of following tuples::
429 (decode_path, defines)
431 where ``decode_path`` is a tuple holding so-called decode path to the
432 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
433 ``defines``, holding exactly the same value as accepted in its
434 :ref:`keyword argument <defines>`.
436 For example, again for CMS, you want to automatically decode
437 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
438 structures it may hold. Also, automatically decode ``controlSequence``
441 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
444 ((("content",), {id_signedData: SignedData()}),),
449 DecodePathDefBy(id_signedData),
454 id_cct_PKIData: PKIData(),
455 id_cct_PKIResponse: PKIResponse(),
461 DecodePathDefBy(id_signedData),
464 DecodePathDefBy(id_cct_PKIResponse),
470 id_cmc_recipientNonce: RecipientNonce(),
471 id_cmc_senderNonce: SenderNonce(),
472 id_cmc_statusInfoV2: CMCStatusInfoV2(),
473 id_cmc_transactionId: TransactionId(),
478 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
479 First function is useful for path construction when some automatic
480 decoding is already done. ``any`` means literally any value it meet --
481 useful for SEQUENCE/SET OF-s.
488 By default PyDERASN accepts only DER encoded data. It always encodes to
489 DER. But you can optionally enable BER decoding with setting ``bered``
490 :ref:`context <ctx>` argument to True. Indefinite lengths and
491 constructed primitive types should be parsed successfully.
493 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
494 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
495 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
496 ``UTCTime``, ``GeneralizedTime`` can contain it.
497 * If object has an indefinite length encoding, then its ``lenindef``
498 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
499 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
501 * If object has an indefinite length encoded explicit tag, then
502 ``expl_lenindef`` is set to True.
503 * If object has either any of BER-related encoding (explicit tag
504 indefinite length, object's indefinite length, BER-encoding) or any
505 underlying component has that kind of encoding, then ``bered``
506 attribute is set to True. For example SignedData CMS can have
507 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
508 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
510 EOC (end-of-contents) token's length is taken in advance in object's
513 .. _allow_expl_oob_ctx:
515 Allow explicit tag out-of-bound
516 -------------------------------
518 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
519 one value, more than one object. If you set ``allow_expl_oob`` context
520 option to True, then no error will be raised and that invalid encoding
521 will be silently further processed. But pay attention that offsets and
522 lengths will be invalid in that case.
526 This option should be used only for skipping some decode errors, just
527 to see the decoded structure somehow.
531 .. autoclass:: pyderasn.Obj
539 .. autoclass:: pyderasn.Boolean
544 .. autoclass:: pyderasn.Integer
549 .. autoclass:: pyderasn.BitString
554 .. autoclass:: pyderasn.OctetString
559 .. autoclass:: pyderasn.Null
564 .. autoclass:: pyderasn.ObjectIdentifier
569 .. autoclass:: pyderasn.Enumerated
573 .. autoclass:: pyderasn.CommonString
577 .. autoclass:: pyderasn.NumericString
581 .. autoclass:: pyderasn.PrintableString
586 .. autoclass:: pyderasn.UTCTime
587 :members: __init__, todatetime
591 .. autoclass:: pyderasn.GeneralizedTime
598 .. autoclass:: pyderasn.Choice
603 .. autoclass:: PrimitiveTypes
607 .. autoclass:: pyderasn.Any
615 .. autoclass:: pyderasn.Sequence
620 .. autoclass:: pyderasn.Set
625 .. autoclass:: pyderasn.SequenceOf
630 .. autoclass:: pyderasn.SetOf
636 .. autofunction:: pyderasn.abs_decode_path
637 .. autofunction:: pyderasn.colonize_hex
638 .. autofunction:: pyderasn.hexenc
639 .. autofunction:: pyderasn.hexdec
640 .. autofunction:: pyderasn.tag_encode
641 .. autofunction:: pyderasn.tag_decode
642 .. autofunction:: pyderasn.tag_ctxp
643 .. autofunction:: pyderasn.tag_ctxc
644 .. autoclass:: pyderasn.DecodeError
646 .. autoclass:: pyderasn.NotEnoughData
647 .. autoclass:: pyderasn.ExceedingData
648 .. autoclass:: pyderasn.LenIndefForm
649 .. autoclass:: pyderasn.TagMismatch
650 .. autoclass:: pyderasn.InvalidLength
651 .. autoclass:: pyderasn.InvalidOID
652 .. autoclass:: pyderasn.ObjUnknown
653 .. autoclass:: pyderasn.ObjNotReady
654 .. autoclass:: pyderasn.InvalidValueType
655 .. autoclass:: pyderasn.BoundsError
658 from codecs import getdecoder
659 from codecs import getencoder
660 from collections import namedtuple
661 from collections import OrderedDict
662 from copy import copy
663 from datetime import datetime
664 from datetime import timedelta
665 from math import ceil
666 from os import environ
667 from string import ascii_letters
668 from string import digits
669 from unicodedata import category as unicat
671 from six import add_metaclass
672 from six import binary_type
673 from six import byte2int
674 from six import indexbytes
675 from six import int2byte
676 from six import integer_types
677 from six import iterbytes
678 from six import iteritems
679 from six import itervalues
681 from six import string_types
682 from six import text_type
683 from six import unichr as six_unichr
684 from six.moves import xrange as six_xrange
688 from termcolor import colored
689 except ImportError: # pragma: no cover
690 def colored(what, *args, **kwargs):
736 "TagClassApplication",
740 "TagFormConstructed",
751 TagClassUniversal = 0
752 TagClassApplication = 1 << 6
753 TagClassContext = 1 << 7
754 TagClassPrivate = 1 << 6 | 1 << 7
756 TagFormConstructed = 1 << 5
759 TagClassApplication: "APPLICATION ",
760 TagClassPrivate: "PRIVATE ",
761 TagClassUniversal: "UNIV ",
765 LENINDEF = b"\x80" # length indefinite mark
766 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
767 NAMEDTUPLE_KWARGS = {} if PY2 else {"module": __name__}
770 ########################################################################
772 ########################################################################
774 class ASN1Error(ValueError):
778 class DecodeError(ASN1Error):
779 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
781 :param str msg: reason of decode failing
782 :param klass: optional exact DecodeError inherited class (like
783 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
784 :py:exc:`InvalidLength`)
785 :param decode_path: tuple of strings. It contains human
786 readable names of the fields through which
787 decoding process has passed
788 :param int offset: binary offset where failure happened
790 super(DecodeError, self).__init__()
793 self.decode_path = decode_path
799 "" if self.klass is None else self.klass.__name__,
801 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
802 if len(self.decode_path) > 0 else ""
804 ("(at %d)" % self.offset) if self.offset > 0 else "",
810 return "%s(%s)" % (self.__class__.__name__, self)
813 class NotEnoughData(DecodeError):
817 class ExceedingData(ASN1Error):
818 def __init__(self, nbytes):
819 super(ExceedingData, self).__init__()
823 return "%d trailing bytes" % self.nbytes
826 return "%s(%s)" % (self.__class__.__name__, self)
829 class LenIndefForm(DecodeError):
833 class TagMismatch(DecodeError):
837 class InvalidLength(DecodeError):
841 class InvalidOID(DecodeError):
845 class ObjUnknown(ASN1Error):
846 def __init__(self, name):
847 super(ObjUnknown, self).__init__()
851 return "object is unknown: %s" % self.name
854 return "%s(%s)" % (self.__class__.__name__, self)
857 class ObjNotReady(ASN1Error):
858 def __init__(self, name):
859 super(ObjNotReady, self).__init__()
863 return "object is not ready: %s" % self.name
866 return "%s(%s)" % (self.__class__.__name__, self)
869 class InvalidValueType(ASN1Error):
870 def __init__(self, expected_types):
871 super(InvalidValueType, self).__init__()
872 self.expected_types = expected_types
875 return "invalid value type, expected: %s" % ", ".join(
876 [repr(t) for t in self.expected_types]
880 return "%s(%s)" % (self.__class__.__name__, self)
883 class BoundsError(ASN1Error):
884 def __init__(self, bound_min, value, bound_max):
885 super(BoundsError, self).__init__()
886 self.bound_min = bound_min
888 self.bound_max = bound_max
891 return "unsatisfied bounds: %s <= %s <= %s" % (
898 return "%s(%s)" % (self.__class__.__name__, self)
901 ########################################################################
903 ########################################################################
905 _hexdecoder = getdecoder("hex")
906 _hexencoder = getencoder("hex")
910 """Binary data to hexadecimal string convert
912 return _hexdecoder(data)[0]
916 """Hexadecimal string to binary data convert
918 return _hexencoder(data)[0].decode("ascii")
921 def int_bytes_len(num, byte_len=8):
924 return int(ceil(float(num.bit_length()) / byte_len))
927 def zero_ended_encode(num):
928 octets = bytearray(int_bytes_len(num, 7))
930 octets[i] = num & 0x7F
934 octets[i] = 0x80 | (num & 0x7F)
940 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
941 """Encode tag to binary form
943 :param int num: tag's number
944 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
945 :py:data:`pyderasn.TagClassContext`,
946 :py:data:`pyderasn.TagClassApplication`,
947 :py:data:`pyderasn.TagClassPrivate`)
948 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
949 :py:data:`pyderasn.TagFormConstructed`)
953 return int2byte(klass | form | num)
954 # [XX|X|11111][1.......][1.......] ... [0.......]
955 return int2byte(klass | form | 31) + zero_ended_encode(num)
959 """Decode tag from binary form
963 No validation is performed, assuming that it has already passed.
965 It returns tuple with three integers, as
966 :py:func:`pyderasn.tag_encode` accepts.
968 first_octet = byte2int(tag)
969 klass = first_octet & 0xC0
970 form = first_octet & 0x20
971 if first_octet & 0x1F < 0x1F:
972 return (klass, form, first_octet & 0x1F)
974 for octet in iterbytes(tag[1:]):
977 return (klass, form, num)
981 """Create CONTEXT PRIMITIVE tag
983 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
987 """Create CONTEXT CONSTRUCTED tag
989 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
993 """Take off tag from the data
995 :returns: (encoded tag, tag length, remaining data)
998 raise NotEnoughData("no data at all")
999 if byte2int(data) & 0x1F < 31:
1000 return data[:1], 1, data[1:]
1005 raise DecodeError("unfinished tag")
1006 if indexbytes(data, i) & 0x80 == 0:
1009 return data[:i], i, data[i:]
1015 octets = bytearray(int_bytes_len(l) + 1)
1016 octets[0] = 0x80 | (len(octets) - 1)
1017 for i in six_xrange(len(octets) - 1, 0, -1):
1018 octets[i] = l & 0xFF
1020 return bytes(octets)
1023 def len_decode(data):
1026 :returns: (decoded length, length's length, remaining data)
1027 :raises LenIndefForm: if indefinite form encoding is met
1030 raise NotEnoughData("no data at all")
1031 first_octet = byte2int(data)
1032 if first_octet & 0x80 == 0:
1033 return first_octet, 1, data[1:]
1034 octets_num = first_octet & 0x7F
1035 if octets_num + 1 > len(data):
1036 raise NotEnoughData("encoded length is longer than data")
1038 raise LenIndefForm()
1039 if byte2int(data[1:]) == 0:
1040 raise DecodeError("leading zeros")
1042 for v in iterbytes(data[1:1 + octets_num]):
1045 raise DecodeError("long form instead of short one")
1046 return l, 1 + octets_num, data[1 + octets_num:]
1049 ########################################################################
1051 ########################################################################
1053 class AutoAddSlots(type):
1054 def __new__(cls, name, bases, _dict):
1055 _dict["__slots__"] = _dict.get("__slots__", ())
1056 return type.__new__(cls, name, bases, _dict)
1059 @add_metaclass(AutoAddSlots)
1061 """Common ASN.1 object class
1063 All ASN.1 types are inherited from it. It has metaclass that
1064 automatically adds ``__slots__`` to all inherited classes.
1088 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1089 self._expl = getattr(self, "expl", None) if expl is None else expl
1090 if self.tag != self.tag_default and self._expl is not None:
1091 raise ValueError("implicit and explicit tags can not be set simultaneously")
1092 if default is not None:
1094 self.optional = optional
1095 self.offset, self.llen, self.vlen = _decoded
1097 self.expl_lenindef = False
1098 self.lenindef = False
1099 self.ber_encoded = False
1102 def ready(self): # pragma: no cover
1103 """Is object ready to be encoded?
1105 raise NotImplementedError()
1107 def _assert_ready(self):
1109 raise ObjNotReady(self.__class__.__name__)
1113 """Is either object or any elements inside is BER encoded?
1115 return self.expl_lenindef or self.lenindef or self.ber_encoded
1119 """Is object decoded?
1121 return (self.llen + self.vlen) > 0
1123 def __getstate__(self): # pragma: no cover
1124 """Used for making safe to be mutable pickleable copies
1126 raise NotImplementedError()
1128 def __setstate__(self, state):
1129 if state.version != __version__:
1130 raise ValueError("data is pickled by different PyDERASN version")
1131 self.tag = self.tag_default
1135 self.optional = False
1139 self.expl_lenindef = False
1140 self.lenindef = False
1141 self.ber_encoded = False
1145 """See :ref:`decoding`
1147 return len(self.tag)
1151 """See :ref:`decoding`
1153 return self.tlen + self.llen + self.vlen
1155 def __str__(self): # pragma: no cover
1156 return self.__bytes__() if PY2 else self.__unicode__()
1158 def __ne__(self, their):
1159 return not(self == their)
1161 def __gt__(self, their): # pragma: no cover
1162 return not(self < their)
1164 def __le__(self, their): # pragma: no cover
1165 return (self == their) or (self < their)
1167 def __ge__(self, their): # pragma: no cover
1168 return (self == their) or (self > their)
1170 def _encode(self): # pragma: no cover
1171 raise NotImplementedError()
1173 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1174 raise NotImplementedError()
1177 """Encode the structure
1179 :returns: DER representation
1181 raw = self._encode()
1182 if self._expl is None:
1184 return b"".join((self._expl, len_encode(len(raw)), raw))
1186 def hexencode(self):
1187 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1189 return hexenc(self.encode())
1199 _ctx_immutable=True,
1203 :param data: either binary or memoryview
1204 :param int offset: initial data's offset
1205 :param bool leavemm: do we need to leave memoryview of remaining
1206 data as is, or convert it to bytes otherwise
1207 :param ctx: optional :ref:`context <ctx>` governing decoding process
1208 :param tag_only: decode only the tag, without length and contents
1209 (used only in Choice and Set structures, trying to
1210 determine if tag satisfies the scheme)
1211 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1213 :returns: (Obj, remaining data)
1215 .. seealso:: :ref:`decoding`
1219 elif _ctx_immutable:
1221 tlv = memoryview(data)
1222 if self._expl is None:
1223 result = self._decode(
1226 decode_path=decode_path,
1235 t, tlen, lv = tag_strip(tlv)
1236 except DecodeError as err:
1237 raise err.__class__(
1239 klass=self.__class__,
1240 decode_path=decode_path,
1245 klass=self.__class__,
1246 decode_path=decode_path,
1250 l, llen, v = len_decode(lv)
1251 except LenIndefForm as err:
1252 if not ctx.get("bered", False):
1253 raise err.__class__(
1255 klass=self.__class__,
1256 decode_path=decode_path,
1260 offset += tlen + llen
1261 result = self._decode(
1264 decode_path=decode_path,
1268 if tag_only: # pragma: no cover
1271 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1272 if eoc_expected.tobytes() != EOC:
1275 klass=self.__class__,
1276 decode_path=decode_path,
1280 obj.expl_lenindef = True
1281 except DecodeError as err:
1282 raise err.__class__(
1284 klass=self.__class__,
1285 decode_path=decode_path,
1290 raise NotEnoughData(
1291 "encoded length is longer than data",
1292 klass=self.__class__,
1293 decode_path=decode_path,
1296 result = self._decode(
1298 offset=offset + tlen + llen,
1299 decode_path=decode_path,
1303 if tag_only: # pragma: no cover
1306 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1308 "explicit tag out-of-bound, longer than data",
1309 klass=self.__class__,
1310 decode_path=decode_path,
1313 return obj, (tail if leavemm else tail.tobytes())
1315 def decod(self, data, offset=0, decode_path=(), ctx=None):
1316 """Decode the data, check that tail is empty
1318 :raises ExceedingData: if tail is not empty
1320 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1321 (decode without tail) that also checks that there is no
1324 obj, tail = self.decode(
1327 decode_path=decode_path,
1332 raise ExceedingData(len(tail))
1335 def hexdecode(self, data, *args, **kwargs):
1336 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1338 return self.decode(hexdec(data), *args, **kwargs)
1340 def hexdecod(self, data, *args, **kwargs):
1341 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1343 return self.decod(hexdec(data), *args, **kwargs)
1347 """See :ref:`decoding`
1349 return self._expl is not None
1353 """See :ref:`decoding`
1358 def expl_tlen(self):
1359 """See :ref:`decoding`
1361 return len(self._expl)
1364 def expl_llen(self):
1365 """See :ref:`decoding`
1367 if self.expl_lenindef:
1369 return len(len_encode(self.tlvlen))
1372 def expl_offset(self):
1373 """See :ref:`decoding`
1375 return self.offset - self.expl_tlen - self.expl_llen
1378 def expl_vlen(self):
1379 """See :ref:`decoding`
1384 def expl_tlvlen(self):
1385 """See :ref:`decoding`
1387 return self.expl_tlen + self.expl_llen + self.expl_vlen
1390 def fulloffset(self):
1391 """See :ref:`decoding`
1393 return self.expl_offset if self.expled else self.offset
1397 """See :ref:`decoding`
1399 return self.expl_tlvlen if self.expled else self.tlvlen
1401 def pps_lenindef(self, decode_path):
1402 if self.lenindef and not (
1403 getattr(self, "defined", None) is not None and
1404 self.defined[1].lenindef
1407 asn1_type_name="EOC",
1409 decode_path=decode_path,
1411 self.offset + self.tlvlen -
1412 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1420 if self.expl_lenindef:
1422 asn1_type_name="EOC",
1423 obj_name="EXPLICIT",
1424 decode_path=decode_path,
1425 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1434 class DecodePathDefBy(object):
1435 """DEFINED BY representation inside decode path
1437 __slots__ = ("defined_by",)
1439 def __init__(self, defined_by):
1440 self.defined_by = defined_by
1442 def __ne__(self, their):
1443 return not(self == their)
1445 def __eq__(self, their):
1446 if not isinstance(their, self.__class__):
1448 return self.defined_by == their.defined_by
1451 return "DEFINED BY " + str(self.defined_by)
1454 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1457 ########################################################################
1459 ########################################################################
1461 PP = namedtuple("PP", (
1484 ), **NAMEDTUPLE_KWARGS)
1489 asn1_type_name="unknown",
1506 expl_lenindef=False,
1537 def _colourize(what, colour, with_colours, attrs=("bold",)):
1538 return colored(what, colour, attrs=attrs) if with_colours else what
1541 def colonize_hex(hexed):
1542 """Separate hexadecimal string with colons
1544 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1553 with_decode_path=False,
1554 decode_path_len_decrease=0,
1561 " " if pp.expl_offset is None else
1562 ("-%d" % (pp.offset - pp.expl_offset))
1564 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1566 col = _colourize(col, "red", with_colours, ())
1567 col += _colourize("B", "red", with_colours) if pp.bered else " "
1569 col = "[%d,%d,%4d]%s" % (
1573 LENINDEF_PP_CHAR if pp.lenindef else " "
1575 col = _colourize(col, "green", with_colours, ())
1577 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1578 if decode_path_len > 0:
1579 cols.append(" ." * decode_path_len)
1580 ent = pp.decode_path[-1]
1581 if isinstance(ent, DecodePathDefBy):
1582 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1583 value = str(ent.defined_by)
1586 len(oid_maps) > 0 and
1587 ent.defined_by.asn1_type_name ==
1588 ObjectIdentifier.asn1_type_name
1590 for oid_map in oid_maps:
1591 oid_name = oid_map.get(value)
1592 if oid_name is not None:
1593 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1595 if oid_name is None:
1596 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1598 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1599 if pp.expl is not None:
1600 klass, _, num = pp.expl
1601 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1602 cols.append(_colourize(col, "blue", with_colours))
1603 if pp.impl is not None:
1604 klass, _, num = pp.impl
1605 col = "[%s%d]" % (TagClassReprs[klass], num)
1606 cols.append(_colourize(col, "blue", with_colours))
1607 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1608 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1610 cols.append(_colourize("BER", "red", with_colours))
1611 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1612 if pp.value is not None:
1614 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1616 len(oid_maps) > 0 and
1617 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1619 for oid_map in oid_maps:
1620 oid_name = oid_map.get(value)
1621 if oid_name is not None:
1622 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1624 if pp.asn1_type_name == Integer.asn1_type_name:
1625 hex_repr = hex(int(pp.obj._value))[2:].upper()
1626 if len(hex_repr) % 2 != 0:
1627 hex_repr = "0" + hex_repr
1628 cols.append(_colourize(
1629 "(%s)" % colonize_hex(hex_repr),
1634 if isinstance(pp.blob, binary_type):
1635 cols.append(hexenc(pp.blob))
1636 elif isinstance(pp.blob, tuple):
1637 cols.append(", ".join(pp.blob))
1639 cols.append(_colourize("OPTIONAL", "red", with_colours))
1641 cols.append(_colourize("DEFAULT", "red", with_colours))
1642 if with_decode_path:
1643 cols.append(_colourize(
1644 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1648 return " ".join(cols)
1651 def pp_console_blob(pp, decode_path_len_decrease=0):
1652 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1653 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1654 if decode_path_len > 0:
1655 cols.append(" ." * (decode_path_len + 1))
1656 if isinstance(pp.blob, binary_type):
1657 blob = hexenc(pp.blob).upper()
1658 for i in six_xrange(0, len(blob), 32):
1659 chunk = blob[i:i + 32]
1660 yield " ".join(cols + [colonize_hex(chunk)])
1661 elif isinstance(pp.blob, tuple):
1662 yield " ".join(cols + [", ".join(pp.blob)])
1670 with_decode_path=False,
1671 decode_path_only=(),
1673 """Pretty print object
1675 :param Obj obj: object you want to pretty print
1676 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1677 Its human readable form is printed when OID is met
1678 :param big_blobs: if large binary objects are met (like OctetString
1679 values), do we need to print them too, on separate
1681 :param with_colours: colourize output, if ``termcolor`` library
1683 :param with_decode_path: print decode path
1684 :param decode_path_only: print only that specified decode path
1686 def _pprint_pps(pps):
1688 if hasattr(pp, "_fields"):
1690 decode_path_only != () and
1692 str(p) for p in pp.decode_path[:len(decode_path_only)]
1693 ) != decode_path_only
1697 yield pp_console_row(
1702 with_colours=with_colours,
1703 with_decode_path=with_decode_path,
1704 decode_path_len_decrease=len(decode_path_only),
1706 for row in pp_console_blob(
1708 decode_path_len_decrease=len(decode_path_only),
1712 yield pp_console_row(
1717 with_colours=with_colours,
1718 with_decode_path=with_decode_path,
1719 decode_path_len_decrease=len(decode_path_only),
1722 for row in _pprint_pps(pp):
1724 return "\n".join(_pprint_pps(obj.pps()))
1727 ########################################################################
1728 # ASN.1 primitive types
1729 ########################################################################
1731 BooleanState = namedtuple("BooleanState", (
1744 ), **NAMEDTUPLE_KWARGS)
1748 """``BOOLEAN`` boolean type
1750 >>> b = Boolean(True)
1752 >>> b == Boolean(True)
1758 tag_default = tag_encode(1)
1759 asn1_type_name = "BOOLEAN"
1771 :param value: set the value. Either boolean type, or
1772 :py:class:`pyderasn.Boolean` object
1773 :param bytes impl: override default tag with ``IMPLICIT`` one
1774 :param bytes expl: override default tag with ``EXPLICIT`` one
1775 :param default: set default value. Type same as in ``value``
1776 :param bool optional: is object ``OPTIONAL`` in sequence
1778 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1779 self._value = None if value is None else self._value_sanitize(value)
1780 if default is not None:
1781 default = self._value_sanitize(default)
1782 self.default = self.__class__(
1788 self._value = default
1790 def _value_sanitize(self, value):
1791 if isinstance(value, bool):
1793 if issubclass(value.__class__, Boolean):
1795 raise InvalidValueType((self.__class__, bool))
1799 return self._value is not None
1801 def __getstate__(self):
1802 return BooleanState(
1817 def __setstate__(self, state):
1818 super(Boolean, self).__setstate__(state)
1819 self._value = state.value
1820 self.tag = state.tag
1821 self._expl = state.expl
1822 self.default = state.default
1823 self.optional = state.optional
1824 self.offset = state.offset
1825 self.llen = state.llen
1826 self.vlen = state.vlen
1827 self.expl_lenindef = state.expl_lenindef
1828 self.lenindef = state.lenindef
1829 self.ber_encoded = state.ber_encoded
1831 def __nonzero__(self):
1832 self._assert_ready()
1836 self._assert_ready()
1839 def __eq__(self, their):
1840 if isinstance(their, bool):
1841 return self._value == their
1842 if not issubclass(their.__class__, Boolean):
1845 self._value == their._value and
1846 self.tag == their.tag and
1847 self._expl == their._expl
1858 return self.__class__(
1860 impl=self.tag if impl is None else impl,
1861 expl=self._expl if expl is None else expl,
1862 default=self.default if default is None else default,
1863 optional=self.optional if optional is None else optional,
1867 self._assert_ready()
1871 (b"\xFF" if self._value else b"\x00"),
1874 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1876 t, _, lv = tag_strip(tlv)
1877 except DecodeError as err:
1878 raise err.__class__(
1880 klass=self.__class__,
1881 decode_path=decode_path,
1886 klass=self.__class__,
1887 decode_path=decode_path,
1893 l, _, v = len_decode(lv)
1894 except DecodeError as err:
1895 raise err.__class__(
1897 klass=self.__class__,
1898 decode_path=decode_path,
1902 raise InvalidLength(
1903 "Boolean's length must be equal to 1",
1904 klass=self.__class__,
1905 decode_path=decode_path,
1909 raise NotEnoughData(
1910 "encoded length is longer than data",
1911 klass=self.__class__,
1912 decode_path=decode_path,
1915 first_octet = byte2int(v)
1917 if first_octet == 0:
1919 elif first_octet == 0xFF:
1921 elif ctx.get("bered", False):
1926 "unacceptable Boolean value",
1927 klass=self.__class__,
1928 decode_path=decode_path,
1931 obj = self.__class__(
1935 default=self.default,
1936 optional=self.optional,
1937 _decoded=(offset, 1, 1),
1939 obj.ber_encoded = ber_encoded
1943 return pp_console_row(next(self.pps()))
1945 def pps(self, decode_path=()):
1948 asn1_type_name=self.asn1_type_name,
1949 obj_name=self.__class__.__name__,
1950 decode_path=decode_path,
1951 value=str(self._value) if self.ready else None,
1952 optional=self.optional,
1953 default=self == self.default,
1954 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1955 expl=None if self._expl is None else tag_decode(self._expl),
1960 expl_offset=self.expl_offset if self.expled else None,
1961 expl_tlen=self.expl_tlen if self.expled else None,
1962 expl_llen=self.expl_llen if self.expled else None,
1963 expl_vlen=self.expl_vlen if self.expled else None,
1964 expl_lenindef=self.expl_lenindef,
1965 ber_encoded=self.ber_encoded,
1968 for pp in self.pps_lenindef(decode_path):
1972 IntegerState = namedtuple("IntegerState", (
1988 ), **NAMEDTUPLE_KWARGS)
1992 """``INTEGER`` integer type
1994 >>> b = Integer(-123)
1996 >>> b == Integer(-123)
2001 >>> Integer(2, bounds=(1, 3))
2003 >>> Integer(5, bounds=(1, 3))
2004 Traceback (most recent call last):
2005 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2009 class Version(Integer):
2016 >>> v = Version("v1")
2023 {'v3': 2, 'v1': 0, 'v2': 1}
2025 __slots__ = ("specs", "_bound_min", "_bound_max")
2026 tag_default = tag_encode(2)
2027 asn1_type_name = "INTEGER"
2041 :param value: set the value. Either integer type, named value
2042 (if ``schema`` is specified in the class), or
2043 :py:class:`pyderasn.Integer` object
2044 :param bounds: set ``(MIN, MAX)`` value constraint.
2045 (-inf, +inf) by default
2046 :param bytes impl: override default tag with ``IMPLICIT`` one
2047 :param bytes expl: override default tag with ``EXPLICIT`` one
2048 :param default: set default value. Type same as in ``value``
2049 :param bool optional: is object ``OPTIONAL`` in sequence
2051 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2053 specs = getattr(self, "schema", {}) if _specs is None else _specs
2054 self.specs = specs if isinstance(specs, dict) else dict(specs)
2055 self._bound_min, self._bound_max = getattr(
2058 (float("-inf"), float("+inf")),
2059 ) if bounds is None else bounds
2060 if value is not None:
2061 self._value = self._value_sanitize(value)
2062 if default is not None:
2063 default = self._value_sanitize(default)
2064 self.default = self.__class__(
2070 if self._value is None:
2071 self._value = default
2073 def _value_sanitize(self, value):
2074 if isinstance(value, integer_types):
2076 elif issubclass(value.__class__, Integer):
2077 value = value._value
2078 elif isinstance(value, str):
2079 value = self.specs.get(value)
2081 raise ObjUnknown("integer value: %s" % value)
2083 raise InvalidValueType((self.__class__, int, str))
2084 if not self._bound_min <= value <= self._bound_max:
2085 raise BoundsError(self._bound_min, value, self._bound_max)
2090 return self._value is not None
2092 def __getstate__(self):
2093 return IntegerState(
2111 def __setstate__(self, state):
2112 super(Integer, self).__setstate__(state)
2113 self.specs = state.specs
2114 self._value = state.value
2115 self._bound_min = state.bound_min
2116 self._bound_max = state.bound_max
2117 self.tag = state.tag
2118 self._expl = state.expl
2119 self.default = state.default
2120 self.optional = state.optional
2121 self.offset = state.offset
2122 self.llen = state.llen
2123 self.vlen = state.vlen
2124 self.expl_lenindef = state.expl_lenindef
2125 self.lenindef = state.lenindef
2126 self.ber_encoded = state.ber_encoded
2129 self._assert_ready()
2130 return int(self._value)
2133 self._assert_ready()
2136 bytes(self._expl or b"") +
2137 str(self._value).encode("ascii"),
2140 def __eq__(self, their):
2141 if isinstance(their, integer_types):
2142 return self._value == their
2143 if not issubclass(their.__class__, Integer):
2146 self._value == their._value and
2147 self.tag == their.tag and
2148 self._expl == their._expl
2151 def __lt__(self, their):
2152 return self._value < their._value
2156 for name, value in iteritems(self.specs):
2157 if value == self._value:
2170 return self.__class__(
2173 (self._bound_min, self._bound_max)
2174 if bounds is None else bounds
2176 impl=self.tag if impl is None else impl,
2177 expl=self._expl if expl is None else expl,
2178 default=self.default if default is None else default,
2179 optional=self.optional if optional is None else optional,
2184 self._assert_ready()
2188 octets = bytearray([0])
2192 octets = bytearray()
2194 octets.append((value & 0xFF) ^ 0xFF)
2196 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2199 octets = bytearray()
2201 octets.append(value & 0xFF)
2203 if octets[-1] & 0x80 > 0:
2206 octets = bytes(octets)
2208 bytes_len = ceil(value.bit_length() / 8) or 1
2211 octets = value.to_bytes(
2216 except OverflowError:
2220 return b"".join((self.tag, len_encode(len(octets)), octets))
2222 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2224 t, _, lv = tag_strip(tlv)
2225 except DecodeError as err:
2226 raise err.__class__(
2228 klass=self.__class__,
2229 decode_path=decode_path,
2234 klass=self.__class__,
2235 decode_path=decode_path,
2241 l, llen, v = len_decode(lv)
2242 except DecodeError as err:
2243 raise err.__class__(
2245 klass=self.__class__,
2246 decode_path=decode_path,
2250 raise NotEnoughData(
2251 "encoded length is longer than data",
2252 klass=self.__class__,
2253 decode_path=decode_path,
2257 raise NotEnoughData(
2259 klass=self.__class__,
2260 decode_path=decode_path,
2263 v, tail = v[:l], v[l:]
2264 first_octet = byte2int(v)
2266 second_octet = byte2int(v[1:])
2268 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2269 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2272 "non normalized integer",
2273 klass=self.__class__,
2274 decode_path=decode_path,
2279 if first_octet & 0x80 > 0:
2280 octets = bytearray()
2281 for octet in bytearray(v):
2282 octets.append(octet ^ 0xFF)
2283 for octet in octets:
2284 value = (value << 8) | octet
2288 for octet in bytearray(v):
2289 value = (value << 8) | octet
2291 value = int.from_bytes(v, byteorder="big", signed=True)
2293 obj = self.__class__(
2295 bounds=(self._bound_min, self._bound_max),
2298 default=self.default,
2299 optional=self.optional,
2301 _decoded=(offset, llen, l),
2303 except BoundsError as err:
2306 klass=self.__class__,
2307 decode_path=decode_path,
2313 return pp_console_row(next(self.pps()))
2315 def pps(self, decode_path=()):
2318 asn1_type_name=self.asn1_type_name,
2319 obj_name=self.__class__.__name__,
2320 decode_path=decode_path,
2321 value=(self.named or str(self._value)) if self.ready else None,
2322 optional=self.optional,
2323 default=self == self.default,
2324 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2325 expl=None if self._expl is None else tag_decode(self._expl),
2330 expl_offset=self.expl_offset if self.expled else None,
2331 expl_tlen=self.expl_tlen if self.expled else None,
2332 expl_llen=self.expl_llen if self.expled else None,
2333 expl_vlen=self.expl_vlen if self.expled else None,
2334 expl_lenindef=self.expl_lenindef,
2337 for pp in self.pps_lenindef(decode_path):
2341 SET01 = frozenset(("0", "1"))
2342 BitStringState = namedtuple("BitStringState", (
2358 ), **NAMEDTUPLE_KWARGS)
2361 class BitString(Obj):
2362 """``BIT STRING`` bit string type
2364 >>> BitString(b"hello world")
2365 BIT STRING 88 bits 68656c6c6f20776f726c64
2368 >>> b == b"hello world"
2373 >>> BitString("'0A3B5F291CD'H")
2374 BIT STRING 44 bits 0a3b5f291cd0
2375 >>> b = BitString("'010110000000'B")
2376 BIT STRING 12 bits 5800
2379 >>> b[0], b[1], b[2], b[3]
2380 (False, True, False, True)
2384 [False, True, False, True, True, False, False, False, False, False, False, False]
2388 class KeyUsage(BitString):
2390 ("digitalSignature", 0),
2391 ("nonRepudiation", 1),
2392 ("keyEncipherment", 2),
2395 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2396 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2398 ['nonRepudiation', 'keyEncipherment']
2400 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2404 Pay attention that BIT STRING can be encoded both in primitive
2405 and constructed forms. Decoder always checks constructed form tag
2406 additionally to specified primitive one. If BER decoding is
2407 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2408 of DER restrictions.
2410 __slots__ = ("tag_constructed", "specs", "defined")
2411 tag_default = tag_encode(3)
2412 asn1_type_name = "BIT STRING"
2425 :param value: set the value. Either binary type, tuple of named
2426 values (if ``schema`` is specified in the class),
2427 string in ``'XXX...'B`` form, or
2428 :py:class:`pyderasn.BitString` object
2429 :param bytes impl: override default tag with ``IMPLICIT`` one
2430 :param bytes expl: override default tag with ``EXPLICIT`` one
2431 :param default: set default value. Type same as in ``value``
2432 :param bool optional: is object ``OPTIONAL`` in sequence
2434 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2435 specs = getattr(self, "schema", {}) if _specs is None else _specs
2436 self.specs = specs if isinstance(specs, dict) else dict(specs)
2437 self._value = None if value is None else self._value_sanitize(value)
2438 if default is not None:
2439 default = self._value_sanitize(default)
2440 self.default = self.__class__(
2446 self._value = default
2448 tag_klass, _, tag_num = tag_decode(self.tag)
2449 self.tag_constructed = tag_encode(
2451 form=TagFormConstructed,
2455 def _bits2octets(self, bits):
2456 if len(self.specs) > 0:
2457 bits = bits.rstrip("0")
2459 bits += "0" * ((8 - (bit_len % 8)) % 8)
2460 octets = bytearray(len(bits) // 8)
2461 for i in six_xrange(len(octets)):
2462 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2463 return bit_len, bytes(octets)
2465 def _value_sanitize(self, value):
2466 if isinstance(value, (string_types, binary_type)):
2468 isinstance(value, string_types) and
2469 value.startswith("'")
2471 if value.endswith("'B"):
2473 if not frozenset(value) <= SET01:
2474 raise ValueError("B's coding contains unacceptable chars")
2475 return self._bits2octets(value)
2476 if value.endswith("'H"):
2480 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2482 if isinstance(value, binary_type):
2483 return (len(value) * 8, value)
2484 raise InvalidValueType((self.__class__, string_types, binary_type))
2485 if isinstance(value, tuple):
2488 isinstance(value[0], integer_types) and
2489 isinstance(value[1], binary_type)
2494 bit = self.specs.get(name)
2496 raise ObjUnknown("BitString value: %s" % name)
2499 return self._bits2octets("")
2500 bits = frozenset(bits)
2501 return self._bits2octets("".join(
2502 ("1" if bit in bits else "0")
2503 for bit in six_xrange(max(bits) + 1)
2505 if issubclass(value.__class__, BitString):
2507 raise InvalidValueType((self.__class__, binary_type, string_types))
2511 return self._value is not None
2513 def __getstate__(self):
2514 return BitStringState(
2528 self.tag_constructed,
2532 def __setstate__(self, state):
2533 super(BitString, self).__setstate__(state)
2534 self.specs = state.specs
2535 self._value = state.value
2536 self.tag = state.tag
2537 self._expl = state.expl
2538 self.default = state.default
2539 self.optional = state.optional
2540 self.offset = state.offset
2541 self.llen = state.llen
2542 self.vlen = state.vlen
2543 self.expl_lenindef = state.expl_lenindef
2544 self.lenindef = state.lenindef
2545 self.ber_encoded = state.ber_encoded
2546 self.tag_constructed = state.tag_constructed
2547 self.defined = state.defined
2550 self._assert_ready()
2551 for i in six_xrange(self._value[0]):
2556 self._assert_ready()
2557 return self._value[0]
2559 def __bytes__(self):
2560 self._assert_ready()
2561 return self._value[1]
2563 def __eq__(self, their):
2564 if isinstance(their, bytes):
2565 return self._value[1] == their
2566 if not issubclass(their.__class__, BitString):
2569 self._value == their._value and
2570 self.tag == their.tag and
2571 self._expl == their._expl
2576 return [name for name, bit in iteritems(self.specs) if self[bit]]
2586 return self.__class__(
2588 impl=self.tag if impl is None else impl,
2589 expl=self._expl if expl is None else expl,
2590 default=self.default if default is None else default,
2591 optional=self.optional if optional is None else optional,
2595 def __getitem__(self, key):
2596 if isinstance(key, int):
2597 bit_len, octets = self._value
2601 byte2int(memoryview(octets)[key // 8:]) >>
2604 if isinstance(key, string_types):
2605 value = self.specs.get(key)
2607 raise ObjUnknown("BitString value: %s" % key)
2609 raise InvalidValueType((int, str))
2612 self._assert_ready()
2613 bit_len, octets = self._value
2616 len_encode(len(octets) + 1),
2617 int2byte((8 - bit_len % 8) % 8),
2621 def _decode_chunk(self, lv, offset, decode_path):
2623 l, llen, v = len_decode(lv)
2624 except DecodeError as err:
2625 raise err.__class__(
2627 klass=self.__class__,
2628 decode_path=decode_path,
2632 raise NotEnoughData(
2633 "encoded length is longer than data",
2634 klass=self.__class__,
2635 decode_path=decode_path,
2639 raise NotEnoughData(
2641 klass=self.__class__,
2642 decode_path=decode_path,
2645 pad_size = byte2int(v)
2646 if l == 1 and pad_size != 0:
2648 "invalid empty value",
2649 klass=self.__class__,
2650 decode_path=decode_path,
2656 klass=self.__class__,
2657 decode_path=decode_path,
2660 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2663 klass=self.__class__,
2664 decode_path=decode_path,
2667 v, tail = v[:l], v[l:]
2668 obj = self.__class__(
2669 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2672 default=self.default,
2673 optional=self.optional,
2675 _decoded=(offset, llen, l),
2679 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2681 t, tlen, lv = tag_strip(tlv)
2682 except DecodeError as err:
2683 raise err.__class__(
2685 klass=self.__class__,
2686 decode_path=decode_path,
2690 if tag_only: # pragma: no cover
2692 return self._decode_chunk(lv, offset, decode_path)
2693 if t == self.tag_constructed:
2694 if not ctx.get("bered", False):
2696 "unallowed BER constructed encoding",
2697 klass=self.__class__,
2698 decode_path=decode_path,
2701 if tag_only: # pragma: no cover
2705 l, llen, v = len_decode(lv)
2706 except LenIndefForm:
2707 llen, l, v = 1, 0, lv[1:]
2709 except DecodeError as err:
2710 raise err.__class__(
2712 klass=self.__class__,
2713 decode_path=decode_path,
2717 raise NotEnoughData(
2718 "encoded length is longer than data",
2719 klass=self.__class__,
2720 decode_path=decode_path,
2723 if not lenindef and l == 0:
2724 raise NotEnoughData(
2726 klass=self.__class__,
2727 decode_path=decode_path,
2731 sub_offset = offset + tlen + llen
2735 if v[:EOC_LEN].tobytes() == EOC:
2742 "chunk out of bounds",
2743 klass=self.__class__,
2744 decode_path=decode_path + (str(len(chunks) - 1),),
2745 offset=chunks[-1].offset,
2747 sub_decode_path = decode_path + (str(len(chunks)),)
2749 chunk, v_tail = BitString().decode(
2752 decode_path=sub_decode_path,
2755 _ctx_immutable=False,
2759 "expected BitString encoded chunk",
2760 klass=self.__class__,
2761 decode_path=sub_decode_path,
2764 chunks.append(chunk)
2765 sub_offset += chunk.tlvlen
2766 vlen += chunk.tlvlen
2768 if len(chunks) == 0:
2771 klass=self.__class__,
2772 decode_path=decode_path,
2777 for chunk_i, chunk in enumerate(chunks[:-1]):
2778 if chunk.bit_len % 8 != 0:
2780 "BitString chunk is not multiple of 8 bits",
2781 klass=self.__class__,
2782 decode_path=decode_path + (str(chunk_i),),
2783 offset=chunk.offset,
2785 values.append(bytes(chunk))
2786 bit_len += chunk.bit_len
2787 chunk_last = chunks[-1]
2788 values.append(bytes(chunk_last))
2789 bit_len += chunk_last.bit_len
2790 obj = self.__class__(
2791 value=(bit_len, b"".join(values)),
2794 default=self.default,
2795 optional=self.optional,
2797 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2799 obj.lenindef = lenindef
2800 obj.ber_encoded = True
2801 return obj, (v[EOC_LEN:] if lenindef else v)
2803 klass=self.__class__,
2804 decode_path=decode_path,
2809 return pp_console_row(next(self.pps()))
2811 def pps(self, decode_path=()):
2815 bit_len, blob = self._value
2816 value = "%d bits" % bit_len
2817 if len(self.specs) > 0:
2818 blob = tuple(self.named)
2821 asn1_type_name=self.asn1_type_name,
2822 obj_name=self.__class__.__name__,
2823 decode_path=decode_path,
2826 optional=self.optional,
2827 default=self == self.default,
2828 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2829 expl=None if self._expl is None else tag_decode(self._expl),
2834 expl_offset=self.expl_offset if self.expled else None,
2835 expl_tlen=self.expl_tlen if self.expled else None,
2836 expl_llen=self.expl_llen if self.expled else None,
2837 expl_vlen=self.expl_vlen if self.expled else None,
2838 expl_lenindef=self.expl_lenindef,
2839 lenindef=self.lenindef,
2840 ber_encoded=self.ber_encoded,
2843 defined_by, defined = self.defined or (None, None)
2844 if defined_by is not None:
2846 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2848 for pp in self.pps_lenindef(decode_path):
2852 OctetStringState = namedtuple("OctetStringState", (
2869 ), **NAMEDTUPLE_KWARGS)
2872 class OctetString(Obj):
2873 """``OCTET STRING`` binary string type
2875 >>> s = OctetString(b"hello world")
2876 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2877 >>> s == OctetString(b"hello world")
2882 >>> OctetString(b"hello", bounds=(4, 4))
2883 Traceback (most recent call last):
2884 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2885 >>> OctetString(b"hell", bounds=(4, 4))
2886 OCTET STRING 4 bytes 68656c6c
2890 Pay attention that OCTET STRING can be encoded both in primitive
2891 and constructed forms. Decoder always checks constructed form tag
2892 additionally to specified primitive one. If BER decoding is
2893 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2894 of DER restrictions.
2896 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2897 tag_default = tag_encode(4)
2898 asn1_type_name = "OCTET STRING"
2912 :param value: set the value. Either binary type, or
2913 :py:class:`pyderasn.OctetString` object
2914 :param bounds: set ``(MIN, MAX)`` value size constraint.
2915 (-inf, +inf) by default
2916 :param bytes impl: override default tag with ``IMPLICIT`` one
2917 :param bytes expl: override default tag with ``EXPLICIT`` one
2918 :param default: set default value. Type same as in ``value``
2919 :param bool optional: is object ``OPTIONAL`` in sequence
2921 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2923 self._bound_min, self._bound_max = getattr(
2927 ) if bounds is None else bounds
2928 if value is not None:
2929 self._value = self._value_sanitize(value)
2930 if default is not None:
2931 default = self._value_sanitize(default)
2932 self.default = self.__class__(
2937 if self._value is None:
2938 self._value = default
2940 tag_klass, _, tag_num = tag_decode(self.tag)
2941 self.tag_constructed = tag_encode(
2943 form=TagFormConstructed,
2947 def _value_sanitize(self, value):
2948 if isinstance(value, binary_type):
2950 elif issubclass(value.__class__, OctetString):
2951 value = value._value
2953 raise InvalidValueType((self.__class__, bytes))
2954 if not self._bound_min <= len(value) <= self._bound_max:
2955 raise BoundsError(self._bound_min, len(value), self._bound_max)
2960 return self._value is not None
2962 def __getstate__(self):
2963 return OctetStringState(
2978 self.tag_constructed,
2982 def __setstate__(self, state):
2983 super(OctetString, self).__setstate__(state)
2984 self._value = state.value
2985 self._bound_min = state.bound_min
2986 self._bound_max = state.bound_max
2987 self.tag = state.tag
2988 self._expl = state.expl
2989 self.default = state.default
2990 self.optional = state.optional
2991 self.offset = state.offset
2992 self.llen = state.llen
2993 self.vlen = state.vlen
2994 self.expl_lenindef = state.expl_lenindef
2995 self.lenindef = state.lenindef
2996 self.ber_encoded = state.ber_encoded
2997 self.tag_constructed = state.tag_constructed
2998 self.defined = state.defined
3000 def __bytes__(self):
3001 self._assert_ready()
3004 def __eq__(self, their):
3005 if isinstance(their, binary_type):
3006 return self._value == their
3007 if not issubclass(their.__class__, OctetString):
3010 self._value == their._value and
3011 self.tag == their.tag and
3012 self._expl == their._expl
3015 def __lt__(self, their):
3016 return self._value < their._value
3027 return self.__class__(
3030 (self._bound_min, self._bound_max)
3031 if bounds is None else bounds
3033 impl=self.tag if impl is None else impl,
3034 expl=self._expl if expl is None else expl,
3035 default=self.default if default is None else default,
3036 optional=self.optional if optional is None else optional,
3040 self._assert_ready()
3043 len_encode(len(self._value)),
3047 def _decode_chunk(self, lv, offset, decode_path, ctx):
3049 l, llen, v = len_decode(lv)
3050 except DecodeError as err:
3051 raise err.__class__(
3053 klass=self.__class__,
3054 decode_path=decode_path,
3058 raise NotEnoughData(
3059 "encoded length is longer than data",
3060 klass=self.__class__,
3061 decode_path=decode_path,
3064 v, tail = v[:l], v[l:]
3066 obj = self.__class__(
3068 bounds=(self._bound_min, self._bound_max),
3071 default=self.default,
3072 optional=self.optional,
3073 _decoded=(offset, llen, l),
3076 except DecodeError as err:
3079 klass=self.__class__,
3080 decode_path=decode_path,
3083 except BoundsError as err:
3086 klass=self.__class__,
3087 decode_path=decode_path,
3092 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3094 t, tlen, lv = tag_strip(tlv)
3095 except DecodeError as err:
3096 raise err.__class__(
3098 klass=self.__class__,
3099 decode_path=decode_path,
3105 return self._decode_chunk(lv, offset, decode_path, ctx)
3106 if t == self.tag_constructed:
3107 if not ctx.get("bered", False):
3109 "unallowed BER constructed encoding",
3110 klass=self.__class__,
3111 decode_path=decode_path,
3118 l, llen, v = len_decode(lv)
3119 except LenIndefForm:
3120 llen, l, v = 1, 0, lv[1:]
3122 except DecodeError as err:
3123 raise err.__class__(
3125 klass=self.__class__,
3126 decode_path=decode_path,
3130 raise NotEnoughData(
3131 "encoded length is longer than data",
3132 klass=self.__class__,
3133 decode_path=decode_path,
3137 sub_offset = offset + tlen + llen
3141 if v[:EOC_LEN].tobytes() == EOC:
3148 "chunk out of bounds",
3149 klass=self.__class__,
3150 decode_path=decode_path + (str(len(chunks) - 1),),
3151 offset=chunks[-1].offset,
3153 sub_decode_path = decode_path + (str(len(chunks)),)
3155 chunk, v_tail = OctetString().decode(
3158 decode_path=sub_decode_path,
3161 _ctx_immutable=False,
3165 "expected OctetString encoded chunk",
3166 klass=self.__class__,
3167 decode_path=sub_decode_path,
3170 chunks.append(chunk)
3171 sub_offset += chunk.tlvlen
3172 vlen += chunk.tlvlen
3175 obj = self.__class__(
3176 value=b"".join(bytes(chunk) for chunk in chunks),
3177 bounds=(self._bound_min, self._bound_max),
3180 default=self.default,
3181 optional=self.optional,
3182 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3185 except DecodeError as err:
3188 klass=self.__class__,
3189 decode_path=decode_path,
3192 except BoundsError as err:
3195 klass=self.__class__,
3196 decode_path=decode_path,
3199 obj.lenindef = lenindef
3200 obj.ber_encoded = True
3201 return obj, (v[EOC_LEN:] if lenindef else v)
3203 klass=self.__class__,
3204 decode_path=decode_path,
3209 return pp_console_row(next(self.pps()))
3211 def pps(self, decode_path=()):
3214 asn1_type_name=self.asn1_type_name,
3215 obj_name=self.__class__.__name__,
3216 decode_path=decode_path,
3217 value=("%d bytes" % len(self._value)) if self.ready else None,
3218 blob=self._value if self.ready else None,
3219 optional=self.optional,
3220 default=self == self.default,
3221 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3222 expl=None if self._expl is None else tag_decode(self._expl),
3227 expl_offset=self.expl_offset if self.expled else None,
3228 expl_tlen=self.expl_tlen if self.expled else None,
3229 expl_llen=self.expl_llen if self.expled else None,
3230 expl_vlen=self.expl_vlen if self.expled else None,
3231 expl_lenindef=self.expl_lenindef,
3232 lenindef=self.lenindef,
3233 ber_encoded=self.ber_encoded,
3236 defined_by, defined = self.defined or (None, None)
3237 if defined_by is not None:
3239 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3241 for pp in self.pps_lenindef(decode_path):
3245 NullState = namedtuple("NullState", (
3257 ), **NAMEDTUPLE_KWARGS)
3261 """``NULL`` null object
3269 tag_default = tag_encode(5)
3270 asn1_type_name = "NULL"
3274 value=None, # unused, but Sequence passes it
3281 :param bytes impl: override default tag with ``IMPLICIT`` one
3282 :param bytes expl: override default tag with ``EXPLICIT`` one
3283 :param bool optional: is object ``OPTIONAL`` in sequence
3285 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3292 def __getstate__(self):
3307 def __setstate__(self, state):
3308 super(Null, self).__setstate__(state)
3309 self.tag = state.tag
3310 self._expl = state.expl
3311 self.default = state.default
3312 self.optional = state.optional
3313 self.offset = state.offset
3314 self.llen = state.llen
3315 self.vlen = state.vlen
3316 self.expl_lenindef = state.expl_lenindef
3317 self.lenindef = state.lenindef
3318 self.ber_encoded = state.ber_encoded
3320 def __eq__(self, their):
3321 if not issubclass(their.__class__, Null):
3324 self.tag == their.tag and
3325 self._expl == their._expl
3335 return self.__class__(
3336 impl=self.tag if impl is None else impl,
3337 expl=self._expl if expl is None else expl,
3338 optional=self.optional if optional is None else optional,
3342 return self.tag + len_encode(0)
3344 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3346 t, _, lv = tag_strip(tlv)
3347 except DecodeError as err:
3348 raise err.__class__(
3350 klass=self.__class__,
3351 decode_path=decode_path,
3356 klass=self.__class__,
3357 decode_path=decode_path,
3360 if tag_only: # pragma: no cover
3363 l, _, v = len_decode(lv)
3364 except DecodeError as err:
3365 raise err.__class__(
3367 klass=self.__class__,
3368 decode_path=decode_path,
3372 raise InvalidLength(
3373 "Null must have zero length",
3374 klass=self.__class__,
3375 decode_path=decode_path,
3378 obj = self.__class__(
3381 optional=self.optional,
3382 _decoded=(offset, 1, 0),
3387 return pp_console_row(next(self.pps()))
3389 def pps(self, decode_path=()):
3392 asn1_type_name=self.asn1_type_name,
3393 obj_name=self.__class__.__name__,
3394 decode_path=decode_path,
3395 optional=self.optional,
3396 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3397 expl=None if self._expl is None else tag_decode(self._expl),
3402 expl_offset=self.expl_offset if self.expled else None,
3403 expl_tlen=self.expl_tlen if self.expled else None,
3404 expl_llen=self.expl_llen if self.expled else None,
3405 expl_vlen=self.expl_vlen if self.expled else None,
3406 expl_lenindef=self.expl_lenindef,
3409 for pp in self.pps_lenindef(decode_path):
3413 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3427 ), **NAMEDTUPLE_KWARGS)
3432 if (value[0] in "+- ") or (value[-1] == " "):
3433 raise ValueError("non-pure integer")
3437 class ObjectIdentifier(Obj):
3438 """``OBJECT IDENTIFIER`` OID type
3440 >>> oid = ObjectIdentifier((1, 2, 3))
3441 OBJECT IDENTIFIER 1.2.3
3442 >>> oid == ObjectIdentifier("1.2.3")
3448 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3449 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3451 >>> str(ObjectIdentifier((3, 1)))
3452 Traceback (most recent call last):
3453 pyderasn.InvalidOID: unacceptable first arc value
3455 __slots__ = ("defines",)
3456 tag_default = tag_encode(6)
3457 asn1_type_name = "OBJECT IDENTIFIER"
3470 :param value: set the value. Either tuples of integers,
3471 string of "."-concatenated integers, or
3472 :py:class:`pyderasn.ObjectIdentifier` object
3473 :param defines: sequence of tuples. Each tuple has two elements.
3474 First one is relative to current one decode
3475 path, aiming to the field defined by that OID.
3476 Read about relative path in
3477 :py:func:`pyderasn.abs_decode_path`. Second
3478 tuple element is ``{OID: pyderasn.Obj()}``
3479 dictionary, mapping between current OID value
3480 and structure applied to defined field.
3481 :ref:`Read about DEFINED BY <definedby>`
3482 :param bytes impl: override default tag with ``IMPLICIT`` one
3483 :param bytes expl: override default tag with ``EXPLICIT`` one
3484 :param default: set default value. Type same as in ``value``
3485 :param bool optional: is object ``OPTIONAL`` in sequence
3487 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3489 if value is not None:
3490 self._value = self._value_sanitize(value)
3491 if default is not None:
3492 default = self._value_sanitize(default)
3493 self.default = self.__class__(
3498 if self._value is None:
3499 self._value = default
3500 self.defines = defines
3502 def __add__(self, their):
3503 if isinstance(their, self.__class__):
3504 return self.__class__(self._value + their._value)
3505 if isinstance(their, tuple):
3506 return self.__class__(self._value + their)
3507 raise InvalidValueType((self.__class__, tuple))
3509 def _value_sanitize(self, value):
3510 if issubclass(value.__class__, ObjectIdentifier):
3512 if isinstance(value, string_types):
3514 value = tuple(pureint(arc) for arc in value.split("."))
3516 raise InvalidOID("unacceptable arcs values")
3517 if isinstance(value, tuple):
3519 raise InvalidOID("less than 2 arcs")
3520 first_arc = value[0]
3521 if first_arc in (0, 1):
3522 if not (0 <= value[1] <= 39):
3523 raise InvalidOID("second arc is too wide")
3524 elif first_arc == 2:
3527 raise InvalidOID("unacceptable first arc value")
3528 if not all(arc >= 0 for arc in value):
3529 raise InvalidOID("negative arc value")
3531 raise InvalidValueType((self.__class__, str, tuple))
3535 return self._value is not None
3537 def __getstate__(self):
3538 return ObjectIdentifierState(
3554 def __setstate__(self, state):
3555 super(ObjectIdentifier, self).__setstate__(state)
3556 self._value = state.value
3557 self.tag = state.tag
3558 self._expl = state.expl
3559 self.default = state.default
3560 self.optional = state.optional
3561 self.offset = state.offset
3562 self.llen = state.llen
3563 self.vlen = state.vlen
3564 self.expl_lenindef = state.expl_lenindef
3565 self.lenindef = state.lenindef
3566 self.ber_encoded = state.ber_encoded
3567 self.defines = state.defines
3570 self._assert_ready()
3571 return iter(self._value)
3574 return ".".join(str(arc) for arc in self._value or ())
3577 self._assert_ready()
3580 bytes(self._expl or b"") +
3581 str(self._value).encode("ascii"),
3584 def __eq__(self, their):
3585 if isinstance(their, tuple):
3586 return self._value == their
3587 if not issubclass(their.__class__, ObjectIdentifier):
3590 self.tag == their.tag and
3591 self._expl == their._expl and
3592 self._value == their._value
3595 def __lt__(self, their):
3596 return self._value < their._value
3607 return self.__class__(
3609 defines=self.defines if defines is None else defines,
3610 impl=self.tag if impl is None else impl,
3611 expl=self._expl if expl is None else expl,
3612 default=self.default if default is None else default,
3613 optional=self.optional if optional is None else optional,
3617 self._assert_ready()
3619 first_value = value[1]
3620 first_arc = value[0]
3623 elif first_arc == 1:
3625 elif first_arc == 2:
3627 else: # pragma: no cover
3628 raise RuntimeError("invalid arc is stored")
3629 octets = [zero_ended_encode(first_value)]
3630 for arc in value[2:]:
3631 octets.append(zero_ended_encode(arc))
3632 v = b"".join(octets)
3633 return b"".join((self.tag, len_encode(len(v)), v))
3635 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3637 t, _, lv = tag_strip(tlv)
3638 except DecodeError as err:
3639 raise err.__class__(
3641 klass=self.__class__,
3642 decode_path=decode_path,
3647 klass=self.__class__,
3648 decode_path=decode_path,
3651 if tag_only: # pragma: no cover
3654 l, llen, v = len_decode(lv)
3655 except DecodeError as err:
3656 raise err.__class__(
3658 klass=self.__class__,
3659 decode_path=decode_path,
3663 raise NotEnoughData(
3664 "encoded length is longer than data",
3665 klass=self.__class__,
3666 decode_path=decode_path,
3670 raise NotEnoughData(
3672 klass=self.__class__,
3673 decode_path=decode_path,
3676 v, tail = v[:l], v[l:]
3683 octet = indexbytes(v, i)
3684 if i == 0 and octet == 0x80:
3685 if ctx.get("bered", False):
3688 raise DecodeError("non normalized arc encoding")
3689 arc = (arc << 7) | (octet & 0x7F)
3690 if octet & 0x80 == 0:
3698 klass=self.__class__,
3699 decode_path=decode_path,
3703 second_arc = arcs[0]
3704 if 0 <= second_arc <= 39:
3706 elif 40 <= second_arc <= 79:
3712 obj = self.__class__(
3713 value=tuple([first_arc, second_arc] + arcs[1:]),
3716 default=self.default,
3717 optional=self.optional,
3718 _decoded=(offset, llen, l),
3721 obj.ber_encoded = True
3725 return pp_console_row(next(self.pps()))
3727 def pps(self, decode_path=()):
3730 asn1_type_name=self.asn1_type_name,
3731 obj_name=self.__class__.__name__,
3732 decode_path=decode_path,
3733 value=str(self) if self.ready else None,
3734 optional=self.optional,
3735 default=self == self.default,
3736 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3737 expl=None if self._expl is None else tag_decode(self._expl),
3742 expl_offset=self.expl_offset if self.expled else None,
3743 expl_tlen=self.expl_tlen if self.expled else None,
3744 expl_llen=self.expl_llen if self.expled else None,
3745 expl_vlen=self.expl_vlen if self.expled else None,
3746 expl_lenindef=self.expl_lenindef,
3747 ber_encoded=self.ber_encoded,
3750 for pp in self.pps_lenindef(decode_path):
3754 class Enumerated(Integer):
3755 """``ENUMERATED`` integer type
3757 This type is identical to :py:class:`pyderasn.Integer`, but requires
3758 schema to be specified and does not accept values missing from it.
3761 tag_default = tag_encode(10)
3762 asn1_type_name = "ENUMERATED"
3773 bounds=None, # dummy argument, workability for Integer.decode
3775 super(Enumerated, self).__init__(
3776 value, bounds, impl, expl, default, optional, _specs, _decoded,
3778 if len(self.specs) == 0:
3779 raise ValueError("schema must be specified")
3781 def _value_sanitize(self, value):
3782 if isinstance(value, self.__class__):
3783 value = value._value
3784 elif isinstance(value, integer_types):
3785 for _value in itervalues(self.specs):
3790 "unknown integer value: %s" % value,
3791 klass=self.__class__,
3793 elif isinstance(value, string_types):
3794 value = self.specs.get(value)
3796 raise ObjUnknown("integer value: %s" % value)
3798 raise InvalidValueType((self.__class__, int, str))
3810 return self.__class__(
3812 impl=self.tag if impl is None else impl,
3813 expl=self._expl if expl is None else expl,
3814 default=self.default if default is None else default,
3815 optional=self.optional if optional is None else optional,
3820 def escape_control_unicode(c):
3821 if unicat(c).startswith("C"):
3822 c = repr(c).lstrip("u").strip("'")
3826 class CommonString(OctetString):
3827 """Common class for all strings
3829 Everything resembles :py:class:`pyderasn.OctetString`, except
3830 ability to deal with unicode text strings.
3832 >>> hexenc("привет мир".encode("utf-8"))
3833 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3834 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3836 >>> s = UTF8String("привет мир")
3837 UTF8String UTF8String привет мир
3839 'привет мир'
3840 >>> hexenc(bytes(s))
3841 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3843 >>> PrintableString("привет мир")
3844 Traceback (most recent call last):
3845 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3847 >>> BMPString("ада", bounds=(2, 2))
3848 Traceback (most recent call last):
3849 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3850 >>> s = BMPString("ад", bounds=(2, 2))
3853 >>> hexenc(bytes(s))
3861 * - :py:class:`pyderasn.UTF8String`
3863 * - :py:class:`pyderasn.NumericString`
3865 * - :py:class:`pyderasn.PrintableString`
3867 * - :py:class:`pyderasn.TeletexString`
3869 * - :py:class:`pyderasn.T61String`
3871 * - :py:class:`pyderasn.VideotexString`
3873 * - :py:class:`pyderasn.IA5String`
3875 * - :py:class:`pyderasn.GraphicString`
3877 * - :py:class:`pyderasn.VisibleString`
3879 * - :py:class:`pyderasn.ISO646String`
3881 * - :py:class:`pyderasn.GeneralString`
3883 * - :py:class:`pyderasn.UniversalString`
3885 * - :py:class:`pyderasn.BMPString`
3890 def _value_sanitize(self, value):
3892 value_decoded = None
3893 if isinstance(value, self.__class__):
3894 value_raw = value._value
3895 elif isinstance(value, text_type):
3896 value_decoded = value
3897 elif isinstance(value, binary_type):
3900 raise InvalidValueType((self.__class__, text_type, binary_type))
3903 value_decoded.encode(self.encoding)
3904 if value_raw is None else value_raw
3907 value_raw.decode(self.encoding)
3908 if value_decoded is None else value_decoded
3910 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3911 raise DecodeError(str(err))
3912 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3920 def __eq__(self, their):
3921 if isinstance(their, binary_type):
3922 return self._value == their
3923 if isinstance(their, text_type):
3924 return self._value == their.encode(self.encoding)
3925 if not isinstance(their, self.__class__):
3928 self._value == their._value and
3929 self.tag == their.tag and
3930 self._expl == their._expl
3933 def __unicode__(self):
3935 return self._value.decode(self.encoding)
3936 return text_type(self._value)
3939 return pp_console_row(next(self.pps(no_unicode=PY2)))
3941 def pps(self, decode_path=(), no_unicode=False):
3945 hexenc(bytes(self)) if no_unicode else
3946 "".join(escape_control_unicode(c) for c in self.__unicode__())
3950 asn1_type_name=self.asn1_type_name,
3951 obj_name=self.__class__.__name__,
3952 decode_path=decode_path,
3954 optional=self.optional,
3955 default=self == self.default,
3956 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3957 expl=None if self._expl is None else tag_decode(self._expl),
3962 expl_offset=self.expl_offset if self.expled else None,
3963 expl_tlen=self.expl_tlen if self.expled else None,
3964 expl_llen=self.expl_llen if self.expled else None,
3965 expl_vlen=self.expl_vlen if self.expled else None,
3966 expl_lenindef=self.expl_lenindef,
3967 ber_encoded=self.ber_encoded,
3970 for pp in self.pps_lenindef(decode_path):
3974 class UTF8String(CommonString):
3976 tag_default = tag_encode(12)
3978 asn1_type_name = "UTF8String"
3981 class AllowableCharsMixin(object):
3983 def allowable_chars(self):
3985 return self._allowable_chars
3986 return frozenset(six_unichr(c) for c in self._allowable_chars)
3989 class NumericString(AllowableCharsMixin, CommonString):
3992 Its value is properly sanitized: only ASCII digits with spaces can
3995 >>> NumericString().allowable_chars
3996 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3999 tag_default = tag_encode(18)
4001 asn1_type_name = "NumericString"
4002 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4004 def _value_sanitize(self, value):
4005 value = super(NumericString, self)._value_sanitize(value)
4006 if not frozenset(value) <= self._allowable_chars:
4007 raise DecodeError("non-numeric value")
4011 PrintableStringState = namedtuple(
4012 "PrintableStringState",
4013 OctetStringState._fields + ("allowable_chars",),
4018 class PrintableString(AllowableCharsMixin, CommonString):
4021 Its value is properly sanitized: see X.680 41.4 table 10.
4023 >>> PrintableString().allowable_chars
4024 frozenset([' ', "'", ..., 'z'])
4025 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4026 PrintableString PrintableString foo*bar
4027 >>> obj.allow_asterisk, obj.allow_ampersand
4031 tag_default = tag_encode(19)
4033 asn1_type_name = "PrintableString"
4034 _allowable_chars = frozenset(
4035 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4037 _asterisk = frozenset("*".encode("ascii"))
4038 _ampersand = frozenset("&".encode("ascii"))
4050 allow_asterisk=False,
4051 allow_ampersand=False,
4054 :param allow_asterisk: allow asterisk character
4055 :param allow_ampersand: allow ampersand character
4058 self._allowable_chars |= self._asterisk
4060 self._allowable_chars |= self._ampersand
4061 super(PrintableString, self).__init__(
4062 value, bounds, impl, expl, default, optional, _decoded, ctx,
4066 def allow_asterisk(self):
4067 """Is asterisk character allowed?
4069 return self._asterisk <= self._allowable_chars
4072 def allow_ampersand(self):
4073 """Is ampersand character allowed?
4075 return self._ampersand <= self._allowable_chars
4077 def _value_sanitize(self, value):
4078 value = super(PrintableString, self)._value_sanitize(value)
4079 if not frozenset(value) <= self._allowable_chars:
4080 raise DecodeError("non-printable value")
4083 def __getstate__(self):
4084 return PrintableStringState(
4085 *super(PrintableString, self).__getstate__(),
4086 **{"allowable_chars": self._allowable_chars}
4089 def __setstate__(self, state):
4090 super(PrintableString, self).__setstate__(state)
4091 self._allowable_chars = state.allowable_chars
4102 return self.__class__(
4105 (self._bound_min, self._bound_max)
4106 if bounds is None else bounds
4108 impl=self.tag if impl is None else impl,
4109 expl=self._expl if expl is None else expl,
4110 default=self.default if default is None else default,
4111 optional=self.optional if optional is None else optional,
4112 allow_asterisk=self.allow_asterisk,
4113 allow_ampersand=self.allow_ampersand,
4117 class TeletexString(CommonString):
4119 tag_default = tag_encode(20)
4121 asn1_type_name = "TeletexString"
4124 class T61String(TeletexString):
4126 asn1_type_name = "T61String"
4129 class VideotexString(CommonString):
4131 tag_default = tag_encode(21)
4132 encoding = "iso-8859-1"
4133 asn1_type_name = "VideotexString"
4136 class IA5String(CommonString):
4138 tag_default = tag_encode(22)
4140 asn1_type_name = "IA5"
4143 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4144 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4145 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4148 def fractions2float(fractions_raw):
4149 pureint(fractions_raw)
4150 return float("0." + fractions_raw)
4153 class VisibleString(CommonString):
4155 tag_default = tag_encode(26)
4157 asn1_type_name = "VisibleString"
4160 UTCTimeState = namedtuple(
4162 OctetStringState._fields + ("ber_raw",),
4167 class UTCTime(VisibleString):
4168 """``UTCTime`` datetime type
4170 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4171 UTCTime UTCTime 2017-09-30T22:07:50
4177 datetime.datetime(2017, 9, 30, 22, 7, 50)
4178 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4179 datetime.datetime(1957, 9, 30, 22, 7, 50)
4183 Pay attention that UTCTime can not hold full year, so all years
4184 having < 50 years are treated as 20xx, 19xx otherwise, according
4185 to X.509 recommendation.
4189 No strict validation of UTC offsets are made, but very crude:
4191 * minutes are not exceeding 60
4192 * offset value is not exceeding 14 hours
4194 __slots__ = ("_ber_raw",)
4195 tag_default = tag_encode(23)
4197 asn1_type_name = "UTCTime"
4207 bounds=None, # dummy argument, workability for OctetString.decode
4211 :param value: set the value. Either datetime type, or
4212 :py:class:`pyderasn.UTCTime` object
4213 :param bytes impl: override default tag with ``IMPLICIT`` one
4214 :param bytes expl: override default tag with ``EXPLICIT`` one
4215 :param default: set default value. Type same as in ``value``
4216 :param bool optional: is object ``OPTIONAL`` in sequence
4218 super(UTCTime, self).__init__(
4219 None, None, impl, expl, None, optional, _decoded, ctx,
4222 self._ber_raw = None
4223 if value is not None:
4224 self._value, self._ber_raw = self._value_sanitize(value, ctx)
4225 self.ber_encoded = self._ber_raw is not None
4226 if default is not None:
4227 default, _ = self._value_sanitize(default)
4228 self.default = self.__class__(
4233 if self._value is None:
4234 self._value = default
4236 self.optional = optional
4238 def _strptime_bered(self, value):
4239 year = pureint(value[:2])
4240 year += 2000 if year < 50 else 1900
4243 pureint(value[2:4]), # %m
4244 pureint(value[4:6]), # %d
4245 pureint(value[6:8]), # %H
4246 pureint(value[8:10]), # %M
4250 raise ValueError("no timezone")
4252 if value[-1] == "Z":
4256 raise ValueError("invalid UTC offset")
4257 if value[-5] == "-":
4259 elif value[-5] == "+":
4262 raise ValueError("invalid UTC offset")
4263 offset = 60 * pureint(value[-2:])
4265 raise ValueError("invalid UTC offset minutes")
4266 offset += 3600 * pureint(value[-4:-2])
4267 if offset > 14 * 3600:
4268 raise ValueError("too big UTC offset")
4272 return offset, decoded
4274 raise ValueError("invalid UTC offset seconds")
4275 seconds = pureint(value)
4277 raise ValueError("invalid seconds value")
4278 decoded += timedelta(seconds=seconds)
4279 return offset, decoded
4281 def _strptime(self, value):
4282 # datetime.strptime's format: %y%m%d%H%M%SZ
4283 if len(value) != LEN_YYMMDDHHMMSSZ:
4284 raise ValueError("invalid UTCTime length")
4285 if value[-1] != "Z":
4286 raise ValueError("non UTC timezone")
4287 year = pureint(value[:2])
4288 year += 2000 if year < 50 else 1900
4291 pureint(value[2:4]), # %m
4292 pureint(value[4:6]), # %d
4293 pureint(value[6:8]), # %H
4294 pureint(value[8:10]), # %M
4295 pureint(value[10:12]), # %S
4298 def _dt_sanitize(self, value):
4299 if value.year < 1950 or value.year > 2049:
4300 raise ValueError("UTCTime can hold only 1950-2049 years")
4301 return value.replace(microsecond=0)
4303 def _value_sanitize(self, value, ctx=None):
4304 if isinstance(value, binary_type):
4306 value_decoded = value.decode("ascii")
4307 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4308 raise DecodeError("invalid UTCTime encoding: %r" % err)
4311 return self._strptime(value_decoded), None
4312 except (TypeError, ValueError) as _err:
4314 if (ctx is not None) and ctx.get("bered", False):
4316 offset, _value = self._strptime_bered(value_decoded)
4317 _value = _value - timedelta(seconds=offset)
4318 return self._dt_sanitize(_value), value_decoded
4319 except (TypeError, ValueError, OverflowError) as _err:
4322 "invalid %s format: %r" % (self.asn1_type_name, err),
4323 klass=self.__class__,
4325 if isinstance(value, self.__class__):
4326 return value._value, None
4327 if isinstance(value, datetime):
4328 return self._dt_sanitize(value), None
4329 raise InvalidValueType((self.__class__, datetime))
4331 def _pp_value(self):
4333 value = self._value.isoformat()
4334 if self.ber_encoded:
4335 value += " (%s)" % self._ber_raw
4338 def __unicode__(self):
4340 value = self._value.isoformat()
4341 if self.ber_encoded:
4342 value += " (%s)" % self._ber_raw
4344 return text_type(self._pp_value())
4346 def __getstate__(self):
4347 return UTCTimeState(
4348 *super(UTCTime, self).__getstate__(),
4349 **{"ber_raw": self._ber_raw}
4352 def __setstate__(self, state):
4353 super(UTCTime, self).__setstate__(state)
4354 self._ber_raw = state.ber_raw
4356 def __bytes__(self):
4357 self._assert_ready()
4358 return self._encode_time()
4360 def __eq__(self, their):
4361 if isinstance(their, binary_type):
4362 return self._encode_time() == their
4363 if isinstance(their, datetime):
4364 return self.todatetime() == their
4365 if not isinstance(their, self.__class__):
4368 self._value == their._value and
4369 self.tag == their.tag and
4370 self._expl == their._expl
4373 def _encode_time(self):
4374 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4377 self._assert_ready()
4378 value = self._encode_time()
4379 return b"".join((self.tag, len_encode(len(value)), value))
4381 def todatetime(self):
4385 return pp_console_row(next(self.pps()))
4387 def pps(self, decode_path=()):
4390 asn1_type_name=self.asn1_type_name,
4391 obj_name=self.__class__.__name__,
4392 decode_path=decode_path,
4393 value=self._pp_value(),
4394 optional=self.optional,
4395 default=self == self.default,
4396 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4397 expl=None if self._expl is None else tag_decode(self._expl),
4402 expl_offset=self.expl_offset if self.expled else None,
4403 expl_tlen=self.expl_tlen if self.expled else None,
4404 expl_llen=self.expl_llen if self.expled else None,
4405 expl_vlen=self.expl_vlen if self.expled else None,
4406 expl_lenindef=self.expl_lenindef,
4407 ber_encoded=self.ber_encoded,
4410 for pp in self.pps_lenindef(decode_path):
4414 class GeneralizedTime(UTCTime):
4415 """``GeneralizedTime`` datetime type
4417 This type is similar to :py:class:`pyderasn.UTCTime`.
4419 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4420 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4422 '20170930220750.000123Z'
4423 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4424 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4428 Only microsecond fractions are supported in DER encoding.
4429 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4430 higher precision values.
4434 BER encoded data can loss information (accuracy) during decoding
4435 because of float transformations.
4439 Local times (without explicit timezone specification) are treated
4440 as UTC one, no transformations are made.
4444 Zero year is unsupported.
4447 tag_default = tag_encode(24)
4448 asn1_type_name = "GeneralizedTime"
4450 def _dt_sanitize(self, value):
4453 def _strptime_bered(self, value):
4454 if len(value) < 4 + 3 * 2:
4455 raise ValueError("invalid GeneralizedTime")
4457 pureint(value[:4]), # %Y
4458 pureint(value[4:6]), # %m
4459 pureint(value[6:8]), # %d
4460 pureint(value[8:10]), # %H
4465 return offset, decoded
4466 if value[-1] == "Z":
4469 for char, sign in (("-", -1), ("+", 1)):
4470 idx = value.rfind(char)
4473 offset_raw = value[idx + 1:].replace(":", "")
4474 if len(offset_raw) not in (2, 4):
4475 raise ValueError("invalid UTC offset")
4477 offset = 60 * pureint(offset_raw[2:] or "0")
4479 raise ValueError("invalid UTC offset minutes")
4480 offset += 3600 * pureint(offset_raw[:2])
4481 if offset > 14 * 3600:
4482 raise ValueError("too big UTC offset")
4486 return offset, decoded
4487 decimal_signs = ".,"
4488 if value[0] in decimal_signs:
4490 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4493 raise ValueError("stripped minutes")
4494 decoded += timedelta(seconds=60 * pureint(value[:2]))
4497 return offset, decoded
4498 if value[0] in decimal_signs:
4500 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4503 raise ValueError("stripped seconds")
4504 decoded += timedelta(seconds=pureint(value[:2]))
4507 return offset, decoded
4508 if value[0] not in decimal_signs:
4509 raise ValueError("invalid format after seconds")
4511 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4514 def _strptime(self, value):
4516 if l == LEN_YYYYMMDDHHMMSSZ:
4517 # datetime.strptime's format: %Y%m%d%H%M%SZ
4518 if value[-1] != "Z":
4519 raise ValueError("non UTC timezone")
4521 pureint(value[:4]), # %Y
4522 pureint(value[4:6]), # %m
4523 pureint(value[6:8]), # %d
4524 pureint(value[8:10]), # %H
4525 pureint(value[10:12]), # %M
4526 pureint(value[12:14]), # %S
4528 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4529 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4530 if value[-1] != "Z":
4531 raise ValueError("non UTC timezone")
4532 if value[14] != ".":
4533 raise ValueError("no fractions separator")
4536 raise ValueError("trailing zero")
4539 raise ValueError("only microsecond fractions are supported")
4540 us = pureint(us + ("0" * (6 - us_len)))
4542 pureint(value[:4]), # %Y
4543 pureint(value[4:6]), # %m
4544 pureint(value[6:8]), # %d
4545 pureint(value[8:10]), # %H
4546 pureint(value[10:12]), # %M
4547 pureint(value[12:14]), # %S
4551 raise ValueError("invalid GeneralizedTime length")
4553 def _encode_time(self):
4555 encoded = value.strftime("%Y%m%d%H%M%S")
4556 if value.microsecond > 0:
4557 encoded += (".%06d" % value.microsecond).rstrip("0")
4558 return (encoded + "Z").encode("ascii")
4561 class GraphicString(CommonString):
4563 tag_default = tag_encode(25)
4564 encoding = "iso-8859-1"
4565 asn1_type_name = "GraphicString"
4568 class ISO646String(VisibleString):
4570 asn1_type_name = "ISO646String"
4573 class GeneralString(CommonString):
4575 tag_default = tag_encode(27)
4576 encoding = "iso-8859-1"
4577 asn1_type_name = "GeneralString"
4580 class UniversalString(CommonString):
4582 tag_default = tag_encode(28)
4583 encoding = "utf-32-be"
4584 asn1_type_name = "UniversalString"
4587 class BMPString(CommonString):
4589 tag_default = tag_encode(30)
4590 encoding = "utf-16-be"
4591 asn1_type_name = "BMPString"
4594 ChoiceState = namedtuple("ChoiceState", (
4608 ), **NAMEDTUPLE_KWARGS)
4612 """``CHOICE`` special type
4616 class GeneralName(Choice):
4618 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4619 ("dNSName", IA5String(impl=tag_ctxp(2))),
4622 >>> gn = GeneralName()
4624 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4625 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4626 >>> gn["dNSName"] = IA5String("bar.baz")
4627 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4628 >>> gn["rfc822Name"]
4631 [2] IA5String IA5 bar.baz
4634 >>> gn.value == gn["dNSName"]
4637 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4639 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4640 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4642 __slots__ = ("specs",)
4644 asn1_type_name = "CHOICE"
4657 :param value: set the value. Either ``(choice, value)`` tuple, or
4658 :py:class:`pyderasn.Choice` object
4659 :param bytes impl: can not be set, do **not** use it
4660 :param bytes expl: override default tag with ``EXPLICIT`` one
4661 :param default: set default value. Type same as in ``value``
4662 :param bool optional: is object ``OPTIONAL`` in sequence
4664 if impl is not None:
4665 raise ValueError("no implicit tag allowed for CHOICE")
4666 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4668 schema = getattr(self, "schema", ())
4669 if len(schema) == 0:
4670 raise ValueError("schema must be specified")
4672 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4675 if value is not None:
4676 self._value = self._value_sanitize(value)
4677 if default is not None:
4678 default_value = self._value_sanitize(default)
4679 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4680 default_obj.specs = self.specs
4681 default_obj._value = default_value
4682 self.default = default_obj
4684 self._value = copy(default_obj._value)
4686 def _value_sanitize(self, value):
4687 if isinstance(value, tuple) and len(value) == 2:
4689 spec = self.specs.get(choice)
4691 raise ObjUnknown(choice)
4692 if not isinstance(obj, spec.__class__):
4693 raise InvalidValueType((spec,))
4694 return (choice, spec(obj))
4695 if isinstance(value, self.__class__):
4697 raise InvalidValueType((self.__class__, tuple))
4701 return self._value is not None and self._value[1].ready
4705 return self.expl_lenindef or (
4706 (self._value is not None) and
4707 self._value[1].bered
4710 def __getstate__(self):
4727 def __setstate__(self, state):
4728 super(Choice, self).__setstate__(state)
4729 self.specs = state.specs
4730 self._value = state.value
4731 self._expl = state.expl
4732 self.default = state.default
4733 self.optional = state.optional
4734 self.offset = state.offset
4735 self.llen = state.llen
4736 self.vlen = state.vlen
4737 self.expl_lenindef = state.expl_lenindef
4738 self.lenindef = state.lenindef
4739 self.ber_encoded = state.ber_encoded
4741 def __eq__(self, their):
4742 if isinstance(their, tuple) and len(their) == 2:
4743 return self._value == their
4744 if not isinstance(their, self.__class__):
4747 self.specs == their.specs and
4748 self._value == their._value
4758 return self.__class__(
4761 expl=self._expl if expl is None else expl,
4762 default=self.default if default is None else default,
4763 optional=self.optional if optional is None else optional,
4768 self._assert_ready()
4769 return self._value[0]
4773 self._assert_ready()
4774 return self._value[1]
4776 def __getitem__(self, key):
4777 if key not in self.specs:
4778 raise ObjUnknown(key)
4779 if self._value is None:
4781 choice, value = self._value
4786 def __setitem__(self, key, value):
4787 spec = self.specs.get(key)
4789 raise ObjUnknown(key)
4790 if not isinstance(value, spec.__class__):
4791 raise InvalidValueType((spec.__class__,))
4792 self._value = (key, spec(value))
4800 return self._value[1].decoded if self.ready else False
4803 self._assert_ready()
4804 return self._value[1].encode()
4806 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4807 for choice, spec in iteritems(self.specs):
4808 sub_decode_path = decode_path + (choice,)
4814 decode_path=sub_decode_path,
4817 _ctx_immutable=False,
4824 klass=self.__class__,
4825 decode_path=decode_path,
4828 if tag_only: # pragma: no cover
4830 value, tail = spec.decode(
4834 decode_path=sub_decode_path,
4836 _ctx_immutable=False,
4838 obj = self.__class__(
4841 default=self.default,
4842 optional=self.optional,
4843 _decoded=(offset, 0, value.fulllen),
4845 obj._value = (choice, value)
4849 value = pp_console_row(next(self.pps()))
4851 value = "%s[%r]" % (value, self.value)
4854 def pps(self, decode_path=()):
4857 asn1_type_name=self.asn1_type_name,
4858 obj_name=self.__class__.__name__,
4859 decode_path=decode_path,
4860 value=self.choice if self.ready else None,
4861 optional=self.optional,
4862 default=self == self.default,
4863 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4864 expl=None if self._expl is None else tag_decode(self._expl),
4869 expl_lenindef=self.expl_lenindef,
4873 yield self.value.pps(decode_path=decode_path + (self.choice,))
4874 for pp in self.pps_lenindef(decode_path):
4878 class PrimitiveTypes(Choice):
4879 """Predefined ``CHOICE`` for all generic primitive types
4881 It could be useful for general decoding of some unspecified values:
4883 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4884 OCTET STRING 3 bytes 666f6f
4885 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4889 schema = tuple((klass.__name__, klass()) for klass in (
4913 AnyState = namedtuple("AnyState", (
4926 ), **NAMEDTUPLE_KWARGS)
4930 """``ANY`` special type
4932 >>> Any(Integer(-123))
4934 >>> a = Any(OctetString(b"hello world").encode())
4935 ANY 040b68656c6c6f20776f726c64
4936 >>> hexenc(bytes(a))
4937 b'0x040x0bhello world'
4939 __slots__ = ("defined",)
4940 tag_default = tag_encode(0)
4941 asn1_type_name = "ANY"
4951 :param value: set the value. Either any kind of pyderasn's
4952 **ready** object, or bytes. Pay attention that
4953 **no** validation is performed is raw binary value
4955 :param bytes expl: override default tag with ``EXPLICIT`` one
4956 :param bool optional: is object ``OPTIONAL`` in sequence
4958 super(Any, self).__init__(None, expl, None, optional, _decoded)
4959 self._value = None if value is None else self._value_sanitize(value)
4962 def _value_sanitize(self, value):
4963 if isinstance(value, binary_type):
4965 if isinstance(value, self.__class__):
4967 if isinstance(value, Obj):
4968 return value.encode()
4969 raise InvalidValueType((self.__class__, Obj, binary_type))
4973 return self._value is not None
4977 if self.expl_lenindef or self.lenindef:
4979 if self.defined is None:
4981 return self.defined[1].bered
4983 def __getstate__(self):
4999 def __setstate__(self, state):
5000 super(Any, self).__setstate__(state)
5001 self._value = state.value
5002 self.tag = state.tag
5003 self._expl = state.expl
5004 self.optional = state.optional
5005 self.offset = state.offset
5006 self.llen = state.llen
5007 self.vlen = state.vlen
5008 self.expl_lenindef = state.expl_lenindef
5009 self.lenindef = state.lenindef
5010 self.ber_encoded = state.ber_encoded
5011 self.defined = state.defined
5013 def __eq__(self, their):
5014 if isinstance(their, binary_type):
5015 return self._value == their
5016 if issubclass(their.__class__, Any):
5017 return self._value == their._value
5026 return self.__class__(
5028 expl=self._expl if expl is None else expl,
5029 optional=self.optional if optional is None else optional,
5032 def __bytes__(self):
5033 self._assert_ready()
5041 self._assert_ready()
5044 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5046 t, tlen, lv = tag_strip(tlv)
5047 except DecodeError as err:
5048 raise err.__class__(
5050 klass=self.__class__,
5051 decode_path=decode_path,
5055 l, llen, v = len_decode(lv)
5056 except LenIndefForm as err:
5057 if not ctx.get("bered", False):
5058 raise err.__class__(
5060 klass=self.__class__,
5061 decode_path=decode_path,
5064 llen, vlen, v = 1, 0, lv[1:]
5065 sub_offset = offset + tlen + llen
5067 while v[:EOC_LEN].tobytes() != EOC:
5068 chunk, v = Any().decode(
5071 decode_path=decode_path + (str(chunk_i),),
5074 _ctx_immutable=False,
5076 vlen += chunk.tlvlen
5077 sub_offset += chunk.tlvlen
5079 tlvlen = tlen + llen + vlen + EOC_LEN
5080 obj = self.__class__(
5081 value=tlv[:tlvlen].tobytes(),
5083 optional=self.optional,
5084 _decoded=(offset, 0, tlvlen),
5087 obj.tag = t.tobytes()
5088 return obj, v[EOC_LEN:]
5089 except DecodeError as err:
5090 raise err.__class__(
5092 klass=self.__class__,
5093 decode_path=decode_path,
5097 raise NotEnoughData(
5098 "encoded length is longer than data",
5099 klass=self.__class__,
5100 decode_path=decode_path,
5103 tlvlen = tlen + llen + l
5104 v, tail = tlv[:tlvlen], v[l:]
5105 obj = self.__class__(
5108 optional=self.optional,
5109 _decoded=(offset, 0, tlvlen),
5111 obj.tag = t.tobytes()
5115 return pp_console_row(next(self.pps()))
5117 def pps(self, decode_path=()):
5120 asn1_type_name=self.asn1_type_name,
5121 obj_name=self.__class__.__name__,
5122 decode_path=decode_path,
5123 blob=self._value if self.ready else None,
5124 optional=self.optional,
5125 default=self == self.default,
5126 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5127 expl=None if self._expl is None else tag_decode(self._expl),
5132 expl_offset=self.expl_offset if self.expled else None,
5133 expl_tlen=self.expl_tlen if self.expled else None,
5134 expl_llen=self.expl_llen if self.expled else None,
5135 expl_vlen=self.expl_vlen if self.expled else None,
5136 expl_lenindef=self.expl_lenindef,
5137 lenindef=self.lenindef,
5140 defined_by, defined = self.defined or (None, None)
5141 if defined_by is not None:
5143 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5145 for pp in self.pps_lenindef(decode_path):
5149 ########################################################################
5150 # ASN.1 constructed types
5151 ########################################################################
5153 def get_def_by_path(defines_by_path, sub_decode_path):
5154 """Get define by decode path
5156 for path, define in defines_by_path:
5157 if len(path) != len(sub_decode_path):
5159 for p1, p2 in zip(path, sub_decode_path):
5160 if (p1 != any) and (p1 != p2):
5166 def abs_decode_path(decode_path, rel_path):
5167 """Create an absolute decode path from current and relative ones
5169 :param decode_path: current decode path, starting point. Tuple of strings
5170 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5171 If first tuple's element is "/", then treat it as
5172 an absolute path, ignoring ``decode_path`` as
5173 starting point. Also this tuple can contain ".."
5174 elements, stripping the leading element from
5177 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5178 ("foo", "bar", "baz", "whatever")
5179 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5181 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5184 if rel_path[0] == "/":
5186 if rel_path[0] == "..":
5187 return abs_decode_path(decode_path[:-1], rel_path[1:])
5188 return decode_path + rel_path
5191 SequenceState = namedtuple("SequenceState", (
5205 ), **NAMEDTUPLE_KWARGS)
5208 class Sequence(Obj):
5209 """``SEQUENCE`` structure type
5211 You have to make specification of sequence::
5213 class Extension(Sequence):
5215 ("extnID", ObjectIdentifier()),
5216 ("critical", Boolean(default=False)),
5217 ("extnValue", OctetString()),
5220 Then, you can work with it as with dictionary.
5222 >>> ext = Extension()
5223 >>> Extension().specs
5225 ('extnID', OBJECT IDENTIFIER),
5226 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5227 ('extnValue', OCTET STRING),
5229 >>> ext["extnID"] = "1.2.3"
5230 Traceback (most recent call last):
5231 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5232 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5234 You can determine if sequence is ready to be encoded:
5239 Traceback (most recent call last):
5240 pyderasn.ObjNotReady: object is not ready: extnValue
5241 >>> ext["extnValue"] = OctetString(b"foobar")
5245 Value you want to assign, must have the same **type** as in
5246 corresponding specification, but it can have different tags,
5247 optional/default attributes -- they will be taken from specification
5250 class TBSCertificate(Sequence):
5252 ("version", Version(expl=tag_ctxc(0), default="v1")),
5255 >>> tbs = TBSCertificate()
5256 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5258 Assign ``None`` to remove value from sequence.
5260 You can set values in Sequence during its initialization:
5262 >>> AlgorithmIdentifier((
5263 ("algorithm", ObjectIdentifier("1.2.3")),
5264 ("parameters", Any(Null()))
5266 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5268 You can determine if value exists/set in the sequence and take its value:
5270 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5273 OBJECT IDENTIFIER 1.2.3
5275 But pay attention that if value has default, then it won't be (not
5276 in) in the sequence (because ``DEFAULT`` must not be encoded in
5277 DER), but you can read its value:
5279 >>> "critical" in ext, ext["critical"]
5280 (False, BOOLEAN False)
5281 >>> ext["critical"] = Boolean(True)
5282 >>> "critical" in ext, ext["critical"]
5283 (True, BOOLEAN True)
5285 All defaulted values are always optional.
5287 .. _allow_default_values_ctx:
5289 DER prohibits default value encoding and will raise an error if
5290 default value is unexpectedly met during decode.
5291 If :ref:`bered <bered_ctx>` context option is set, then no error
5292 will be raised, but ``bered`` attribute set. You can disable strict
5293 defaulted values existence validation by setting
5294 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5296 Two sequences are equal if they have equal specification (schema),
5297 implicit/explicit tagging and the same values.
5299 __slots__ = ("specs",)
5300 tag_default = tag_encode(form=TagFormConstructed, num=16)
5301 asn1_type_name = "SEQUENCE"
5313 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5315 schema = getattr(self, "schema", ())
5317 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5320 if value is not None:
5321 if issubclass(value.__class__, Sequence):
5322 self._value = value._value
5323 elif hasattr(value, "__iter__"):
5324 for seq_key, seq_value in value:
5325 self[seq_key] = seq_value
5327 raise InvalidValueType((Sequence,))
5328 if default is not None:
5329 if not issubclass(default.__class__, Sequence):
5330 raise InvalidValueType((Sequence,))
5331 default_value = default._value
5332 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5333 default_obj.specs = self.specs
5334 default_obj._value = default_value
5335 self.default = default_obj
5337 self._value = copy(default_obj._value)
5341 for name, spec in iteritems(self.specs):
5342 value = self._value.get(name)
5353 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5355 return any(value.bered for value in itervalues(self._value))
5357 def __getstate__(self):
5358 return SequenceState(
5361 {k: copy(v) for k, v in iteritems(self._value)},
5374 def __setstate__(self, state):
5375 super(Sequence, self).__setstate__(state)
5376 self.specs = state.specs
5377 self._value = state.value
5378 self.tag = state.tag
5379 self._expl = state.expl
5380 self.default = state.default
5381 self.optional = state.optional
5382 self.offset = state.offset
5383 self.llen = state.llen
5384 self.vlen = state.vlen
5385 self.expl_lenindef = state.expl_lenindef
5386 self.lenindef = state.lenindef
5387 self.ber_encoded = state.ber_encoded
5389 def __eq__(self, their):
5390 if not isinstance(their, self.__class__):
5393 self.specs == their.specs and
5394 self.tag == their.tag and
5395 self._expl == their._expl and
5396 self._value == their._value
5407 return self.__class__(
5410 impl=self.tag if impl is None else impl,
5411 expl=self._expl if expl is None else expl,
5412 default=self.default if default is None else default,
5413 optional=self.optional if optional is None else optional,
5416 def __contains__(self, key):
5417 return key in self._value
5419 def __setitem__(self, key, value):
5420 spec = self.specs.get(key)
5422 raise ObjUnknown(key)
5424 self._value.pop(key, None)
5426 if not isinstance(value, spec.__class__):
5427 raise InvalidValueType((spec.__class__,))
5428 value = spec(value=value)
5429 if spec.default is not None and value == spec.default:
5430 self._value.pop(key, None)
5432 self._value[key] = value
5434 def __getitem__(self, key):
5435 value = self._value.get(key)
5436 if value is not None:
5438 spec = self.specs.get(key)
5440 raise ObjUnknown(key)
5441 if spec.default is not None:
5445 def _encoded_values(self):
5447 for name, spec in iteritems(self.specs):
5448 value = self._value.get(name)
5452 raise ObjNotReady(name)
5453 raws.append(value.encode())
5457 v = b"".join(self._encoded_values())
5458 return b"".join((self.tag, len_encode(len(v)), v))
5460 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5462 t, tlen, lv = tag_strip(tlv)
5463 except DecodeError as err:
5464 raise err.__class__(
5466 klass=self.__class__,
5467 decode_path=decode_path,
5472 klass=self.__class__,
5473 decode_path=decode_path,
5476 if tag_only: # pragma: no cover
5479 ctx_bered = ctx.get("bered", False)
5481 l, llen, v = len_decode(lv)
5482 except LenIndefForm as err:
5484 raise err.__class__(
5486 klass=self.__class__,
5487 decode_path=decode_path,
5490 l, llen, v = 0, 1, lv[1:]
5492 except DecodeError as err:
5493 raise err.__class__(
5495 klass=self.__class__,
5496 decode_path=decode_path,
5500 raise NotEnoughData(
5501 "encoded length is longer than data",
5502 klass=self.__class__,
5503 decode_path=decode_path,
5507 v, tail = v[:l], v[l:]
5509 sub_offset = offset + tlen + llen
5512 ctx_allow_default_values = ctx.get("allow_default_values", False)
5513 for name, spec in iteritems(self.specs):
5514 if spec.optional and (
5515 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5519 sub_decode_path = decode_path + (name,)
5521 value, v_tail = spec.decode(
5525 decode_path=sub_decode_path,
5527 _ctx_immutable=False,
5529 except TagMismatch as err:
5530 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5534 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5535 if defined is not None:
5536 defined_by, defined_spec = defined
5537 if issubclass(value.__class__, SequenceOf):
5538 for i, _value in enumerate(value):
5539 sub_sub_decode_path = sub_decode_path + (
5541 DecodePathDefBy(defined_by),
5543 defined_value, defined_tail = defined_spec.decode(
5544 memoryview(bytes(_value)),
5546 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5547 if value.expled else (value.tlen + value.llen)
5550 decode_path=sub_sub_decode_path,
5552 _ctx_immutable=False,
5554 if len(defined_tail) > 0:
5557 klass=self.__class__,
5558 decode_path=sub_sub_decode_path,
5561 _value.defined = (defined_by, defined_value)
5563 defined_value, defined_tail = defined_spec.decode(
5564 memoryview(bytes(value)),
5566 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5567 if value.expled else (value.tlen + value.llen)
5570 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5572 _ctx_immutable=False,
5574 if len(defined_tail) > 0:
5577 klass=self.__class__,
5578 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5581 value.defined = (defined_by, defined_value)
5583 value_len = value.fulllen
5585 sub_offset += value_len
5587 if spec.default is not None and value == spec.default:
5588 if ctx_bered or ctx_allow_default_values:
5592 "DEFAULT value met",
5593 klass=self.__class__,
5594 decode_path=sub_decode_path,
5597 values[name] = value
5599 spec_defines = getattr(spec, "defines", ())
5600 if len(spec_defines) == 0:
5601 defines_by_path = ctx.get("defines_by_path", ())
5602 if len(defines_by_path) > 0:
5603 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5604 if spec_defines is not None and len(spec_defines) > 0:
5605 for rel_path, schema in spec_defines:
5606 defined = schema.get(value, None)
5607 if defined is not None:
5608 ctx.setdefault("_defines", []).append((
5609 abs_decode_path(sub_decode_path[:-1], rel_path),
5613 if v[:EOC_LEN].tobytes() != EOC:
5616 klass=self.__class__,
5617 decode_path=decode_path,
5625 klass=self.__class__,
5626 decode_path=decode_path,
5629 obj = self.__class__(
5633 default=self.default,
5634 optional=self.optional,
5635 _decoded=(offset, llen, vlen),
5638 obj.lenindef = lenindef
5639 obj.ber_encoded = ber_encoded
5643 value = pp_console_row(next(self.pps()))
5645 for name in self.specs:
5646 _value = self._value.get(name)
5649 cols.append("%s: %s" % (name, repr(_value)))
5650 return "%s[%s]" % (value, "; ".join(cols))
5652 def pps(self, decode_path=()):
5655 asn1_type_name=self.asn1_type_name,
5656 obj_name=self.__class__.__name__,
5657 decode_path=decode_path,
5658 optional=self.optional,
5659 default=self == self.default,
5660 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5661 expl=None if self._expl is None else tag_decode(self._expl),
5666 expl_offset=self.expl_offset if self.expled else None,
5667 expl_tlen=self.expl_tlen if self.expled else None,
5668 expl_llen=self.expl_llen if self.expled else None,
5669 expl_vlen=self.expl_vlen if self.expled else None,
5670 expl_lenindef=self.expl_lenindef,
5671 lenindef=self.lenindef,
5672 ber_encoded=self.ber_encoded,
5675 for name in self.specs:
5676 value = self._value.get(name)
5679 yield value.pps(decode_path=decode_path + (name,))
5680 for pp in self.pps_lenindef(decode_path):
5684 class Set(Sequence):
5685 """``SET`` structure type
5687 Its usage is identical to :py:class:`pyderasn.Sequence`.
5689 .. _allow_unordered_set_ctx:
5691 DER prohibits unordered values encoding and will raise an error
5692 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5693 then no error will occure. Also you can disable strict values
5694 ordering check by setting ``"allow_unordered_set": True``
5695 :ref:`context <ctx>` option.
5698 tag_default = tag_encode(form=TagFormConstructed, num=17)
5699 asn1_type_name = "SET"
5702 raws = self._encoded_values()
5705 return b"".join((self.tag, len_encode(len(v)), v))
5707 def _specs_items(self):
5708 return iteritems(self.specs)
5710 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5712 t, tlen, lv = tag_strip(tlv)
5713 except DecodeError as err:
5714 raise err.__class__(
5716 klass=self.__class__,
5717 decode_path=decode_path,
5722 klass=self.__class__,
5723 decode_path=decode_path,
5729 ctx_bered = ctx.get("bered", False)
5731 l, llen, v = len_decode(lv)
5732 except LenIndefForm as err:
5734 raise err.__class__(
5736 klass=self.__class__,
5737 decode_path=decode_path,
5740 l, llen, v = 0, 1, lv[1:]
5742 except DecodeError as err:
5743 raise err.__class__(
5745 klass=self.__class__,
5746 decode_path=decode_path,
5750 raise NotEnoughData(
5751 "encoded length is longer than data",
5752 klass=self.__class__,
5756 v, tail = v[:l], v[l:]
5758 sub_offset = offset + tlen + llen
5761 ctx_allow_default_values = ctx.get("allow_default_values", False)
5762 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5763 value_prev = memoryview(v[:0])
5766 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5768 for name, spec in self._specs_items():
5769 sub_decode_path = decode_path + (name,)
5775 decode_path=sub_decode_path,
5778 _ctx_immutable=False,
5785 klass=self.__class__,
5786 decode_path=decode_path,
5789 value, v_tail = spec.decode(
5793 decode_path=sub_decode_path,
5795 _ctx_immutable=False,
5797 value_len = value.fulllen
5798 if value_prev.tobytes() > v[:value_len].tobytes():
5799 if ctx_bered or ctx_allow_unordered_set:
5803 "unordered " + self.asn1_type_name,
5804 klass=self.__class__,
5805 decode_path=sub_decode_path,
5808 if spec.default is None or value != spec.default:
5810 elif ctx_bered or ctx_allow_default_values:
5814 "DEFAULT value met",
5815 klass=self.__class__,
5816 decode_path=sub_decode_path,
5819 values[name] = value
5820 value_prev = v[:value_len]
5821 sub_offset += value_len
5824 obj = self.__class__(
5828 default=self.default,
5829 optional=self.optional,
5830 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5833 if v[:EOC_LEN].tobytes() != EOC:
5836 klass=self.__class__,
5837 decode_path=decode_path,
5845 "not all values are ready",
5846 klass=self.__class__,
5847 decode_path=decode_path,
5850 obj.ber_encoded = ber_encoded
5854 SequenceOfState = namedtuple("SequenceOfState", (
5870 ), **NAMEDTUPLE_KWARGS)
5873 class SequenceOf(Obj):
5874 """``SEQUENCE OF`` sequence type
5876 For that kind of type you must specify the object it will carry on
5877 (bounds are for example here, not required)::
5879 class Ints(SequenceOf):
5884 >>> ints.append(Integer(123))
5885 >>> ints.append(Integer(234))
5887 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5888 >>> [int(i) for i in ints]
5890 >>> ints.append(Integer(345))
5891 Traceback (most recent call last):
5892 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5895 >>> ints[1] = Integer(345)
5897 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5899 Also you can initialize sequence with preinitialized values:
5901 >>> ints = Ints([Integer(123), Integer(234)])
5903 __slots__ = ("spec", "_bound_min", "_bound_max")
5904 tag_default = tag_encode(form=TagFormConstructed, num=16)
5905 asn1_type_name = "SEQUENCE OF"
5918 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5920 schema = getattr(self, "schema", None)
5922 raise ValueError("schema must be specified")
5924 self._bound_min, self._bound_max = getattr(
5928 ) if bounds is None else bounds
5930 if value is not None:
5931 self._value = self._value_sanitize(value)
5932 if default is not None:
5933 default_value = self._value_sanitize(default)
5934 default_obj = self.__class__(
5939 default_obj._value = default_value
5940 self.default = default_obj
5942 self._value = copy(default_obj._value)
5944 def _value_sanitize(self, value):
5945 if issubclass(value.__class__, SequenceOf):
5946 value = value._value
5947 elif hasattr(value, "__iter__"):
5950 raise InvalidValueType((self.__class__, iter))
5951 if not self._bound_min <= len(value) <= self._bound_max:
5952 raise BoundsError(self._bound_min, len(value), self._bound_max)
5954 if not isinstance(v, self.spec.__class__):
5955 raise InvalidValueType((self.spec.__class__,))
5960 return all(v.ready for v in self._value)
5964 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5966 return any(v.bered for v in self._value)
5968 def __getstate__(self):
5969 return SequenceOfState(
5972 [copy(v) for v in self._value],
5987 def __setstate__(self, state):
5988 super(SequenceOf, self).__setstate__(state)
5989 self.spec = state.spec
5990 self._value = state.value
5991 self._bound_min = state.bound_min
5992 self._bound_max = state.bound_max
5993 self.tag = state.tag
5994 self._expl = state.expl
5995 self.default = state.default
5996 self.optional = state.optional
5997 self.offset = state.offset
5998 self.llen = state.llen
5999 self.vlen = state.vlen
6000 self.expl_lenindef = state.expl_lenindef
6001 self.lenindef = state.lenindef
6002 self.ber_encoded = state.ber_encoded
6004 def __eq__(self, their):
6005 if isinstance(their, self.__class__):
6007 self.spec == their.spec and
6008 self.tag == their.tag and
6009 self._expl == their._expl and
6010 self._value == their._value
6012 if hasattr(their, "__iter__"):
6013 return self._value == list(their)
6025 return self.__class__(
6029 (self._bound_min, self._bound_max)
6030 if bounds is None else bounds
6032 impl=self.tag if impl is None else impl,
6033 expl=self._expl if expl is None else expl,
6034 default=self.default if default is None else default,
6035 optional=self.optional if optional is None else optional,
6038 def __contains__(self, key):
6039 return key in self._value
6041 def append(self, value):
6042 if not isinstance(value, self.spec.__class__):
6043 raise InvalidValueType((self.spec.__class__,))
6044 if len(self._value) + 1 > self._bound_max:
6047 len(self._value) + 1,
6050 self._value.append(value)
6053 self._assert_ready()
6054 return iter(self._value)
6057 self._assert_ready()
6058 return len(self._value)
6060 def __setitem__(self, key, value):
6061 if not isinstance(value, self.spec.__class__):
6062 raise InvalidValueType((self.spec.__class__,))
6063 self._value[key] = self.spec(value=value)
6065 def __getitem__(self, key):
6066 return self._value[key]
6068 def _encoded_values(self):
6069 return [v.encode() for v in self._value]
6072 v = b"".join(self._encoded_values())
6073 return b"".join((self.tag, len_encode(len(v)), v))
6075 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6077 t, tlen, lv = tag_strip(tlv)
6078 except DecodeError as err:
6079 raise err.__class__(
6081 klass=self.__class__,
6082 decode_path=decode_path,
6087 klass=self.__class__,
6088 decode_path=decode_path,
6094 ctx_bered = ctx.get("bered", False)
6096 l, llen, v = len_decode(lv)
6097 except LenIndefForm as err:
6099 raise err.__class__(
6101 klass=self.__class__,
6102 decode_path=decode_path,
6105 l, llen, v = 0, 1, lv[1:]
6107 except DecodeError as err:
6108 raise err.__class__(
6110 klass=self.__class__,
6111 decode_path=decode_path,
6115 raise NotEnoughData(
6116 "encoded length is longer than data",
6117 klass=self.__class__,
6118 decode_path=decode_path,
6122 v, tail = v[:l], v[l:]
6124 sub_offset = offset + tlen + llen
6126 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6127 value_prev = memoryview(v[:0])
6131 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6133 sub_decode_path = decode_path + (str(len(_value)),)
6134 value, v_tail = spec.decode(
6138 decode_path=sub_decode_path,
6140 _ctx_immutable=False,
6142 value_len = value.fulllen
6144 if value_prev.tobytes() > v[:value_len].tobytes():
6145 if ctx_bered or ctx_allow_unordered_set:
6149 "unordered " + self.asn1_type_name,
6150 klass=self.__class__,
6151 decode_path=sub_decode_path,
6154 value_prev = v[:value_len]
6155 _value.append(value)
6156 sub_offset += value_len
6160 obj = self.__class__(
6163 bounds=(self._bound_min, self._bound_max),
6166 default=self.default,
6167 optional=self.optional,
6168 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6170 except BoundsError as err:
6173 klass=self.__class__,
6174 decode_path=decode_path,
6178 if v[:EOC_LEN].tobytes() != EOC:
6181 klass=self.__class__,
6182 decode_path=decode_path,
6187 obj.ber_encoded = ber_encoded
6192 pp_console_row(next(self.pps())),
6193 ", ".join(repr(v) for v in self._value),
6196 def pps(self, decode_path=()):
6199 asn1_type_name=self.asn1_type_name,
6200 obj_name=self.__class__.__name__,
6201 decode_path=decode_path,
6202 optional=self.optional,
6203 default=self == self.default,
6204 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6205 expl=None if self._expl is None else tag_decode(self._expl),
6210 expl_offset=self.expl_offset if self.expled else None,
6211 expl_tlen=self.expl_tlen if self.expled else None,
6212 expl_llen=self.expl_llen if self.expled else None,
6213 expl_vlen=self.expl_vlen if self.expled else None,
6214 expl_lenindef=self.expl_lenindef,
6215 lenindef=self.lenindef,
6216 ber_encoded=self.ber_encoded,
6219 for i, value in enumerate(self._value):
6220 yield value.pps(decode_path=decode_path + (str(i),))
6221 for pp in self.pps_lenindef(decode_path):
6225 class SetOf(SequenceOf):
6226 """``SET OF`` sequence type
6228 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6231 tag_default = tag_encode(form=TagFormConstructed, num=17)
6232 asn1_type_name = "SET OF"
6235 raws = self._encoded_values()
6238 return b"".join((self.tag, len_encode(len(v)), v))
6240 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6241 return super(SetOf, self)._decode(
6247 ordering_check=True,
6251 def obj_by_path(pypath): # pragma: no cover
6252 """Import object specified as string Python path
6254 Modules must be separated from classes/functions with ``:``.
6256 >>> obj_by_path("foo.bar:Baz")
6257 <class 'foo.bar.Baz'>
6258 >>> obj_by_path("foo.bar:Baz.boo")
6259 <classmethod 'foo.bar.Baz.boo'>
6261 mod, objs = pypath.rsplit(":", 1)
6262 from importlib import import_module
6263 obj = import_module(mod)
6264 for obj_name in objs.split("."):
6265 obj = getattr(obj, obj_name)
6269 def generic_decoder(): # pragma: no cover
6270 # All of this below is a big hack with self references
6271 choice = PrimitiveTypes()
6272 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6273 choice.specs["SetOf"] = SetOf(schema=choice)
6274 for i in six_xrange(31):
6275 choice.specs["SequenceOf%d" % i] = SequenceOf(
6279 choice.specs["Any"] = Any()
6281 # Class name equals to type name, to omit it from output
6282 class SEQUENCEOF(SequenceOf):
6290 with_decode_path=False,
6291 decode_path_only=(),
6293 def _pprint_pps(pps):
6295 if hasattr(pp, "_fields"):
6297 decode_path_only != () and
6298 pp.decode_path[:len(decode_path_only)] != decode_path_only
6301 if pp.asn1_type_name == Choice.asn1_type_name:
6303 pp_kwargs = pp._asdict()
6304 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6305 pp = _pp(**pp_kwargs)
6306 yield pp_console_row(
6311 with_colours=with_colours,
6312 with_decode_path=with_decode_path,
6313 decode_path_len_decrease=len(decode_path_only),
6315 for row in pp_console_blob(
6317 decode_path_len_decrease=len(decode_path_only),
6321 for row in _pprint_pps(pp):
6323 return "\n".join(_pprint_pps(obj.pps()))
6324 return SEQUENCEOF(), pprint_any
6327 def main(): # pragma: no cover
6329 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6330 parser.add_argument(
6334 help="Skip that number of bytes from the beginning",
6336 parser.add_argument(
6338 help="Python paths to dictionary with OIDs, comma separated",
6340 parser.add_argument(
6342 help="Python path to schema definition to use",
6344 parser.add_argument(
6345 "--defines-by-path",
6346 help="Python path to decoder's defines_by_path",
6348 parser.add_argument(
6350 action="store_true",
6351 help="Disallow BER encoding",
6353 parser.add_argument(
6354 "--print-decode-path",
6355 action="store_true",
6356 help="Print decode paths",
6358 parser.add_argument(
6359 "--decode-path-only",
6360 help="Print only specified decode path",
6362 parser.add_argument(
6364 action="store_true",
6365 help="Allow explicit tag out-of-bound",
6367 parser.add_argument(
6369 type=argparse.FileType("rb"),
6370 help="Path to DER file you want to decode",
6372 args = parser.parse_args()
6373 args.DERFile.seek(args.skip)
6374 der = memoryview(args.DERFile.read())
6375 args.DERFile.close()
6377 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6378 if args.oids else ()
6381 schema = obj_by_path(args.schema)
6382 from functools import partial
6383 pprinter = partial(pprint, big_blobs=True)
6385 schema, pprinter = generic_decoder()
6387 "bered": not args.nobered,
6388 "allow_expl_oob": args.allow_expl_oob,
6390 if args.defines_by_path is not None:
6391 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6392 obj, tail = schema().decode(der, ctx=ctx)
6396 with_colours=environ.get("NO_COLOR") is None,
6397 with_decode_path=args.print_decode_path,
6399 () if args.decode_path_only is None else
6400 tuple(args.decode_path_only.split(":"))
6404 print("\nTrailing data: %s" % hexenc(tail))
6407 if __name__ == "__main__":