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 sys import version_info
670 from unicodedata import category as unicat
672 from six import add_metaclass
673 from six import binary_type
674 from six import byte2int
675 from six import indexbytes
676 from six import int2byte
677 from six import integer_types
678 from six import iterbytes
679 from six import iteritems
680 from six import itervalues
682 from six import string_types
683 from six import text_type
684 from six import unichr as six_unichr
685 from six.moves import xrange as six_xrange
689 from termcolor import colored
690 except ImportError: # pragma: no cover
691 def colored(what, *args, **kwargs):
737 "TagClassApplication",
741 "TagFormConstructed",
752 TagClassUniversal = 0
753 TagClassApplication = 1 << 6
754 TagClassContext = 1 << 7
755 TagClassPrivate = 1 << 6 | 1 << 7
757 TagFormConstructed = 1 << 5
760 TagClassApplication: "APPLICATION ",
761 TagClassPrivate: "PRIVATE ",
762 TagClassUniversal: "UNIV ",
766 LENINDEF = b"\x80" # length indefinite mark
767 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
768 NAMEDTUPLE_KWARGS = {} if version_info < (3, 6) else {"module": __name__}
769 SET01 = frozenset("01")
770 DECIMALS = frozenset(digits)
775 if not set(value) <= DECIMALS:
776 raise ValueError("non-pure integer")
779 def fractions2float(fractions_raw):
780 pureint(fractions_raw)
781 return float("0." + fractions_raw)
784 ########################################################################
786 ########################################################################
788 class ASN1Error(ValueError):
792 class DecodeError(ASN1Error):
793 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
795 :param str msg: reason of decode failing
796 :param klass: optional exact DecodeError inherited class (like
797 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
798 :py:exc:`InvalidLength`)
799 :param decode_path: tuple of strings. It contains human
800 readable names of the fields through which
801 decoding process has passed
802 :param int offset: binary offset where failure happened
804 super(DecodeError, self).__init__()
807 self.decode_path = decode_path
813 "" if self.klass is None else self.klass.__name__,
815 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
816 if len(self.decode_path) > 0 else ""
818 ("(at %d)" % self.offset) if self.offset > 0 else "",
824 return "%s(%s)" % (self.__class__.__name__, self)
827 class NotEnoughData(DecodeError):
831 class ExceedingData(ASN1Error):
832 def __init__(self, nbytes):
833 super(ExceedingData, self).__init__()
837 return "%d trailing bytes" % self.nbytes
840 return "%s(%s)" % (self.__class__.__name__, self)
843 class LenIndefForm(DecodeError):
847 class TagMismatch(DecodeError):
851 class InvalidLength(DecodeError):
855 class InvalidOID(DecodeError):
859 class ObjUnknown(ASN1Error):
860 def __init__(self, name):
861 super(ObjUnknown, self).__init__()
865 return "object is unknown: %s" % self.name
868 return "%s(%s)" % (self.__class__.__name__, self)
871 class ObjNotReady(ASN1Error):
872 def __init__(self, name):
873 super(ObjNotReady, self).__init__()
877 return "object is not ready: %s" % self.name
880 return "%s(%s)" % (self.__class__.__name__, self)
883 class InvalidValueType(ASN1Error):
884 def __init__(self, expected_types):
885 super(InvalidValueType, self).__init__()
886 self.expected_types = expected_types
889 return "invalid value type, expected: %s" % ", ".join(
890 [repr(t) for t in self.expected_types]
894 return "%s(%s)" % (self.__class__.__name__, self)
897 class BoundsError(ASN1Error):
898 def __init__(self, bound_min, value, bound_max):
899 super(BoundsError, self).__init__()
900 self.bound_min = bound_min
902 self.bound_max = bound_max
905 return "unsatisfied bounds: %s <= %s <= %s" % (
912 return "%s(%s)" % (self.__class__.__name__, self)
915 ########################################################################
917 ########################################################################
919 _hexdecoder = getdecoder("hex")
920 _hexencoder = getencoder("hex")
924 """Binary data to hexadecimal string convert
926 return _hexdecoder(data)[0]
930 """Hexadecimal string to binary data convert
932 return _hexencoder(data)[0].decode("ascii")
935 def int_bytes_len(num, byte_len=8):
938 return int(ceil(float(num.bit_length()) / byte_len))
941 def zero_ended_encode(num):
942 octets = bytearray(int_bytes_len(num, 7))
944 octets[i] = num & 0x7F
948 octets[i] = 0x80 | (num & 0x7F)
954 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
955 """Encode tag to binary form
957 :param int num: tag's number
958 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
959 :py:data:`pyderasn.TagClassContext`,
960 :py:data:`pyderasn.TagClassApplication`,
961 :py:data:`pyderasn.TagClassPrivate`)
962 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
963 :py:data:`pyderasn.TagFormConstructed`)
967 return int2byte(klass | form | num)
968 # [XX|X|11111][1.......][1.......] ... [0.......]
969 return int2byte(klass | form | 31) + zero_ended_encode(num)
973 """Decode tag from binary form
977 No validation is performed, assuming that it has already passed.
979 It returns tuple with three integers, as
980 :py:func:`pyderasn.tag_encode` accepts.
982 first_octet = byte2int(tag)
983 klass = first_octet & 0xC0
984 form = first_octet & 0x20
985 if first_octet & 0x1F < 0x1F:
986 return (klass, form, first_octet & 0x1F)
988 for octet in iterbytes(tag[1:]):
991 return (klass, form, num)
995 """Create CONTEXT PRIMITIVE tag
997 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1001 """Create CONTEXT CONSTRUCTED tag
1003 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1006 def tag_strip(data):
1007 """Take off tag from the data
1009 :returns: (encoded tag, tag length, remaining data)
1012 raise NotEnoughData("no data at all")
1013 if byte2int(data) & 0x1F < 31:
1014 return data[:1], 1, data[1:]
1019 raise DecodeError("unfinished tag")
1020 if indexbytes(data, i) & 0x80 == 0:
1023 return data[:i], i, data[i:]
1029 octets = bytearray(int_bytes_len(l) + 1)
1030 octets[0] = 0x80 | (len(octets) - 1)
1031 for i in six_xrange(len(octets) - 1, 0, -1):
1032 octets[i] = l & 0xFF
1034 return bytes(octets)
1037 def len_decode(data):
1040 :returns: (decoded length, length's length, remaining data)
1041 :raises LenIndefForm: if indefinite form encoding is met
1044 raise NotEnoughData("no data at all")
1045 first_octet = byte2int(data)
1046 if first_octet & 0x80 == 0:
1047 return first_octet, 1, data[1:]
1048 octets_num = first_octet & 0x7F
1049 if octets_num + 1 > len(data):
1050 raise NotEnoughData("encoded length is longer than data")
1052 raise LenIndefForm()
1053 if byte2int(data[1:]) == 0:
1054 raise DecodeError("leading zeros")
1056 for v in iterbytes(data[1:1 + octets_num]):
1059 raise DecodeError("long form instead of short one")
1060 return l, 1 + octets_num, data[1 + octets_num:]
1063 ########################################################################
1065 ########################################################################
1067 class AutoAddSlots(type):
1068 def __new__(cls, name, bases, _dict):
1069 _dict["__slots__"] = _dict.get("__slots__", ())
1070 return type.__new__(cls, name, bases, _dict)
1073 @add_metaclass(AutoAddSlots)
1075 """Common ASN.1 object class
1077 All ASN.1 types are inherited from it. It has metaclass that
1078 automatically adds ``__slots__`` to all inherited classes.
1102 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1103 self._expl = getattr(self, "expl", None) if expl is None else expl
1104 if self.tag != self.tag_default and self._expl is not None:
1105 raise ValueError("implicit and explicit tags can not be set simultaneously")
1106 if default is not None:
1108 self.optional = optional
1109 self.offset, self.llen, self.vlen = _decoded
1111 self.expl_lenindef = False
1112 self.lenindef = False
1113 self.ber_encoded = False
1116 def ready(self): # pragma: no cover
1117 """Is object ready to be encoded?
1119 raise NotImplementedError()
1121 def _assert_ready(self):
1123 raise ObjNotReady(self.__class__.__name__)
1127 """Is either object or any elements inside is BER encoded?
1129 return self.expl_lenindef or self.lenindef or self.ber_encoded
1133 """Is object decoded?
1135 return (self.llen + self.vlen) > 0
1137 def __getstate__(self): # pragma: no cover
1138 """Used for making safe to be mutable pickleable copies
1140 raise NotImplementedError()
1142 def __setstate__(self, state):
1143 if state.version != __version__:
1144 raise ValueError("data is pickled by different PyDERASN version")
1145 self.tag = self.tag_default
1149 self.optional = False
1153 self.expl_lenindef = False
1154 self.lenindef = False
1155 self.ber_encoded = False
1159 """See :ref:`decoding`
1161 return len(self.tag)
1165 """See :ref:`decoding`
1167 return self.tlen + self.llen + self.vlen
1169 def __str__(self): # pragma: no cover
1170 return self.__bytes__() if PY2 else self.__unicode__()
1172 def __ne__(self, their):
1173 return not(self == their)
1175 def __gt__(self, their): # pragma: no cover
1176 return not(self < their)
1178 def __le__(self, their): # pragma: no cover
1179 return (self == their) or (self < their)
1181 def __ge__(self, their): # pragma: no cover
1182 return (self == their) or (self > their)
1184 def _encode(self): # pragma: no cover
1185 raise NotImplementedError()
1187 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1188 raise NotImplementedError()
1191 """Encode the structure
1193 :returns: DER representation
1195 raw = self._encode()
1196 if self._expl is None:
1198 return b"".join((self._expl, len_encode(len(raw)), raw))
1200 def hexencode(self):
1201 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1203 return hexenc(self.encode())
1213 _ctx_immutable=True,
1217 :param data: either binary or memoryview
1218 :param int offset: initial data's offset
1219 :param bool leavemm: do we need to leave memoryview of remaining
1220 data as is, or convert it to bytes otherwise
1221 :param ctx: optional :ref:`context <ctx>` governing decoding process
1222 :param tag_only: decode only the tag, without length and contents
1223 (used only in Choice and Set structures, trying to
1224 determine if tag satisfies the scheme)
1225 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1227 :returns: (Obj, remaining data)
1229 .. seealso:: :ref:`decoding`
1233 elif _ctx_immutable:
1235 tlv = memoryview(data)
1236 if self._expl is None:
1237 result = self._decode(
1240 decode_path=decode_path,
1249 t, tlen, lv = tag_strip(tlv)
1250 except DecodeError as err:
1251 raise err.__class__(
1253 klass=self.__class__,
1254 decode_path=decode_path,
1259 klass=self.__class__,
1260 decode_path=decode_path,
1264 l, llen, v = len_decode(lv)
1265 except LenIndefForm as err:
1266 if not ctx.get("bered", False):
1267 raise err.__class__(
1269 klass=self.__class__,
1270 decode_path=decode_path,
1274 offset += tlen + llen
1275 result = self._decode(
1278 decode_path=decode_path,
1282 if tag_only: # pragma: no cover
1285 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1286 if eoc_expected.tobytes() != EOC:
1289 klass=self.__class__,
1290 decode_path=decode_path,
1294 obj.expl_lenindef = True
1295 except DecodeError as err:
1296 raise err.__class__(
1298 klass=self.__class__,
1299 decode_path=decode_path,
1304 raise NotEnoughData(
1305 "encoded length is longer than data",
1306 klass=self.__class__,
1307 decode_path=decode_path,
1310 result = self._decode(
1312 offset=offset + tlen + llen,
1313 decode_path=decode_path,
1317 if tag_only: # pragma: no cover
1320 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1322 "explicit tag out-of-bound, longer than data",
1323 klass=self.__class__,
1324 decode_path=decode_path,
1327 return obj, (tail if leavemm else tail.tobytes())
1329 def decod(self, data, offset=0, decode_path=(), ctx=None):
1330 """Decode the data, check that tail is empty
1332 :raises ExceedingData: if tail is not empty
1334 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1335 (decode without tail) that also checks that there is no
1338 obj, tail = self.decode(
1341 decode_path=decode_path,
1346 raise ExceedingData(len(tail))
1349 def hexdecode(self, data, *args, **kwargs):
1350 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1352 return self.decode(hexdec(data), *args, **kwargs)
1354 def hexdecod(self, data, *args, **kwargs):
1355 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1357 return self.decod(hexdec(data), *args, **kwargs)
1361 """See :ref:`decoding`
1363 return self._expl is not None
1367 """See :ref:`decoding`
1372 def expl_tlen(self):
1373 """See :ref:`decoding`
1375 return len(self._expl)
1378 def expl_llen(self):
1379 """See :ref:`decoding`
1381 if self.expl_lenindef:
1383 return len(len_encode(self.tlvlen))
1386 def expl_offset(self):
1387 """See :ref:`decoding`
1389 return self.offset - self.expl_tlen - self.expl_llen
1392 def expl_vlen(self):
1393 """See :ref:`decoding`
1398 def expl_tlvlen(self):
1399 """See :ref:`decoding`
1401 return self.expl_tlen + self.expl_llen + self.expl_vlen
1404 def fulloffset(self):
1405 """See :ref:`decoding`
1407 return self.expl_offset if self.expled else self.offset
1411 """See :ref:`decoding`
1413 return self.expl_tlvlen if self.expled else self.tlvlen
1415 def pps_lenindef(self, decode_path):
1416 if self.lenindef and not (
1417 getattr(self, "defined", None) is not None and
1418 self.defined[1].lenindef
1421 asn1_type_name="EOC",
1423 decode_path=decode_path,
1425 self.offset + self.tlvlen -
1426 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1434 if self.expl_lenindef:
1436 asn1_type_name="EOC",
1437 obj_name="EXPLICIT",
1438 decode_path=decode_path,
1439 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1448 class DecodePathDefBy(object):
1449 """DEFINED BY representation inside decode path
1451 __slots__ = ("defined_by",)
1453 def __init__(self, defined_by):
1454 self.defined_by = defined_by
1456 def __ne__(self, their):
1457 return not(self == their)
1459 def __eq__(self, their):
1460 if not isinstance(their, self.__class__):
1462 return self.defined_by == their.defined_by
1465 return "DEFINED BY " + str(self.defined_by)
1468 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1471 ########################################################################
1473 ########################################################################
1475 PP = namedtuple("PP", (
1498 ), **NAMEDTUPLE_KWARGS)
1503 asn1_type_name="unknown",
1520 expl_lenindef=False,
1551 def _colourize(what, colour, with_colours, attrs=("bold",)):
1552 return colored(what, colour, attrs=attrs) if with_colours else what
1555 def colonize_hex(hexed):
1556 """Separate hexadecimal string with colons
1558 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1567 with_decode_path=False,
1568 decode_path_len_decrease=0,
1575 " " if pp.expl_offset is None else
1576 ("-%d" % (pp.offset - pp.expl_offset))
1578 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1580 col = _colourize(col, "red", with_colours, ())
1581 col += _colourize("B", "red", with_colours) if pp.bered else " "
1583 col = "[%d,%d,%4d]%s" % (
1587 LENINDEF_PP_CHAR if pp.lenindef else " "
1589 col = _colourize(col, "green", with_colours, ())
1591 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1592 if decode_path_len > 0:
1593 cols.append(" ." * decode_path_len)
1594 ent = pp.decode_path[-1]
1595 if isinstance(ent, DecodePathDefBy):
1596 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1597 value = str(ent.defined_by)
1600 len(oid_maps) > 0 and
1601 ent.defined_by.asn1_type_name ==
1602 ObjectIdentifier.asn1_type_name
1604 for oid_map in oid_maps:
1605 oid_name = oid_map.get(value)
1606 if oid_name is not None:
1607 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1609 if oid_name is None:
1610 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1612 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1613 if pp.expl is not None:
1614 klass, _, num = pp.expl
1615 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1616 cols.append(_colourize(col, "blue", with_colours))
1617 if pp.impl is not None:
1618 klass, _, num = pp.impl
1619 col = "[%s%d]" % (TagClassReprs[klass], num)
1620 cols.append(_colourize(col, "blue", with_colours))
1621 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1622 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1624 cols.append(_colourize("BER", "red", with_colours))
1625 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1626 if pp.value is not None:
1628 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1630 len(oid_maps) > 0 and
1631 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1633 for oid_map in oid_maps:
1634 oid_name = oid_map.get(value)
1635 if oid_name is not None:
1636 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1638 if pp.asn1_type_name == Integer.asn1_type_name:
1639 hex_repr = hex(int(pp.obj._value))[2:].upper()
1640 if len(hex_repr) % 2 != 0:
1641 hex_repr = "0" + hex_repr
1642 cols.append(_colourize(
1643 "(%s)" % colonize_hex(hex_repr),
1648 if pp.blob.__class__ == binary_type:
1649 cols.append(hexenc(pp.blob))
1650 elif pp.blob.__class__ == tuple:
1651 cols.append(", ".join(pp.blob))
1653 cols.append(_colourize("OPTIONAL", "red", with_colours))
1655 cols.append(_colourize("DEFAULT", "red", with_colours))
1656 if with_decode_path:
1657 cols.append(_colourize(
1658 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1662 return " ".join(cols)
1665 def pp_console_blob(pp, decode_path_len_decrease=0):
1666 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1667 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1668 if decode_path_len > 0:
1669 cols.append(" ." * (decode_path_len + 1))
1670 if pp.blob.__class__ == binary_type:
1671 blob = hexenc(pp.blob).upper()
1672 for i in six_xrange(0, len(blob), 32):
1673 chunk = blob[i:i + 32]
1674 yield " ".join(cols + [colonize_hex(chunk)])
1675 elif pp.blob.__class__ == tuple:
1676 yield " ".join(cols + [", ".join(pp.blob)])
1684 with_decode_path=False,
1685 decode_path_only=(),
1687 """Pretty print object
1689 :param Obj obj: object you want to pretty print
1690 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1691 Its human readable form is printed when OID is met
1692 :param big_blobs: if large binary objects are met (like OctetString
1693 values), do we need to print them too, on separate
1695 :param with_colours: colourize output, if ``termcolor`` library
1697 :param with_decode_path: print decode path
1698 :param decode_path_only: print only that specified decode path
1700 def _pprint_pps(pps):
1702 if hasattr(pp, "_fields"):
1704 decode_path_only != () and
1706 str(p) for p in pp.decode_path[:len(decode_path_only)]
1707 ) != decode_path_only
1711 yield pp_console_row(
1716 with_colours=with_colours,
1717 with_decode_path=with_decode_path,
1718 decode_path_len_decrease=len(decode_path_only),
1720 for row in pp_console_blob(
1722 decode_path_len_decrease=len(decode_path_only),
1726 yield pp_console_row(
1731 with_colours=with_colours,
1732 with_decode_path=with_decode_path,
1733 decode_path_len_decrease=len(decode_path_only),
1736 for row in _pprint_pps(pp):
1738 return "\n".join(_pprint_pps(obj.pps()))
1741 ########################################################################
1742 # ASN.1 primitive types
1743 ########################################################################
1745 BooleanState = namedtuple("BooleanState", (
1758 ), **NAMEDTUPLE_KWARGS)
1762 """``BOOLEAN`` boolean type
1764 >>> b = Boolean(True)
1766 >>> b == Boolean(True)
1772 tag_default = tag_encode(1)
1773 asn1_type_name = "BOOLEAN"
1785 :param value: set the value. Either boolean type, or
1786 :py:class:`pyderasn.Boolean` object
1787 :param bytes impl: override default tag with ``IMPLICIT`` one
1788 :param bytes expl: override default tag with ``EXPLICIT`` one
1789 :param default: set default value. Type same as in ``value``
1790 :param bool optional: is object ``OPTIONAL`` in sequence
1792 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1793 self._value = None if value is None else self._value_sanitize(value)
1794 if default is not None:
1795 default = self._value_sanitize(default)
1796 self.default = self.__class__(
1802 self._value = default
1804 def _value_sanitize(self, value):
1805 if value.__class__ == bool:
1807 if issubclass(value.__class__, Boolean):
1809 raise InvalidValueType((self.__class__, bool))
1813 return self._value is not None
1815 def __getstate__(self):
1816 return BooleanState(
1831 def __setstate__(self, state):
1832 super(Boolean, self).__setstate__(state)
1833 self._value = state.value
1834 self.tag = state.tag
1835 self._expl = state.expl
1836 self.default = state.default
1837 self.optional = state.optional
1838 self.offset = state.offset
1839 self.llen = state.llen
1840 self.vlen = state.vlen
1841 self.expl_lenindef = state.expl_lenindef
1842 self.lenindef = state.lenindef
1843 self.ber_encoded = state.ber_encoded
1845 def __nonzero__(self):
1846 self._assert_ready()
1850 self._assert_ready()
1853 def __eq__(self, their):
1854 if their.__class__ == bool:
1855 return self._value == their
1856 if not issubclass(their.__class__, Boolean):
1859 self._value == their._value and
1860 self.tag == their.tag and
1861 self._expl == their._expl
1872 return self.__class__(
1874 impl=self.tag if impl is None else impl,
1875 expl=self._expl if expl is None else expl,
1876 default=self.default if default is None else default,
1877 optional=self.optional if optional is None else optional,
1881 self._assert_ready()
1885 (b"\xFF" if self._value else b"\x00"),
1888 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1890 t, _, lv = tag_strip(tlv)
1891 except DecodeError as err:
1892 raise err.__class__(
1894 klass=self.__class__,
1895 decode_path=decode_path,
1900 klass=self.__class__,
1901 decode_path=decode_path,
1907 l, _, v = len_decode(lv)
1908 except DecodeError as err:
1909 raise err.__class__(
1911 klass=self.__class__,
1912 decode_path=decode_path,
1916 raise InvalidLength(
1917 "Boolean's length must be equal to 1",
1918 klass=self.__class__,
1919 decode_path=decode_path,
1923 raise NotEnoughData(
1924 "encoded length is longer than data",
1925 klass=self.__class__,
1926 decode_path=decode_path,
1929 first_octet = byte2int(v)
1931 if first_octet == 0:
1933 elif first_octet == 0xFF:
1935 elif ctx.get("bered", False):
1940 "unacceptable Boolean value",
1941 klass=self.__class__,
1942 decode_path=decode_path,
1945 obj = self.__class__(
1949 default=self.default,
1950 optional=self.optional,
1951 _decoded=(offset, 1, 1),
1953 obj.ber_encoded = ber_encoded
1957 return pp_console_row(next(self.pps()))
1959 def pps(self, decode_path=()):
1962 asn1_type_name=self.asn1_type_name,
1963 obj_name=self.__class__.__name__,
1964 decode_path=decode_path,
1965 value=str(self._value) if self.ready else None,
1966 optional=self.optional,
1967 default=self == self.default,
1968 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1969 expl=None if self._expl is None else tag_decode(self._expl),
1974 expl_offset=self.expl_offset if self.expled else None,
1975 expl_tlen=self.expl_tlen if self.expled else None,
1976 expl_llen=self.expl_llen if self.expled else None,
1977 expl_vlen=self.expl_vlen if self.expled else None,
1978 expl_lenindef=self.expl_lenindef,
1979 ber_encoded=self.ber_encoded,
1982 for pp in self.pps_lenindef(decode_path):
1986 IntegerState = namedtuple("IntegerState", (
2002 ), **NAMEDTUPLE_KWARGS)
2006 """``INTEGER`` integer type
2008 >>> b = Integer(-123)
2010 >>> b == Integer(-123)
2015 >>> Integer(2, bounds=(1, 3))
2017 >>> Integer(5, bounds=(1, 3))
2018 Traceback (most recent call last):
2019 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2023 class Version(Integer):
2030 >>> v = Version("v1")
2037 {'v3': 2, 'v1': 0, 'v2': 1}
2039 __slots__ = ("specs", "_bound_min", "_bound_max")
2040 tag_default = tag_encode(2)
2041 asn1_type_name = "INTEGER"
2055 :param value: set the value. Either integer type, named value
2056 (if ``schema`` is specified in the class), or
2057 :py:class:`pyderasn.Integer` object
2058 :param bounds: set ``(MIN, MAX)`` value constraint.
2059 (-inf, +inf) by default
2060 :param bytes impl: override default tag with ``IMPLICIT`` one
2061 :param bytes expl: override default tag with ``EXPLICIT`` one
2062 :param default: set default value. Type same as in ``value``
2063 :param bool optional: is object ``OPTIONAL`` in sequence
2065 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2067 specs = getattr(self, "schema", {}) if _specs is None else _specs
2068 self.specs = specs if specs.__class__ == dict else dict(specs)
2069 self._bound_min, self._bound_max = getattr(
2072 (float("-inf"), float("+inf")),
2073 ) if bounds is None else bounds
2074 if value is not None:
2075 self._value = self._value_sanitize(value)
2076 if default is not None:
2077 default = self._value_sanitize(default)
2078 self.default = self.__class__(
2084 if self._value is None:
2085 self._value = default
2087 def _value_sanitize(self, value):
2088 if isinstance(value, integer_types):
2090 elif issubclass(value.__class__, Integer):
2091 value = value._value
2092 elif value.__class__ == str:
2093 value = self.specs.get(value)
2095 raise ObjUnknown("integer value: %s" % value)
2097 raise InvalidValueType((self.__class__, int, str))
2098 if not self._bound_min <= value <= self._bound_max:
2099 raise BoundsError(self._bound_min, value, self._bound_max)
2104 return self._value is not None
2106 def __getstate__(self):
2107 return IntegerState(
2125 def __setstate__(self, state):
2126 super(Integer, self).__setstate__(state)
2127 self.specs = state.specs
2128 self._value = state.value
2129 self._bound_min = state.bound_min
2130 self._bound_max = state.bound_max
2131 self.tag = state.tag
2132 self._expl = state.expl
2133 self.default = state.default
2134 self.optional = state.optional
2135 self.offset = state.offset
2136 self.llen = state.llen
2137 self.vlen = state.vlen
2138 self.expl_lenindef = state.expl_lenindef
2139 self.lenindef = state.lenindef
2140 self.ber_encoded = state.ber_encoded
2143 self._assert_ready()
2144 return int(self._value)
2147 self._assert_ready()
2150 bytes(self._expl or b"") +
2151 str(self._value).encode("ascii"),
2154 def __eq__(self, their):
2155 if isinstance(their, integer_types):
2156 return self._value == their
2157 if not issubclass(their.__class__, Integer):
2160 self._value == their._value and
2161 self.tag == their.tag and
2162 self._expl == their._expl
2165 def __lt__(self, their):
2166 return self._value < their._value
2170 for name, value in iteritems(self.specs):
2171 if value == self._value:
2184 return self.__class__(
2187 (self._bound_min, self._bound_max)
2188 if bounds is None else bounds
2190 impl=self.tag if impl is None else impl,
2191 expl=self._expl if expl is None else expl,
2192 default=self.default if default is None else default,
2193 optional=self.optional if optional is None else optional,
2198 self._assert_ready()
2202 octets = bytearray([0])
2206 octets = bytearray()
2208 octets.append((value & 0xFF) ^ 0xFF)
2210 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2213 octets = bytearray()
2215 octets.append(value & 0xFF)
2217 if octets[-1] & 0x80 > 0:
2220 octets = bytes(octets)
2222 bytes_len = ceil(value.bit_length() / 8) or 1
2225 octets = value.to_bytes(
2230 except OverflowError:
2234 return b"".join((self.tag, len_encode(len(octets)), octets))
2236 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2238 t, _, lv = tag_strip(tlv)
2239 except DecodeError as err:
2240 raise err.__class__(
2242 klass=self.__class__,
2243 decode_path=decode_path,
2248 klass=self.__class__,
2249 decode_path=decode_path,
2255 l, llen, v = len_decode(lv)
2256 except DecodeError as err:
2257 raise err.__class__(
2259 klass=self.__class__,
2260 decode_path=decode_path,
2264 raise NotEnoughData(
2265 "encoded length is longer than data",
2266 klass=self.__class__,
2267 decode_path=decode_path,
2271 raise NotEnoughData(
2273 klass=self.__class__,
2274 decode_path=decode_path,
2277 v, tail = v[:l], v[l:]
2278 first_octet = byte2int(v)
2280 second_octet = byte2int(v[1:])
2282 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2283 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2286 "non normalized integer",
2287 klass=self.__class__,
2288 decode_path=decode_path,
2293 if first_octet & 0x80 > 0:
2294 octets = bytearray()
2295 for octet in bytearray(v):
2296 octets.append(octet ^ 0xFF)
2297 for octet in octets:
2298 value = (value << 8) | octet
2302 for octet in bytearray(v):
2303 value = (value << 8) | octet
2305 value = int.from_bytes(v, byteorder="big", signed=True)
2307 obj = self.__class__(
2309 bounds=(self._bound_min, self._bound_max),
2312 default=self.default,
2313 optional=self.optional,
2315 _decoded=(offset, llen, l),
2317 except BoundsError as err:
2320 klass=self.__class__,
2321 decode_path=decode_path,
2327 return pp_console_row(next(self.pps()))
2329 def pps(self, decode_path=()):
2332 asn1_type_name=self.asn1_type_name,
2333 obj_name=self.__class__.__name__,
2334 decode_path=decode_path,
2335 value=(self.named or str(self._value)) if self.ready else None,
2336 optional=self.optional,
2337 default=self == self.default,
2338 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2339 expl=None if self._expl is None else tag_decode(self._expl),
2344 expl_offset=self.expl_offset if self.expled else None,
2345 expl_tlen=self.expl_tlen if self.expled else None,
2346 expl_llen=self.expl_llen if self.expled else None,
2347 expl_vlen=self.expl_vlen if self.expled else None,
2348 expl_lenindef=self.expl_lenindef,
2351 for pp in self.pps_lenindef(decode_path):
2355 BitStringState = namedtuple("BitStringState", (
2371 ), **NAMEDTUPLE_KWARGS)
2374 class BitString(Obj):
2375 """``BIT STRING`` bit string type
2377 >>> BitString(b"hello world")
2378 BIT STRING 88 bits 68656c6c6f20776f726c64
2381 >>> b == b"hello world"
2386 >>> BitString("'0A3B5F291CD'H")
2387 BIT STRING 44 bits 0a3b5f291cd0
2388 >>> b = BitString("'010110000000'B")
2389 BIT STRING 12 bits 5800
2392 >>> b[0], b[1], b[2], b[3]
2393 (False, True, False, True)
2397 [False, True, False, True, True, False, False, False, False, False, False, False]
2401 class KeyUsage(BitString):
2403 ("digitalSignature", 0),
2404 ("nonRepudiation", 1),
2405 ("keyEncipherment", 2),
2408 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2409 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2411 ['nonRepudiation', 'keyEncipherment']
2413 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2417 Pay attention that BIT STRING can be encoded both in primitive
2418 and constructed forms. Decoder always checks constructed form tag
2419 additionally to specified primitive one. If BER decoding is
2420 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2421 of DER restrictions.
2423 __slots__ = ("tag_constructed", "specs", "defined")
2424 tag_default = tag_encode(3)
2425 asn1_type_name = "BIT STRING"
2438 :param value: set the value. Either binary type, tuple of named
2439 values (if ``schema`` is specified in the class),
2440 string in ``'XXX...'B`` form, or
2441 :py:class:`pyderasn.BitString` object
2442 :param bytes impl: override default tag with ``IMPLICIT`` one
2443 :param bytes expl: override default tag with ``EXPLICIT`` one
2444 :param default: set default value. Type same as in ``value``
2445 :param bool optional: is object ``OPTIONAL`` in sequence
2447 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2448 specs = getattr(self, "schema", {}) if _specs is None else _specs
2449 self.specs = specs if specs.__class__ == dict else dict(specs)
2450 self._value = None if value is None else self._value_sanitize(value)
2451 if default is not None:
2452 default = self._value_sanitize(default)
2453 self.default = self.__class__(
2459 self._value = default
2461 tag_klass, _, tag_num = tag_decode(self.tag)
2462 self.tag_constructed = tag_encode(
2464 form=TagFormConstructed,
2468 def _bits2octets(self, bits):
2469 if len(self.specs) > 0:
2470 bits = bits.rstrip("0")
2472 bits += "0" * ((8 - (bit_len % 8)) % 8)
2473 octets = bytearray(len(bits) // 8)
2474 for i in six_xrange(len(octets)):
2475 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2476 return bit_len, bytes(octets)
2478 def _value_sanitize(self, value):
2479 if isinstance(value, (string_types, binary_type)):
2481 isinstance(value, string_types) and
2482 value.startswith("'")
2484 if value.endswith("'B"):
2486 if not frozenset(value) <= SET01:
2487 raise ValueError("B's coding contains unacceptable chars")
2488 return self._bits2octets(value)
2489 if value.endswith("'H"):
2493 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2495 if value.__class__ == binary_type:
2496 return (len(value) * 8, value)
2497 raise InvalidValueType((self.__class__, string_types, binary_type))
2498 if value.__class__ == tuple:
2501 isinstance(value[0], integer_types) and
2502 value[1].__class__ == binary_type
2507 bit = self.specs.get(name)
2509 raise ObjUnknown("BitString value: %s" % name)
2512 return self._bits2octets("")
2513 bits = frozenset(bits)
2514 return self._bits2octets("".join(
2515 ("1" if bit in bits else "0")
2516 for bit in six_xrange(max(bits) + 1)
2518 if issubclass(value.__class__, BitString):
2520 raise InvalidValueType((self.__class__, binary_type, string_types))
2524 return self._value is not None
2526 def __getstate__(self):
2527 return BitStringState(
2541 self.tag_constructed,
2545 def __setstate__(self, state):
2546 super(BitString, self).__setstate__(state)
2547 self.specs = state.specs
2548 self._value = state.value
2549 self.tag = state.tag
2550 self._expl = state.expl
2551 self.default = state.default
2552 self.optional = state.optional
2553 self.offset = state.offset
2554 self.llen = state.llen
2555 self.vlen = state.vlen
2556 self.expl_lenindef = state.expl_lenindef
2557 self.lenindef = state.lenindef
2558 self.ber_encoded = state.ber_encoded
2559 self.tag_constructed = state.tag_constructed
2560 self.defined = state.defined
2563 self._assert_ready()
2564 for i in six_xrange(self._value[0]):
2569 self._assert_ready()
2570 return self._value[0]
2572 def __bytes__(self):
2573 self._assert_ready()
2574 return self._value[1]
2576 def __eq__(self, their):
2577 if their.__class__ == bytes:
2578 return self._value[1] == their
2579 if not issubclass(their.__class__, BitString):
2582 self._value == their._value and
2583 self.tag == their.tag and
2584 self._expl == their._expl
2589 return [name for name, bit in iteritems(self.specs) if self[bit]]
2599 return self.__class__(
2601 impl=self.tag if impl is None else impl,
2602 expl=self._expl if expl is None else expl,
2603 default=self.default if default is None else default,
2604 optional=self.optional if optional is None else optional,
2608 def __getitem__(self, key):
2609 if key.__class__ == int:
2610 bit_len, octets = self._value
2614 byte2int(memoryview(octets)[key // 8:]) >>
2617 if isinstance(key, string_types):
2618 value = self.specs.get(key)
2620 raise ObjUnknown("BitString value: %s" % key)
2622 raise InvalidValueType((int, str))
2625 self._assert_ready()
2626 bit_len, octets = self._value
2629 len_encode(len(octets) + 1),
2630 int2byte((8 - bit_len % 8) % 8),
2634 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2636 t, tlen, lv = tag_strip(tlv)
2637 except DecodeError as err:
2638 raise err.__class__(
2640 klass=self.__class__,
2641 decode_path=decode_path,
2645 if tag_only: # pragma: no cover
2648 l, llen, v = len_decode(lv)
2649 except DecodeError as err:
2650 raise err.__class__(
2652 klass=self.__class__,
2653 decode_path=decode_path,
2657 raise NotEnoughData(
2658 "encoded length is longer than data",
2659 klass=self.__class__,
2660 decode_path=decode_path,
2664 raise NotEnoughData(
2666 klass=self.__class__,
2667 decode_path=decode_path,
2670 pad_size = byte2int(v)
2671 if l == 1 and pad_size != 0:
2673 "invalid empty value",
2674 klass=self.__class__,
2675 decode_path=decode_path,
2681 klass=self.__class__,
2682 decode_path=decode_path,
2685 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2688 klass=self.__class__,
2689 decode_path=decode_path,
2692 v, tail = v[:l], v[l:]
2693 obj = self.__class__(
2694 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2697 default=self.default,
2698 optional=self.optional,
2700 _decoded=(offset, llen, l),
2703 if t != self.tag_constructed:
2705 klass=self.__class__,
2706 decode_path=decode_path,
2709 if not ctx.get("bered", False):
2711 "unallowed BER constructed encoding",
2712 klass=self.__class__,
2713 decode_path=decode_path,
2716 if tag_only: # pragma: no cover
2720 l, llen, v = len_decode(lv)
2721 except LenIndefForm:
2722 llen, l, v = 1, 0, lv[1:]
2724 except DecodeError as err:
2725 raise err.__class__(
2727 klass=self.__class__,
2728 decode_path=decode_path,
2732 raise NotEnoughData(
2733 "encoded length is longer than data",
2734 klass=self.__class__,
2735 decode_path=decode_path,
2738 if not lenindef and l == 0:
2739 raise NotEnoughData(
2741 klass=self.__class__,
2742 decode_path=decode_path,
2746 sub_offset = offset + tlen + llen
2750 if v[:EOC_LEN].tobytes() == EOC:
2757 "chunk out of bounds",
2758 klass=self.__class__,
2759 decode_path=decode_path + (str(len(chunks) - 1),),
2760 offset=chunks[-1].offset,
2762 sub_decode_path = decode_path + (str(len(chunks)),)
2764 chunk, v_tail = BitString().decode(
2767 decode_path=sub_decode_path,
2770 _ctx_immutable=False,
2774 "expected BitString encoded chunk",
2775 klass=self.__class__,
2776 decode_path=sub_decode_path,
2779 chunks.append(chunk)
2780 sub_offset += chunk.tlvlen
2781 vlen += chunk.tlvlen
2783 if len(chunks) == 0:
2786 klass=self.__class__,
2787 decode_path=decode_path,
2792 for chunk_i, chunk in enumerate(chunks[:-1]):
2793 if chunk.bit_len % 8 != 0:
2795 "BitString chunk is not multiple of 8 bits",
2796 klass=self.__class__,
2797 decode_path=decode_path + (str(chunk_i),),
2798 offset=chunk.offset,
2800 values.append(bytes(chunk))
2801 bit_len += chunk.bit_len
2802 chunk_last = chunks[-1]
2803 values.append(bytes(chunk_last))
2804 bit_len += chunk_last.bit_len
2805 obj = self.__class__(
2806 value=(bit_len, b"".join(values)),
2809 default=self.default,
2810 optional=self.optional,
2812 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2814 obj.lenindef = lenindef
2815 obj.ber_encoded = True
2816 return obj, (v[EOC_LEN:] if lenindef else v)
2819 return pp_console_row(next(self.pps()))
2821 def pps(self, decode_path=()):
2825 bit_len, blob = self._value
2826 value = "%d bits" % bit_len
2827 if len(self.specs) > 0:
2828 blob = tuple(self.named)
2831 asn1_type_name=self.asn1_type_name,
2832 obj_name=self.__class__.__name__,
2833 decode_path=decode_path,
2836 optional=self.optional,
2837 default=self == self.default,
2838 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2839 expl=None if self._expl is None else tag_decode(self._expl),
2844 expl_offset=self.expl_offset if self.expled else None,
2845 expl_tlen=self.expl_tlen if self.expled else None,
2846 expl_llen=self.expl_llen if self.expled else None,
2847 expl_vlen=self.expl_vlen if self.expled else None,
2848 expl_lenindef=self.expl_lenindef,
2849 lenindef=self.lenindef,
2850 ber_encoded=self.ber_encoded,
2853 defined_by, defined = self.defined or (None, None)
2854 if defined_by is not None:
2856 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2858 for pp in self.pps_lenindef(decode_path):
2862 OctetStringState = namedtuple("OctetStringState", (
2879 ), **NAMEDTUPLE_KWARGS)
2882 class OctetString(Obj):
2883 """``OCTET STRING`` binary string type
2885 >>> s = OctetString(b"hello world")
2886 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2887 >>> s == OctetString(b"hello world")
2892 >>> OctetString(b"hello", bounds=(4, 4))
2893 Traceback (most recent call last):
2894 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2895 >>> OctetString(b"hell", bounds=(4, 4))
2896 OCTET STRING 4 bytes 68656c6c
2900 Pay attention that OCTET STRING can be encoded both in primitive
2901 and constructed forms. Decoder always checks constructed form tag
2902 additionally to specified primitive one. If BER decoding is
2903 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2904 of DER restrictions.
2906 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2907 tag_default = tag_encode(4)
2908 asn1_type_name = "OCTET STRING"
2922 :param value: set the value. Either binary type, or
2923 :py:class:`pyderasn.OctetString` object
2924 :param bounds: set ``(MIN, MAX)`` value size constraint.
2925 (-inf, +inf) by default
2926 :param bytes impl: override default tag with ``IMPLICIT`` one
2927 :param bytes expl: override default tag with ``EXPLICIT`` one
2928 :param default: set default value. Type same as in ``value``
2929 :param bool optional: is object ``OPTIONAL`` in sequence
2931 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2933 self._bound_min, self._bound_max = getattr(
2937 ) if bounds is None else bounds
2938 if value is not None:
2939 self._value = self._value_sanitize(value)
2940 if default is not None:
2941 default = self._value_sanitize(default)
2942 self.default = self.__class__(
2947 if self._value is None:
2948 self._value = default
2950 tag_klass, _, tag_num = tag_decode(self.tag)
2951 self.tag_constructed = tag_encode(
2953 form=TagFormConstructed,
2957 def _value_sanitize(self, value):
2958 if value.__class__ == binary_type:
2960 elif issubclass(value.__class__, OctetString):
2961 value = value._value
2963 raise InvalidValueType((self.__class__, bytes))
2964 if not self._bound_min <= len(value) <= self._bound_max:
2965 raise BoundsError(self._bound_min, len(value), self._bound_max)
2970 return self._value is not None
2972 def __getstate__(self):
2973 return OctetStringState(
2988 self.tag_constructed,
2992 def __setstate__(self, state):
2993 super(OctetString, self).__setstate__(state)
2994 self._value = state.value
2995 self._bound_min = state.bound_min
2996 self._bound_max = state.bound_max
2997 self.tag = state.tag
2998 self._expl = state.expl
2999 self.default = state.default
3000 self.optional = state.optional
3001 self.offset = state.offset
3002 self.llen = state.llen
3003 self.vlen = state.vlen
3004 self.expl_lenindef = state.expl_lenindef
3005 self.lenindef = state.lenindef
3006 self.ber_encoded = state.ber_encoded
3007 self.tag_constructed = state.tag_constructed
3008 self.defined = state.defined
3010 def __bytes__(self):
3011 self._assert_ready()
3014 def __eq__(self, their):
3015 if their.__class__ == binary_type:
3016 return self._value == their
3017 if not issubclass(their.__class__, OctetString):
3020 self._value == their._value and
3021 self.tag == their.tag and
3022 self._expl == their._expl
3025 def __lt__(self, their):
3026 return self._value < their._value
3037 return self.__class__(
3040 (self._bound_min, self._bound_max)
3041 if bounds is None else bounds
3043 impl=self.tag if impl is None else impl,
3044 expl=self._expl if expl is None else expl,
3045 default=self.default if default is None else default,
3046 optional=self.optional if optional is None else optional,
3050 self._assert_ready()
3053 len_encode(len(self._value)),
3057 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3059 t, tlen, lv = tag_strip(tlv)
3060 except DecodeError as err:
3061 raise err.__class__(
3063 klass=self.__class__,
3064 decode_path=decode_path,
3071 l, llen, v = len_decode(lv)
3072 except DecodeError as err:
3073 raise err.__class__(
3075 klass=self.__class__,
3076 decode_path=decode_path,
3080 raise NotEnoughData(
3081 "encoded length is longer than data",
3082 klass=self.__class__,
3083 decode_path=decode_path,
3086 v, tail = v[:l], v[l:]
3088 obj = self.__class__(
3090 bounds=(self._bound_min, self._bound_max),
3093 default=self.default,
3094 optional=self.optional,
3095 _decoded=(offset, llen, l),
3098 except DecodeError as err:
3101 klass=self.__class__,
3102 decode_path=decode_path,
3105 except BoundsError as err:
3108 klass=self.__class__,
3109 decode_path=decode_path,
3113 if t != self.tag_constructed:
3115 klass=self.__class__,
3116 decode_path=decode_path,
3119 if not ctx.get("bered", False):
3121 "unallowed BER constructed encoding",
3122 klass=self.__class__,
3123 decode_path=decode_path,
3130 l, llen, v = len_decode(lv)
3131 except LenIndefForm:
3132 llen, l, v = 1, 0, lv[1:]
3134 except DecodeError as err:
3135 raise err.__class__(
3137 klass=self.__class__,
3138 decode_path=decode_path,
3142 raise NotEnoughData(
3143 "encoded length is longer than data",
3144 klass=self.__class__,
3145 decode_path=decode_path,
3149 sub_offset = offset + tlen + llen
3153 if v[:EOC_LEN].tobytes() == EOC:
3160 "chunk out of bounds",
3161 klass=self.__class__,
3162 decode_path=decode_path + (str(len(chunks) - 1),),
3163 offset=chunks[-1].offset,
3165 sub_decode_path = decode_path + (str(len(chunks)),)
3167 chunk, v_tail = OctetString().decode(
3170 decode_path=sub_decode_path,
3173 _ctx_immutable=False,
3177 "expected OctetString encoded chunk",
3178 klass=self.__class__,
3179 decode_path=sub_decode_path,
3182 chunks.append(chunk)
3183 sub_offset += chunk.tlvlen
3184 vlen += chunk.tlvlen
3187 obj = self.__class__(
3188 value=b"".join(bytes(chunk) for chunk in chunks),
3189 bounds=(self._bound_min, self._bound_max),
3192 default=self.default,
3193 optional=self.optional,
3194 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3197 except DecodeError as err:
3200 klass=self.__class__,
3201 decode_path=decode_path,
3204 except BoundsError as err:
3207 klass=self.__class__,
3208 decode_path=decode_path,
3211 obj.lenindef = lenindef
3212 obj.ber_encoded = True
3213 return obj, (v[EOC_LEN:] if lenindef else v)
3216 return pp_console_row(next(self.pps()))
3218 def pps(self, decode_path=()):
3221 asn1_type_name=self.asn1_type_name,
3222 obj_name=self.__class__.__name__,
3223 decode_path=decode_path,
3224 value=("%d bytes" % len(self._value)) if self.ready else None,
3225 blob=self._value if self.ready else None,
3226 optional=self.optional,
3227 default=self == self.default,
3228 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3229 expl=None if self._expl is None else tag_decode(self._expl),
3234 expl_offset=self.expl_offset if self.expled else None,
3235 expl_tlen=self.expl_tlen if self.expled else None,
3236 expl_llen=self.expl_llen if self.expled else None,
3237 expl_vlen=self.expl_vlen if self.expled else None,
3238 expl_lenindef=self.expl_lenindef,
3239 lenindef=self.lenindef,
3240 ber_encoded=self.ber_encoded,
3243 defined_by, defined = self.defined or (None, None)
3244 if defined_by is not None:
3246 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3248 for pp in self.pps_lenindef(decode_path):
3252 NullState = namedtuple("NullState", (
3264 ), **NAMEDTUPLE_KWARGS)
3268 """``NULL`` null object
3276 tag_default = tag_encode(5)
3277 asn1_type_name = "NULL"
3281 value=None, # unused, but Sequence passes it
3288 :param bytes impl: override default tag with ``IMPLICIT`` one
3289 :param bytes expl: override default tag with ``EXPLICIT`` one
3290 :param bool optional: is object ``OPTIONAL`` in sequence
3292 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3299 def __getstate__(self):
3314 def __setstate__(self, state):
3315 super(Null, self).__setstate__(state)
3316 self.tag = state.tag
3317 self._expl = state.expl
3318 self.default = state.default
3319 self.optional = state.optional
3320 self.offset = state.offset
3321 self.llen = state.llen
3322 self.vlen = state.vlen
3323 self.expl_lenindef = state.expl_lenindef
3324 self.lenindef = state.lenindef
3325 self.ber_encoded = state.ber_encoded
3327 def __eq__(self, their):
3328 if not issubclass(their.__class__, Null):
3331 self.tag == their.tag and
3332 self._expl == their._expl
3342 return self.__class__(
3343 impl=self.tag if impl is None else impl,
3344 expl=self._expl if expl is None else expl,
3345 optional=self.optional if optional is None else optional,
3349 return self.tag + len_encode(0)
3351 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3353 t, _, lv = tag_strip(tlv)
3354 except DecodeError as err:
3355 raise err.__class__(
3357 klass=self.__class__,
3358 decode_path=decode_path,
3363 klass=self.__class__,
3364 decode_path=decode_path,
3367 if tag_only: # pragma: no cover
3370 l, _, v = len_decode(lv)
3371 except DecodeError as err:
3372 raise err.__class__(
3374 klass=self.__class__,
3375 decode_path=decode_path,
3379 raise InvalidLength(
3380 "Null must have zero length",
3381 klass=self.__class__,
3382 decode_path=decode_path,
3385 obj = self.__class__(
3388 optional=self.optional,
3389 _decoded=(offset, 1, 0),
3394 return pp_console_row(next(self.pps()))
3396 def pps(self, decode_path=()):
3399 asn1_type_name=self.asn1_type_name,
3400 obj_name=self.__class__.__name__,
3401 decode_path=decode_path,
3402 optional=self.optional,
3403 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3404 expl=None if self._expl is None else tag_decode(self._expl),
3409 expl_offset=self.expl_offset if self.expled else None,
3410 expl_tlen=self.expl_tlen if self.expled else None,
3411 expl_llen=self.expl_llen if self.expled else None,
3412 expl_vlen=self.expl_vlen if self.expled else None,
3413 expl_lenindef=self.expl_lenindef,
3416 for pp in self.pps_lenindef(decode_path):
3420 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3434 ), **NAMEDTUPLE_KWARGS)
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 their.__class__ == tuple:
3504 return self.__class__(self._value + their)
3505 if isinstance(their, self.__class__):
3506 return self.__class__(self._value + their._value)
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 value.__class__ == 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 their.__class__ == 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)[0] == "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 value.__class__ == text_type:
3896 value_decoded = value
3897 elif value.__class__ == 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 their.__class__ == binary_type:
3922 return self._value == their
3923 if their.__class__ == 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 class VisibleString(CommonString):
4150 tag_default = tag_encode(26)
4152 asn1_type_name = "VisibleString"
4155 UTCTimeState = namedtuple(
4157 OctetStringState._fields + ("ber_raw",),
4162 def str_to_time_fractions(value):
4164 year, v = (v // 10**10), (v % 10**10)
4165 month, v = (v // 10**8), (v % 10**8)
4166 day, v = (v // 10**6), (v % 10**6)
4167 hour, v = (v // 10**4), (v % 10**4)
4168 minute, second = (v // 100), (v % 100)
4169 return year, month, day, hour, minute, second
4172 class UTCTime(VisibleString):
4173 """``UTCTime`` datetime type
4175 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4176 UTCTime UTCTime 2017-09-30T22:07:50
4182 datetime.datetime(2017, 9, 30, 22, 7, 50)
4183 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4184 datetime.datetime(1957, 9, 30, 22, 7, 50)
4186 If BER encoded value was met, then ``ber_raw`` attribute will hold
4187 its raw representation.
4191 Pay attention that UTCTime can not hold full year, so all years
4192 having < 50 years are treated as 20xx, 19xx otherwise, according
4193 to X.509 recommendation.
4197 No strict validation of UTC offsets are made, but very crude:
4199 * minutes are not exceeding 60
4200 * offset value is not exceeding 14 hours
4202 __slots__ = ("ber_raw",)
4203 tag_default = tag_encode(23)
4205 asn1_type_name = "UTCTime"
4215 bounds=None, # dummy argument, workability for OctetString.decode
4219 :param value: set the value. Either datetime type, or
4220 :py:class:`pyderasn.UTCTime` object
4221 :param bytes impl: override default tag with ``IMPLICIT`` one
4222 :param bytes expl: override default tag with ``EXPLICIT`` one
4223 :param default: set default value. Type same as in ``value``
4224 :param bool optional: is object ``OPTIONAL`` in sequence
4226 super(UTCTime, self).__init__(
4227 None, None, impl, expl, None, optional, _decoded, ctx,
4231 if value is not None:
4232 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4233 self.ber_encoded = self.ber_raw is not None
4234 if default is not None:
4235 default, _ = self._value_sanitize(default)
4236 self.default = self.__class__(
4241 if self._value is None:
4242 self._value = default
4244 self.optional = optional
4246 def _strptime_bered(self, value):
4247 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4250 raise ValueError("no timezone")
4251 year += 2000 if year < 50 else 1900
4252 decoded = datetime(year, month, day, hour, minute)
4254 if value[-1] == "Z":
4258 raise ValueError("invalid UTC offset")
4259 if value[-5] == "-":
4261 elif value[-5] == "+":
4264 raise ValueError("invalid UTC offset")
4265 v = pureint(value[-4:])
4266 offset, v = (60 * (v % 100)), v // 100
4268 raise ValueError("invalid UTC offset minutes")
4270 if offset > 14 * 3600:
4271 raise ValueError("too big UTC offset")
4275 return offset, decoded
4277 raise ValueError("invalid UTC offset seconds")
4278 seconds = pureint(value)
4280 raise ValueError("invalid seconds value")
4281 return offset, decoded + timedelta(seconds=seconds)
4283 def _strptime(self, value):
4284 # datetime.strptime's format: %y%m%d%H%M%SZ
4285 if len(value) != LEN_YYMMDDHHMMSSZ:
4286 raise ValueError("invalid UTCTime length")
4287 if value[-1] != "Z":
4288 raise ValueError("non UTC timezone")
4289 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4290 year += 2000 if year < 50 else 1900
4291 return datetime(year, month, day, hour, minute, second)
4293 def _dt_sanitize(self, value):
4294 if value.year < 1950 or value.year > 2049:
4295 raise ValueError("UTCTime can hold only 1950-2049 years")
4296 return value.replace(microsecond=0)
4298 def _value_sanitize(self, value, ctx=None):
4299 if value.__class__ == binary_type:
4301 value_decoded = value.decode("ascii")
4302 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4303 raise DecodeError("invalid UTCTime encoding: %r" % err)
4306 return self._strptime(value_decoded), None
4307 except (TypeError, ValueError) as _err:
4309 if (ctx is not None) and ctx.get("bered", False):
4311 offset, _value = self._strptime_bered(value_decoded)
4312 _value = _value - timedelta(seconds=offset)
4313 return self._dt_sanitize(_value), value
4314 except (TypeError, ValueError, OverflowError) as _err:
4317 "invalid %s format: %r" % (self.asn1_type_name, err),
4318 klass=self.__class__,
4320 if isinstance(value, self.__class__):
4321 return value._value, None
4322 if value.__class__ == datetime:
4323 return self._dt_sanitize(value), None
4324 raise InvalidValueType((self.__class__, datetime))
4326 def _pp_value(self):
4328 value = self._value.isoformat()
4329 if self.ber_encoded:
4330 value += " (%s)" % self.ber_raw
4333 def __unicode__(self):
4335 value = self._value.isoformat()
4336 if self.ber_encoded:
4337 value += " (%s)" % self.ber_raw
4339 return text_type(self._pp_value())
4341 def __getstate__(self):
4342 return UTCTimeState(
4343 *super(UTCTime, self).__getstate__(),
4344 **{"ber_raw": self.ber_raw}
4347 def __setstate__(self, state):
4348 super(UTCTime, self).__setstate__(state)
4349 self.ber_raw = state.ber_raw
4351 def __bytes__(self):
4352 self._assert_ready()
4353 return self._encode_time()
4355 def __eq__(self, their):
4356 if their.__class__ == binary_type:
4357 return self._encode_time() == their
4358 if their.__class__ == datetime:
4359 return self.todatetime() == their
4360 if not isinstance(their, self.__class__):
4363 self._value == their._value and
4364 self.tag == their.tag and
4365 self._expl == their._expl
4368 def _encode_time(self):
4369 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4372 self._assert_ready()
4373 value = self._encode_time()
4374 return b"".join((self.tag, len_encode(len(value)), value))
4376 def todatetime(self):
4380 return pp_console_row(next(self.pps()))
4382 def pps(self, decode_path=()):
4385 asn1_type_name=self.asn1_type_name,
4386 obj_name=self.__class__.__name__,
4387 decode_path=decode_path,
4388 value=self._pp_value(),
4389 optional=self.optional,
4390 default=self == self.default,
4391 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4392 expl=None if self._expl is None else tag_decode(self._expl),
4397 expl_offset=self.expl_offset if self.expled else None,
4398 expl_tlen=self.expl_tlen if self.expled else None,
4399 expl_llen=self.expl_llen if self.expled else None,
4400 expl_vlen=self.expl_vlen if self.expled else None,
4401 expl_lenindef=self.expl_lenindef,
4402 ber_encoded=self.ber_encoded,
4405 for pp in self.pps_lenindef(decode_path):
4409 class GeneralizedTime(UTCTime):
4410 """``GeneralizedTime`` datetime type
4412 This type is similar to :py:class:`pyderasn.UTCTime`.
4414 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4415 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4417 '20170930220750.000123Z'
4418 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4419 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4423 Only microsecond fractions are supported in DER encoding.
4424 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4425 higher precision values.
4429 BER encoded data can loss information (accuracy) during decoding
4430 because of float transformations.
4434 Local times (without explicit timezone specification) are treated
4435 as UTC one, no transformations are made.
4439 Zero year is unsupported.
4442 tag_default = tag_encode(24)
4443 asn1_type_name = "GeneralizedTime"
4445 def _dt_sanitize(self, value):
4448 def _strptime_bered(self, value):
4449 if len(value) < 4 + 3 * 2:
4450 raise ValueError("invalid GeneralizedTime")
4451 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4452 decoded = datetime(year, month, day, hour)
4453 offset, value = 0, value[10:]
4455 return offset, decoded
4456 if value[-1] == "Z":
4459 for char, sign in (("-", -1), ("+", 1)):
4460 idx = value.rfind(char)
4463 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4464 v = pureint(offset_raw)
4465 if len(offset_raw) == 4:
4466 offset, v = (60 * (v % 100)), v // 100
4468 raise ValueError("invalid UTC offset minutes")
4469 elif len(offset_raw) == 2:
4472 raise ValueError("invalid UTC offset")
4474 if offset > 14 * 3600:
4475 raise ValueError("too big UTC offset")
4479 return offset, decoded
4480 if value[0] in DECIMAL_SIGNS:
4482 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4485 raise ValueError("stripped minutes")
4486 decoded += timedelta(seconds=60 * pureint(value[:2]))
4489 return offset, decoded
4490 if value[0] in DECIMAL_SIGNS:
4492 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4495 raise ValueError("stripped seconds")
4496 decoded += timedelta(seconds=pureint(value[:2]))
4499 return offset, decoded
4500 if value[0] not in DECIMAL_SIGNS:
4501 raise ValueError("invalid format after seconds")
4503 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4506 def _strptime(self, value):
4508 if l == LEN_YYYYMMDDHHMMSSZ:
4509 # datetime.strptime's format: %Y%m%d%H%M%SZ
4510 if value[-1] != "Z":
4511 raise ValueError("non UTC timezone")
4512 return datetime(*str_to_time_fractions(value[:-1]))
4513 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4514 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4515 if value[-1] != "Z":
4516 raise ValueError("non UTC timezone")
4517 if value[14] != ".":
4518 raise ValueError("no fractions separator")
4521 raise ValueError("trailing zero")
4524 raise ValueError("only microsecond fractions are supported")
4525 us = pureint(us + ("0" * (6 - us_len)))
4526 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4527 return datetime(year, month, day, hour, minute, second, us)
4528 raise ValueError("invalid GeneralizedTime length")
4530 def _encode_time(self):
4532 encoded = value.strftime("%Y%m%d%H%M%S")
4533 if value.microsecond > 0:
4534 encoded += (".%06d" % value.microsecond).rstrip("0")
4535 return (encoded + "Z").encode("ascii")
4538 class GraphicString(CommonString):
4540 tag_default = tag_encode(25)
4541 encoding = "iso-8859-1"
4542 asn1_type_name = "GraphicString"
4545 class ISO646String(VisibleString):
4547 asn1_type_name = "ISO646String"
4550 class GeneralString(CommonString):
4552 tag_default = tag_encode(27)
4553 encoding = "iso-8859-1"
4554 asn1_type_name = "GeneralString"
4557 class UniversalString(CommonString):
4559 tag_default = tag_encode(28)
4560 encoding = "utf-32-be"
4561 asn1_type_name = "UniversalString"
4564 class BMPString(CommonString):
4566 tag_default = tag_encode(30)
4567 encoding = "utf-16-be"
4568 asn1_type_name = "BMPString"
4571 ChoiceState = namedtuple("ChoiceState", (
4585 ), **NAMEDTUPLE_KWARGS)
4589 """``CHOICE`` special type
4593 class GeneralName(Choice):
4595 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4596 ("dNSName", IA5String(impl=tag_ctxp(2))),
4599 >>> gn = GeneralName()
4601 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4602 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4603 >>> gn["dNSName"] = IA5String("bar.baz")
4604 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4605 >>> gn["rfc822Name"]
4608 [2] IA5String IA5 bar.baz
4611 >>> gn.value == gn["dNSName"]
4614 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4616 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4617 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4619 __slots__ = ("specs",)
4621 asn1_type_name = "CHOICE"
4634 :param value: set the value. Either ``(choice, value)`` tuple, or
4635 :py:class:`pyderasn.Choice` object
4636 :param bytes impl: can not be set, do **not** use it
4637 :param bytes expl: override default tag with ``EXPLICIT`` one
4638 :param default: set default value. Type same as in ``value``
4639 :param bool optional: is object ``OPTIONAL`` in sequence
4641 if impl is not None:
4642 raise ValueError("no implicit tag allowed for CHOICE")
4643 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4645 schema = getattr(self, "schema", ())
4646 if len(schema) == 0:
4647 raise ValueError("schema must be specified")
4649 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4652 if value is not None:
4653 self._value = self._value_sanitize(value)
4654 if default is not None:
4655 default_value = self._value_sanitize(default)
4656 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4657 default_obj.specs = self.specs
4658 default_obj._value = default_value
4659 self.default = default_obj
4661 self._value = copy(default_obj._value)
4663 def _value_sanitize(self, value):
4664 if (value.__class__ == tuple) and len(value) == 2:
4666 spec = self.specs.get(choice)
4668 raise ObjUnknown(choice)
4669 if not isinstance(obj, spec.__class__):
4670 raise InvalidValueType((spec,))
4671 return (choice, spec(obj))
4672 if isinstance(value, self.__class__):
4674 raise InvalidValueType((self.__class__, tuple))
4678 return self._value is not None and self._value[1].ready
4682 return self.expl_lenindef or (
4683 (self._value is not None) and
4684 self._value[1].bered
4687 def __getstate__(self):
4704 def __setstate__(self, state):
4705 super(Choice, self).__setstate__(state)
4706 self.specs = state.specs
4707 self._value = state.value
4708 self._expl = state.expl
4709 self.default = state.default
4710 self.optional = state.optional
4711 self.offset = state.offset
4712 self.llen = state.llen
4713 self.vlen = state.vlen
4714 self.expl_lenindef = state.expl_lenindef
4715 self.lenindef = state.lenindef
4716 self.ber_encoded = state.ber_encoded
4718 def __eq__(self, their):
4719 if (their.__class__ == tuple) and len(their) == 2:
4720 return self._value == their
4721 if not isinstance(their, self.__class__):
4724 self.specs == their.specs and
4725 self._value == their._value
4735 return self.__class__(
4738 expl=self._expl if expl is None else expl,
4739 default=self.default if default is None else default,
4740 optional=self.optional if optional is None else optional,
4745 self._assert_ready()
4746 return self._value[0]
4750 self._assert_ready()
4751 return self._value[1]
4753 def __getitem__(self, key):
4754 if key not in self.specs:
4755 raise ObjUnknown(key)
4756 if self._value is None:
4758 choice, value = self._value
4763 def __setitem__(self, key, value):
4764 spec = self.specs.get(key)
4766 raise ObjUnknown(key)
4767 if not isinstance(value, spec.__class__):
4768 raise InvalidValueType((spec.__class__,))
4769 self._value = (key, spec(value))
4777 return self._value[1].decoded if self.ready else False
4780 self._assert_ready()
4781 return self._value[1].encode()
4783 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4784 for choice, spec in iteritems(self.specs):
4785 sub_decode_path = decode_path + (choice,)
4791 decode_path=sub_decode_path,
4794 _ctx_immutable=False,
4801 klass=self.__class__,
4802 decode_path=decode_path,
4805 if tag_only: # pragma: no cover
4807 value, tail = spec.decode(
4811 decode_path=sub_decode_path,
4813 _ctx_immutable=False,
4815 obj = self.__class__(
4818 default=self.default,
4819 optional=self.optional,
4820 _decoded=(offset, 0, value.fulllen),
4822 obj._value = (choice, value)
4826 value = pp_console_row(next(self.pps()))
4828 value = "%s[%r]" % (value, self.value)
4831 def pps(self, decode_path=()):
4834 asn1_type_name=self.asn1_type_name,
4835 obj_name=self.__class__.__name__,
4836 decode_path=decode_path,
4837 value=self.choice if self.ready else None,
4838 optional=self.optional,
4839 default=self == self.default,
4840 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4841 expl=None if self._expl is None else tag_decode(self._expl),
4846 expl_lenindef=self.expl_lenindef,
4850 yield self.value.pps(decode_path=decode_path + (self.choice,))
4851 for pp in self.pps_lenindef(decode_path):
4855 class PrimitiveTypes(Choice):
4856 """Predefined ``CHOICE`` for all generic primitive types
4858 It could be useful for general decoding of some unspecified values:
4860 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4861 OCTET STRING 3 bytes 666f6f
4862 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4866 schema = tuple((klass.__name__, klass()) for klass in (
4890 AnyState = namedtuple("AnyState", (
4903 ), **NAMEDTUPLE_KWARGS)
4907 """``ANY`` special type
4909 >>> Any(Integer(-123))
4911 >>> a = Any(OctetString(b"hello world").encode())
4912 ANY 040b68656c6c6f20776f726c64
4913 >>> hexenc(bytes(a))
4914 b'0x040x0bhello world'
4916 __slots__ = ("defined",)
4917 tag_default = tag_encode(0)
4918 asn1_type_name = "ANY"
4928 :param value: set the value. Either any kind of pyderasn's
4929 **ready** object, or bytes. Pay attention that
4930 **no** validation is performed is raw binary value
4932 :param bytes expl: override default tag with ``EXPLICIT`` one
4933 :param bool optional: is object ``OPTIONAL`` in sequence
4935 super(Any, self).__init__(None, expl, None, optional, _decoded)
4936 self._value = None if value is None else self._value_sanitize(value)
4939 def _value_sanitize(self, value):
4940 if value.__class__ == binary_type:
4942 if isinstance(value, self.__class__):
4944 if isinstance(value, Obj):
4945 return value.encode()
4946 raise InvalidValueType((self.__class__, Obj, binary_type))
4950 return self._value is not None
4954 if self.expl_lenindef or self.lenindef:
4956 if self.defined is None:
4958 return self.defined[1].bered
4960 def __getstate__(self):
4976 def __setstate__(self, state):
4977 super(Any, self).__setstate__(state)
4978 self._value = state.value
4979 self.tag = state.tag
4980 self._expl = state.expl
4981 self.optional = state.optional
4982 self.offset = state.offset
4983 self.llen = state.llen
4984 self.vlen = state.vlen
4985 self.expl_lenindef = state.expl_lenindef
4986 self.lenindef = state.lenindef
4987 self.ber_encoded = state.ber_encoded
4988 self.defined = state.defined
4990 def __eq__(self, their):
4991 if their.__class__ == binary_type:
4992 return self._value == their
4993 if issubclass(their.__class__, Any):
4994 return self._value == their._value
5003 return self.__class__(
5005 expl=self._expl if expl is None else expl,
5006 optional=self.optional if optional is None else optional,
5009 def __bytes__(self):
5010 self._assert_ready()
5018 self._assert_ready()
5021 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5023 t, tlen, lv = tag_strip(tlv)
5024 except DecodeError as err:
5025 raise err.__class__(
5027 klass=self.__class__,
5028 decode_path=decode_path,
5032 l, llen, v = len_decode(lv)
5033 except LenIndefForm as err:
5034 if not ctx.get("bered", False):
5035 raise err.__class__(
5037 klass=self.__class__,
5038 decode_path=decode_path,
5041 llen, vlen, v = 1, 0, lv[1:]
5042 sub_offset = offset + tlen + llen
5044 while v[:EOC_LEN].tobytes() != EOC:
5045 chunk, v = Any().decode(
5048 decode_path=decode_path + (str(chunk_i),),
5051 _ctx_immutable=False,
5053 vlen += chunk.tlvlen
5054 sub_offset += chunk.tlvlen
5056 tlvlen = tlen + llen + vlen + EOC_LEN
5057 obj = self.__class__(
5058 value=tlv[:tlvlen].tobytes(),
5060 optional=self.optional,
5061 _decoded=(offset, 0, tlvlen),
5064 obj.tag = t.tobytes()
5065 return obj, v[EOC_LEN:]
5066 except DecodeError as err:
5067 raise err.__class__(
5069 klass=self.__class__,
5070 decode_path=decode_path,
5074 raise NotEnoughData(
5075 "encoded length is longer than data",
5076 klass=self.__class__,
5077 decode_path=decode_path,
5080 tlvlen = tlen + llen + l
5081 v, tail = tlv[:tlvlen], v[l:]
5082 obj = self.__class__(
5085 optional=self.optional,
5086 _decoded=(offset, 0, tlvlen),
5088 obj.tag = t.tobytes()
5092 return pp_console_row(next(self.pps()))
5094 def pps(self, decode_path=()):
5097 asn1_type_name=self.asn1_type_name,
5098 obj_name=self.__class__.__name__,
5099 decode_path=decode_path,
5100 blob=self._value if self.ready else None,
5101 optional=self.optional,
5102 default=self == self.default,
5103 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5104 expl=None if self._expl is None else tag_decode(self._expl),
5109 expl_offset=self.expl_offset if self.expled else None,
5110 expl_tlen=self.expl_tlen if self.expled else None,
5111 expl_llen=self.expl_llen if self.expled else None,
5112 expl_vlen=self.expl_vlen if self.expled else None,
5113 expl_lenindef=self.expl_lenindef,
5114 lenindef=self.lenindef,
5117 defined_by, defined = self.defined or (None, None)
5118 if defined_by is not None:
5120 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5122 for pp in self.pps_lenindef(decode_path):
5126 ########################################################################
5127 # ASN.1 constructed types
5128 ########################################################################
5130 def get_def_by_path(defines_by_path, sub_decode_path):
5131 """Get define by decode path
5133 for path, define in defines_by_path:
5134 if len(path) != len(sub_decode_path):
5136 for p1, p2 in zip(path, sub_decode_path):
5137 if (not p1 is any) and (p1 != p2):
5143 def abs_decode_path(decode_path, rel_path):
5144 """Create an absolute decode path from current and relative ones
5146 :param decode_path: current decode path, starting point. Tuple of strings
5147 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5148 If first tuple's element is "/", then treat it as
5149 an absolute path, ignoring ``decode_path`` as
5150 starting point. Also this tuple can contain ".."
5151 elements, stripping the leading element from
5154 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5155 ("foo", "bar", "baz", "whatever")
5156 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5158 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5161 if rel_path[0] == "/":
5163 if rel_path[0] == "..":
5164 return abs_decode_path(decode_path[:-1], rel_path[1:])
5165 return decode_path + rel_path
5168 SequenceState = namedtuple("SequenceState", (
5182 ), **NAMEDTUPLE_KWARGS)
5185 class Sequence(Obj):
5186 """``SEQUENCE`` structure type
5188 You have to make specification of sequence::
5190 class Extension(Sequence):
5192 ("extnID", ObjectIdentifier()),
5193 ("critical", Boolean(default=False)),
5194 ("extnValue", OctetString()),
5197 Then, you can work with it as with dictionary.
5199 >>> ext = Extension()
5200 >>> Extension().specs
5202 ('extnID', OBJECT IDENTIFIER),
5203 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5204 ('extnValue', OCTET STRING),
5206 >>> ext["extnID"] = "1.2.3"
5207 Traceback (most recent call last):
5208 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5209 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5211 You can determine if sequence is ready to be encoded:
5216 Traceback (most recent call last):
5217 pyderasn.ObjNotReady: object is not ready: extnValue
5218 >>> ext["extnValue"] = OctetString(b"foobar")
5222 Value you want to assign, must have the same **type** as in
5223 corresponding specification, but it can have different tags,
5224 optional/default attributes -- they will be taken from specification
5227 class TBSCertificate(Sequence):
5229 ("version", Version(expl=tag_ctxc(0), default="v1")),
5232 >>> tbs = TBSCertificate()
5233 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5235 Assign ``None`` to remove value from sequence.
5237 You can set values in Sequence during its initialization:
5239 >>> AlgorithmIdentifier((
5240 ("algorithm", ObjectIdentifier("1.2.3")),
5241 ("parameters", Any(Null()))
5243 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5245 You can determine if value exists/set in the sequence and take its value:
5247 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5250 OBJECT IDENTIFIER 1.2.3
5252 But pay attention that if value has default, then it won't be (not
5253 in) in the sequence (because ``DEFAULT`` must not be encoded in
5254 DER), but you can read its value:
5256 >>> "critical" in ext, ext["critical"]
5257 (False, BOOLEAN False)
5258 >>> ext["critical"] = Boolean(True)
5259 >>> "critical" in ext, ext["critical"]
5260 (True, BOOLEAN True)
5262 All defaulted values are always optional.
5264 .. _allow_default_values_ctx:
5266 DER prohibits default value encoding and will raise an error if
5267 default value is unexpectedly met during decode.
5268 If :ref:`bered <bered_ctx>` context option is set, then no error
5269 will be raised, but ``bered`` attribute set. You can disable strict
5270 defaulted values existence validation by setting
5271 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5273 Two sequences are equal if they have equal specification (schema),
5274 implicit/explicit tagging and the same values.
5276 __slots__ = ("specs",)
5277 tag_default = tag_encode(form=TagFormConstructed, num=16)
5278 asn1_type_name = "SEQUENCE"
5290 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5292 schema = getattr(self, "schema", ())
5294 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5297 if value is not None:
5298 if issubclass(value.__class__, Sequence):
5299 self._value = value._value
5300 elif hasattr(value, "__iter__"):
5301 for seq_key, seq_value in value:
5302 self[seq_key] = seq_value
5304 raise InvalidValueType((Sequence,))
5305 if default is not None:
5306 if not issubclass(default.__class__, Sequence):
5307 raise InvalidValueType((Sequence,))
5308 default_value = default._value
5309 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5310 default_obj.specs = self.specs
5311 default_obj._value = default_value
5312 self.default = default_obj
5314 self._value = copy(default_obj._value)
5318 for name, spec in iteritems(self.specs):
5319 value = self._value.get(name)
5330 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5332 return any(value.bered for value in itervalues(self._value))
5334 def __getstate__(self):
5335 return SequenceState(
5338 {k: copy(v) for k, v in iteritems(self._value)},
5351 def __setstate__(self, state):
5352 super(Sequence, self).__setstate__(state)
5353 self.specs = state.specs
5354 self._value = state.value
5355 self.tag = state.tag
5356 self._expl = state.expl
5357 self.default = state.default
5358 self.optional = state.optional
5359 self.offset = state.offset
5360 self.llen = state.llen
5361 self.vlen = state.vlen
5362 self.expl_lenindef = state.expl_lenindef
5363 self.lenindef = state.lenindef
5364 self.ber_encoded = state.ber_encoded
5366 def __eq__(self, their):
5367 if not isinstance(their, self.__class__):
5370 self.specs == their.specs and
5371 self.tag == their.tag and
5372 self._expl == their._expl and
5373 self._value == their._value
5384 return self.__class__(
5387 impl=self.tag if impl is None else impl,
5388 expl=self._expl if expl is None else expl,
5389 default=self.default if default is None else default,
5390 optional=self.optional if optional is None else optional,
5393 def __contains__(self, key):
5394 return key in self._value
5396 def __setitem__(self, key, value):
5397 spec = self.specs.get(key)
5399 raise ObjUnknown(key)
5401 self._value.pop(key, None)
5403 if not isinstance(value, spec.__class__):
5404 raise InvalidValueType((spec.__class__,))
5405 value = spec(value=value)
5406 if spec.default is not None and value == spec.default:
5407 self._value.pop(key, None)
5409 self._value[key] = value
5411 def __getitem__(self, key):
5412 value = self._value.get(key)
5413 if value is not None:
5415 spec = self.specs.get(key)
5417 raise ObjUnknown(key)
5418 if spec.default is not None:
5422 def _values_for_encoding(self):
5423 for name, spec in iteritems(self.specs):
5424 value = self._value.get(name)
5428 raise ObjNotReady(name)
5432 v = b"".join(v.encode() for v in self._values_for_encoding())
5433 return b"".join((self.tag, len_encode(len(v)), v))
5435 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5437 t, tlen, lv = tag_strip(tlv)
5438 except DecodeError as err:
5439 raise err.__class__(
5441 klass=self.__class__,
5442 decode_path=decode_path,
5447 klass=self.__class__,
5448 decode_path=decode_path,
5451 if tag_only: # pragma: no cover
5454 ctx_bered = ctx.get("bered", False)
5456 l, llen, v = len_decode(lv)
5457 except LenIndefForm as err:
5459 raise err.__class__(
5461 klass=self.__class__,
5462 decode_path=decode_path,
5465 l, llen, v = 0, 1, lv[1:]
5467 except DecodeError as err:
5468 raise err.__class__(
5470 klass=self.__class__,
5471 decode_path=decode_path,
5475 raise NotEnoughData(
5476 "encoded length is longer than data",
5477 klass=self.__class__,
5478 decode_path=decode_path,
5482 v, tail = v[:l], v[l:]
5484 sub_offset = offset + tlen + llen
5487 ctx_allow_default_values = ctx.get("allow_default_values", False)
5488 for name, spec in iteritems(self.specs):
5489 if spec.optional and (
5490 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5494 sub_decode_path = decode_path + (name,)
5496 value, v_tail = spec.decode(
5500 decode_path=sub_decode_path,
5502 _ctx_immutable=False,
5504 except TagMismatch as err:
5505 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5509 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5510 if defined is not None:
5511 defined_by, defined_spec = defined
5512 if issubclass(value.__class__, SequenceOf):
5513 for i, _value in enumerate(value):
5514 sub_sub_decode_path = sub_decode_path + (
5516 DecodePathDefBy(defined_by),
5518 defined_value, defined_tail = defined_spec.decode(
5519 memoryview(bytes(_value)),
5521 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5522 if value.expled else (value.tlen + value.llen)
5525 decode_path=sub_sub_decode_path,
5527 _ctx_immutable=False,
5529 if len(defined_tail) > 0:
5532 klass=self.__class__,
5533 decode_path=sub_sub_decode_path,
5536 _value.defined = (defined_by, defined_value)
5538 defined_value, defined_tail = defined_spec.decode(
5539 memoryview(bytes(value)),
5541 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5542 if value.expled else (value.tlen + value.llen)
5545 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5547 _ctx_immutable=False,
5549 if len(defined_tail) > 0:
5552 klass=self.__class__,
5553 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5556 value.defined = (defined_by, defined_value)
5558 value_len = value.fulllen
5560 sub_offset += value_len
5562 if spec.default is not None and value == spec.default:
5563 if ctx_bered or ctx_allow_default_values:
5567 "DEFAULT value met",
5568 klass=self.__class__,
5569 decode_path=sub_decode_path,
5572 values[name] = value
5574 spec_defines = getattr(spec, "defines", ())
5575 if len(spec_defines) == 0:
5576 defines_by_path = ctx.get("defines_by_path", ())
5577 if len(defines_by_path) > 0:
5578 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5579 if spec_defines is not None and len(spec_defines) > 0:
5580 for rel_path, schema in spec_defines:
5581 defined = schema.get(value, None)
5582 if defined is not None:
5583 ctx.setdefault("_defines", []).append((
5584 abs_decode_path(sub_decode_path[:-1], rel_path),
5588 if v[:EOC_LEN].tobytes() != EOC:
5591 klass=self.__class__,
5592 decode_path=decode_path,
5600 klass=self.__class__,
5601 decode_path=decode_path,
5604 obj = self.__class__(
5608 default=self.default,
5609 optional=self.optional,
5610 _decoded=(offset, llen, vlen),
5613 obj.lenindef = lenindef
5614 obj.ber_encoded = ber_encoded
5618 value = pp_console_row(next(self.pps()))
5620 for name in self.specs:
5621 _value = self._value.get(name)
5624 cols.append("%s: %s" % (name, repr(_value)))
5625 return "%s[%s]" % (value, "; ".join(cols))
5627 def pps(self, decode_path=()):
5630 asn1_type_name=self.asn1_type_name,
5631 obj_name=self.__class__.__name__,
5632 decode_path=decode_path,
5633 optional=self.optional,
5634 default=self == self.default,
5635 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5636 expl=None if self._expl is None else tag_decode(self._expl),
5641 expl_offset=self.expl_offset if self.expled else None,
5642 expl_tlen=self.expl_tlen if self.expled else None,
5643 expl_llen=self.expl_llen if self.expled else None,
5644 expl_vlen=self.expl_vlen if self.expled else None,
5645 expl_lenindef=self.expl_lenindef,
5646 lenindef=self.lenindef,
5647 ber_encoded=self.ber_encoded,
5650 for name in self.specs:
5651 value = self._value.get(name)
5654 yield value.pps(decode_path=decode_path + (name,))
5655 for pp in self.pps_lenindef(decode_path):
5659 class Set(Sequence):
5660 """``SET`` structure type
5662 Its usage is identical to :py:class:`pyderasn.Sequence`.
5664 .. _allow_unordered_set_ctx:
5666 DER prohibits unordered values encoding and will raise an error
5667 during decode. If :ref:`bered <bered_ctx>` context option is set,
5668 then no error will occur. Also you can disable strict values
5669 ordering check by setting ``"allow_unordered_set": True``
5670 :ref:`context <ctx>` option.
5673 tag_default = tag_encode(form=TagFormConstructed, num=17)
5674 asn1_type_name = "SET"
5677 raws = [v.encode() for v in self._values_for_encoding()]
5680 return b"".join((self.tag, len_encode(len(v)), v))
5682 def _specs_items(self):
5683 return iteritems(self.specs)
5685 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5687 t, tlen, lv = tag_strip(tlv)
5688 except DecodeError as err:
5689 raise err.__class__(
5691 klass=self.__class__,
5692 decode_path=decode_path,
5697 klass=self.__class__,
5698 decode_path=decode_path,
5704 ctx_bered = ctx.get("bered", False)
5706 l, llen, v = len_decode(lv)
5707 except LenIndefForm as err:
5709 raise err.__class__(
5711 klass=self.__class__,
5712 decode_path=decode_path,
5715 l, llen, v = 0, 1, lv[1:]
5717 except DecodeError as err:
5718 raise err.__class__(
5720 klass=self.__class__,
5721 decode_path=decode_path,
5725 raise NotEnoughData(
5726 "encoded length is longer than data",
5727 klass=self.__class__,
5731 v, tail = v[:l], v[l:]
5733 sub_offset = offset + tlen + llen
5736 ctx_allow_default_values = ctx.get("allow_default_values", False)
5737 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5738 value_prev = memoryview(v[:0])
5741 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5743 for name, spec in self._specs_items():
5744 sub_decode_path = decode_path + (name,)
5750 decode_path=sub_decode_path,
5753 _ctx_immutable=False,
5760 klass=self.__class__,
5761 decode_path=decode_path,
5764 value, v_tail = spec.decode(
5768 decode_path=sub_decode_path,
5770 _ctx_immutable=False,
5772 value_len = value.fulllen
5773 if value_prev.tobytes() > v[:value_len].tobytes():
5774 if ctx_bered or ctx_allow_unordered_set:
5778 "unordered " + self.asn1_type_name,
5779 klass=self.__class__,
5780 decode_path=sub_decode_path,
5783 if spec.default is None or value != spec.default:
5785 elif ctx_bered or ctx_allow_default_values:
5789 "DEFAULT value met",
5790 klass=self.__class__,
5791 decode_path=sub_decode_path,
5794 values[name] = value
5795 value_prev = v[:value_len]
5796 sub_offset += value_len
5799 obj = self.__class__(
5803 default=self.default,
5804 optional=self.optional,
5805 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5808 if v[:EOC_LEN].tobytes() != EOC:
5811 klass=self.__class__,
5812 decode_path=decode_path,
5818 for name, spec in iteritems(self.specs):
5819 if name not in values and not spec.optional:
5821 "%s value is not ready" % name,
5822 klass=self.__class__,
5823 decode_path=decode_path,
5826 obj.ber_encoded = ber_encoded
5830 SequenceOfState = namedtuple("SequenceOfState", (
5846 ), **NAMEDTUPLE_KWARGS)
5849 class SequenceOf(Obj):
5850 """``SEQUENCE OF`` sequence type
5852 For that kind of type you must specify the object it will carry on
5853 (bounds are for example here, not required)::
5855 class Ints(SequenceOf):
5860 >>> ints.append(Integer(123))
5861 >>> ints.append(Integer(234))
5863 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5864 >>> [int(i) for i in ints]
5866 >>> ints.append(Integer(345))
5867 Traceback (most recent call last):
5868 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5871 >>> ints[1] = Integer(345)
5873 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5875 Also you can initialize sequence with preinitialized values:
5877 >>> ints = Ints([Integer(123), Integer(234)])
5879 __slots__ = ("spec", "_bound_min", "_bound_max")
5880 tag_default = tag_encode(form=TagFormConstructed, num=16)
5881 asn1_type_name = "SEQUENCE OF"
5894 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5896 schema = getattr(self, "schema", None)
5898 raise ValueError("schema must be specified")
5900 self._bound_min, self._bound_max = getattr(
5904 ) if bounds is None else bounds
5906 if value is not None:
5907 self._value = self._value_sanitize(value)
5908 if default is not None:
5909 default_value = self._value_sanitize(default)
5910 default_obj = self.__class__(
5915 default_obj._value = default_value
5916 self.default = default_obj
5918 self._value = copy(default_obj._value)
5920 def _value_sanitize(self, value):
5921 if issubclass(value.__class__, SequenceOf):
5922 value = value._value
5923 elif hasattr(value, "__iter__"):
5926 raise InvalidValueType((self.__class__, iter))
5927 if not self._bound_min <= len(value) <= self._bound_max:
5928 raise BoundsError(self._bound_min, len(value), self._bound_max)
5930 if not isinstance(v, self.spec.__class__):
5931 raise InvalidValueType((self.spec.__class__,))
5936 return all(v.ready for v in self._value)
5940 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5942 return any(v.bered for v in self._value)
5944 def __getstate__(self):
5945 return SequenceOfState(
5948 [copy(v) for v in self._value],
5963 def __setstate__(self, state):
5964 super(SequenceOf, self).__setstate__(state)
5965 self.spec = state.spec
5966 self._value = state.value
5967 self._bound_min = state.bound_min
5968 self._bound_max = state.bound_max
5969 self.tag = state.tag
5970 self._expl = state.expl
5971 self.default = state.default
5972 self.optional = state.optional
5973 self.offset = state.offset
5974 self.llen = state.llen
5975 self.vlen = state.vlen
5976 self.expl_lenindef = state.expl_lenindef
5977 self.lenindef = state.lenindef
5978 self.ber_encoded = state.ber_encoded
5980 def __eq__(self, their):
5981 if isinstance(their, self.__class__):
5983 self.spec == their.spec and
5984 self.tag == their.tag and
5985 self._expl == their._expl and
5986 self._value == their._value
5988 if hasattr(their, "__iter__"):
5989 return self._value == list(their)
6001 return self.__class__(
6005 (self._bound_min, self._bound_max)
6006 if bounds is None else bounds
6008 impl=self.tag if impl is None else impl,
6009 expl=self._expl if expl is None else expl,
6010 default=self.default if default is None else default,
6011 optional=self.optional if optional is None else optional,
6014 def __contains__(self, key):
6015 return key in self._value
6017 def append(self, value):
6018 if not isinstance(value, self.spec.__class__):
6019 raise InvalidValueType((self.spec.__class__,))
6020 if len(self._value) + 1 > self._bound_max:
6023 len(self._value) + 1,
6026 self._value.append(value)
6029 self._assert_ready()
6030 return iter(self._value)
6033 self._assert_ready()
6034 return len(self._value)
6036 def __setitem__(self, key, value):
6037 if not isinstance(value, self.spec.__class__):
6038 raise InvalidValueType((self.spec.__class__,))
6039 self._value[key] = self.spec(value=value)
6041 def __getitem__(self, key):
6042 return self._value[key]
6044 def _values_for_encoding(self):
6045 return iter(self._value)
6048 v = b"".join(v.encode() for v in self._values_for_encoding())
6049 return b"".join((self.tag, len_encode(len(v)), v))
6051 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6053 t, tlen, lv = tag_strip(tlv)
6054 except DecodeError as err:
6055 raise err.__class__(
6057 klass=self.__class__,
6058 decode_path=decode_path,
6063 klass=self.__class__,
6064 decode_path=decode_path,
6070 ctx_bered = ctx.get("bered", False)
6072 l, llen, v = len_decode(lv)
6073 except LenIndefForm as err:
6075 raise err.__class__(
6077 klass=self.__class__,
6078 decode_path=decode_path,
6081 l, llen, v = 0, 1, lv[1:]
6083 except DecodeError as err:
6084 raise err.__class__(
6086 klass=self.__class__,
6087 decode_path=decode_path,
6091 raise NotEnoughData(
6092 "encoded length is longer than data",
6093 klass=self.__class__,
6094 decode_path=decode_path,
6098 v, tail = v[:l], v[l:]
6100 sub_offset = offset + tlen + llen
6102 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6103 value_prev = memoryview(v[:0])
6107 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6109 sub_decode_path = decode_path + (str(len(_value)),)
6110 value, v_tail = spec.decode(
6114 decode_path=sub_decode_path,
6116 _ctx_immutable=False,
6118 value_len = value.fulllen
6120 if value_prev.tobytes() > v[:value_len].tobytes():
6121 if ctx_bered or ctx_allow_unordered_set:
6125 "unordered " + self.asn1_type_name,
6126 klass=self.__class__,
6127 decode_path=sub_decode_path,
6130 value_prev = v[:value_len]
6131 _value.append(value)
6132 sub_offset += value_len
6136 obj = self.__class__(
6139 bounds=(self._bound_min, self._bound_max),
6142 default=self.default,
6143 optional=self.optional,
6144 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6146 except BoundsError as err:
6149 klass=self.__class__,
6150 decode_path=decode_path,
6154 if v[:EOC_LEN].tobytes() != EOC:
6157 klass=self.__class__,
6158 decode_path=decode_path,
6163 obj.ber_encoded = ber_encoded
6168 pp_console_row(next(self.pps())),
6169 ", ".join(repr(v) for v in self._value),
6172 def pps(self, decode_path=()):
6175 asn1_type_name=self.asn1_type_name,
6176 obj_name=self.__class__.__name__,
6177 decode_path=decode_path,
6178 optional=self.optional,
6179 default=self == self.default,
6180 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6181 expl=None if self._expl is None else tag_decode(self._expl),
6186 expl_offset=self.expl_offset if self.expled else None,
6187 expl_tlen=self.expl_tlen if self.expled else None,
6188 expl_llen=self.expl_llen if self.expled else None,
6189 expl_vlen=self.expl_vlen if self.expled else None,
6190 expl_lenindef=self.expl_lenindef,
6191 lenindef=self.lenindef,
6192 ber_encoded=self.ber_encoded,
6195 for i, value in enumerate(self._value):
6196 yield value.pps(decode_path=decode_path + (str(i),))
6197 for pp in self.pps_lenindef(decode_path):
6201 class SetOf(SequenceOf):
6202 """``SET OF`` sequence type
6204 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6207 tag_default = tag_encode(form=TagFormConstructed, num=17)
6208 asn1_type_name = "SET OF"
6211 raws = [v.encode() for v in self._values_for_encoding()]
6214 return b"".join((self.tag, len_encode(len(v)), v))
6216 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6217 return super(SetOf, self)._decode(
6223 ordering_check=True,
6227 def obj_by_path(pypath): # pragma: no cover
6228 """Import object specified as string Python path
6230 Modules must be separated from classes/functions with ``:``.
6232 >>> obj_by_path("foo.bar:Baz")
6233 <class 'foo.bar.Baz'>
6234 >>> obj_by_path("foo.bar:Baz.boo")
6235 <classmethod 'foo.bar.Baz.boo'>
6237 mod, objs = pypath.rsplit(":", 1)
6238 from importlib import import_module
6239 obj = import_module(mod)
6240 for obj_name in objs.split("."):
6241 obj = getattr(obj, obj_name)
6245 def generic_decoder(): # pragma: no cover
6246 # All of this below is a big hack with self references
6247 choice = PrimitiveTypes()
6248 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6249 choice.specs["SetOf"] = SetOf(schema=choice)
6250 for i in six_xrange(31):
6251 choice.specs["SequenceOf%d" % i] = SequenceOf(
6255 choice.specs["Any"] = Any()
6257 # Class name equals to type name, to omit it from output
6258 class SEQUENCEOF(SequenceOf):
6266 with_decode_path=False,
6267 decode_path_only=(),
6269 def _pprint_pps(pps):
6271 if hasattr(pp, "_fields"):
6273 decode_path_only != () and
6274 pp.decode_path[:len(decode_path_only)] != decode_path_only
6277 if pp.asn1_type_name == Choice.asn1_type_name:
6279 pp_kwargs = pp._asdict()
6280 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6281 pp = _pp(**pp_kwargs)
6282 yield pp_console_row(
6287 with_colours=with_colours,
6288 with_decode_path=with_decode_path,
6289 decode_path_len_decrease=len(decode_path_only),
6291 for row in pp_console_blob(
6293 decode_path_len_decrease=len(decode_path_only),
6297 for row in _pprint_pps(pp):
6299 return "\n".join(_pprint_pps(obj.pps()))
6300 return SEQUENCEOF(), pprint_any
6303 def main(): # pragma: no cover
6305 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6306 parser.add_argument(
6310 help="Skip that number of bytes from the beginning",
6312 parser.add_argument(
6314 help="Python paths to dictionary with OIDs, comma separated",
6316 parser.add_argument(
6318 help="Python path to schema definition to use",
6320 parser.add_argument(
6321 "--defines-by-path",
6322 help="Python path to decoder's defines_by_path",
6324 parser.add_argument(
6326 action="store_true",
6327 help="Disallow BER encoding",
6329 parser.add_argument(
6330 "--print-decode-path",
6331 action="store_true",
6332 help="Print decode paths",
6334 parser.add_argument(
6335 "--decode-path-only",
6336 help="Print only specified decode path",
6338 parser.add_argument(
6340 action="store_true",
6341 help="Allow explicit tag out-of-bound",
6343 parser.add_argument(
6345 type=argparse.FileType("rb"),
6346 help="Path to DER file you want to decode",
6348 args = parser.parse_args()
6349 args.DERFile.seek(args.skip)
6350 der = memoryview(args.DERFile.read())
6351 args.DERFile.close()
6353 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6354 if args.oids else ()
6357 schema = obj_by_path(args.schema)
6358 from functools import partial
6359 pprinter = partial(pprint, big_blobs=True)
6361 schema, pprinter = generic_decoder()
6363 "bered": not args.nobered,
6364 "allow_expl_oob": args.allow_expl_oob,
6366 if args.defines_by_path is not None:
6367 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6368 obj, tail = schema().decode(der, ctx=ctx)
6372 with_colours=environ.get("NO_COLOR") is None,
6373 with_decode_path=args.print_decode_path,
6375 () if args.decode_path_only is None else
6376 tuple(args.decode_path_only.split(":"))
6380 print("\nTrailing data: %s" % hexenc(tail))
6383 if __name__ == "__main__":