3 # cython: language_level=3
4 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
5 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, version 3 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Python ASN.1 DER/BER codec with abstract structures
20 This library allows you to marshal various structures in ASN.1 DER
21 format, unmarshal them in BER/CER/DER ones.
25 >>> Integer().decod(raw) == i
28 There are primitive types, holding single values
29 (:py:class:`pyderasn.BitString`,
30 :py:class:`pyderasn.Boolean`,
31 :py:class:`pyderasn.Enumerated`,
32 :py:class:`pyderasn.GeneralizedTime`,
33 :py:class:`pyderasn.Integer`,
34 :py:class:`pyderasn.Null`,
35 :py:class:`pyderasn.ObjectIdentifier`,
36 :py:class:`pyderasn.OctetString`,
37 :py:class:`pyderasn.UTCTime`,
38 :py:class:`various strings <pyderasn.CommonString>`
39 (:py:class:`pyderasn.BMPString`,
40 :py:class:`pyderasn.GeneralString`,
41 :py:class:`pyderasn.GraphicString`,
42 :py:class:`pyderasn.IA5String`,
43 :py:class:`pyderasn.ISO646String`,
44 :py:class:`pyderasn.NumericString`,
45 :py:class:`pyderasn.PrintableString`,
46 :py:class:`pyderasn.T61String`,
47 :py:class:`pyderasn.TeletexString`,
48 :py:class:`pyderasn.UniversalString`,
49 :py:class:`pyderasn.UTF8String`,
50 :py:class:`pyderasn.VideotexString`,
51 :py:class:`pyderasn.VisibleString`)),
52 constructed types, holding multiple primitive types
53 (:py:class:`pyderasn.Sequence`,
54 :py:class:`pyderasn.SequenceOf`,
55 :py:class:`pyderasn.Set`,
56 :py:class:`pyderasn.SetOf`),
57 and special types like
58 :py:class:`pyderasn.Any` and
59 :py:class:`pyderasn.Choice`.
67 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
68 the default tag used during coding process. You can override it with
69 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
70 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
71 argument or ``expl`` class attribute). Both arguments take raw binary
72 string, containing that tag. You can **not** set implicit and explicit
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
78 number. Pay attention that explicit tags always have *constructed* tag
79 (``tag_ctxc``), but implicit tags for primitive types are primitive
84 >>> Integer(impl=tag_ctxp(1))
86 >>> Integer(expl=tag_ctxc(2))
89 Implicit tag is not explicitly shown.
91 Two objects of the same type, but with different implicit/explicit tags
94 You can get object's effective tag (either default or implicited) through
95 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
98 >>> tag_decode(tag_ctxc(123))
100 >>> klass, form, num = tag_decode(tag_ctxc(123))
101 >>> klass == TagClassContext
103 >>> form == TagFormConstructed
106 To determine if object has explicit tag, use ``expled`` boolean property
107 and ``expl_tag`` property, returning explicit tag's value.
112 Many objects in sequences could be ``OPTIONAL`` and could have
113 ``DEFAULT`` value. You can specify that object's property using
114 corresponding keyword arguments.
116 >>> Integer(optional=True, default=123)
117 INTEGER 123 OPTIONAL DEFAULT
119 Those specifications do not play any role in primitive value encoding,
120 but are taken into account when dealing with sequences holding them. For
121 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
124 class Version(Integer):
130 class TBSCertificate(Sequence):
132 ("version", Version(expl=tag_ctxc(0), default="v1")),
135 When default argument is used and value is not specified, then it equals
143 Some objects give ability to set value size constraints. This is either
144 possible integer value, or allowed length of various strings and
145 sequences. Constraints are set in the following way::
150 And values satisfaction is checked as: ``MIN <= X <= MAX``.
152 For simplicity you can also set bounds the following way::
154 bounded_x = X(bounds=(MIN, MAX))
156 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
162 All objects have ``ready`` boolean property, that tells if object is
163 ready to be encoded. If that kind of action is performed on unready
164 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
166 All objects are friendly to ``copy.copy()`` and copied objects can be
169 Also all objects can be safely ``pickle``-d, but pay attention that
170 pickling among different PyDERASN versions is prohibited.
177 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
178 ``offset`` optional argument could be used to set initial object's
179 offset in the binary data, for convenience. It returns decoded object
180 and remaining unmarshalled data (tail). Internally all work is done on
181 ``memoryview(data)``, and you can leave returning tail as a memoryview,
182 by specifying ``leavemm=True`` argument.
184 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
185 immediately checks and raises if there is non-empty tail.
187 When object is decoded, ``decoded`` property is true and you can safely
188 use following properties:
190 * ``offset`` -- position including initial offset where object's tag starts
191 * ``tlen`` -- length of object's tag
192 * ``llen`` -- length of object's length value
193 * ``vlen`` -- length of object's value
194 * ``tlvlen`` -- length of the whole object
196 Pay attention that those values do **not** include anything related to
197 explicit tag. If you want to know information about it, then use:
199 * ``expled`` -- to know if explicit tag is set
200 * ``expl_offset`` (it is lesser than ``offset``)
203 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
204 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
206 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
209 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
216 You can specify so called context keyword argument during
217 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
218 various options governing decoding process.
220 Currently available context options:
222 * :ref:`allow_default_values <allow_default_values_ctx>`
223 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
224 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
225 * :ref:`bered <bered_ctx>`
226 * :ref:`defines_by_path <defines_by_path_ctx>`
233 All objects have ``pps()`` method, that is a generator of
234 :py:class:`pyderasn.PP` namedtuple, holding various raw information
235 about the object. If ``pps`` is called on sequences, then all underlying
236 ``PP`` will be yielded.
238 You can use :py:func:`pyderasn.pp_console_row` function, converting
239 those ``PP`` to human readable string. Actually exactly it is used for
240 all object ``repr``. But it is easy to write custom formatters.
242 >>> from pyderasn import pprint
243 >>> encoded = Integer(-12345).encode()
244 >>> obj, tail = Integer().decode(encoded)
245 >>> print(pprint(obj))
246 0 [1,1, 2] INTEGER -12345
250 Example certificate::
252 >>> print(pprint(crt))
253 0 [1,3,1604] Certificate SEQUENCE
254 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
255 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
256 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
257 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
258 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
259 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
261 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
262 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
263 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
264 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
265 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
266 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
267 . . . . . . . 13:02:45:53
269 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
270 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
271 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
273 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
274 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
275 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
280 Let's parse that output, human::
282 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
283 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
284 0 1 2 3 4 5 6 7 8 9 10 11
288 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
294 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
300 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
305 Offset of the object, where its DER/BER encoding begins.
306 Pay attention that it does **not** include explicit tag.
308 If explicit tag exists, then this is its length (tag + encoded length).
310 Length of object's tag. For example CHOICE does not have its own tag,
313 Length of encoded length.
315 Length of encoded value.
317 Visual indentation to show the depth of object in the hierarchy.
319 Object's name inside SEQUENCE/CHOICE.
321 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
322 here. "IMPLICIT" is omitted.
324 Object's class name, if set. Omitted if it is just an ordinary simple
325 value (like with ``algorithm`` in example above).
329 Object's value, if set. Can consist of multiple words (like OCTET/BIT
330 STRINGs above). We see ``v3`` value in Version, because it is named.
331 ``rdnSequence`` is the choice of CHOICE type.
333 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
334 default one, specified in the schema.
336 Shows does object contains any kind of BER encoded data (possibly
337 Sequence holding BER-encoded underlying value).
339 Only applicable to BER encoded data. Indefinite length encoding mark.
341 Only applicable to BER encoded data. If object has BER-specific
342 encoding, then ``BER`` will be shown. It does not depend on indefinite
343 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
344 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
353 ASN.1 structures often have ANY and OCTET STRING fields, that are
354 DEFINED BY some previously met ObjectIdentifier. This library provides
355 ability to specify mapping between some OID and field that must be
356 decoded with specific specification.
363 :py:class:`pyderasn.ObjectIdentifier` field inside
364 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
365 necessary for decoding structures. For example, CMS (:rfc:`5652`)
368 class ContentInfo(Sequence):
370 ("contentType", ContentType(defines=((("content",), {
371 id_digestedData: DigestedData(),
372 id_signedData: SignedData(),
374 ("content", Any(expl=tag_ctxc(0))),
377 ``contentType`` field tells that it defines that ``content`` must be
378 decoded with ``SignedData`` specification, if ``contentType`` equals to
379 ``id-signedData``. The same applies to ``DigestedData``. If
380 ``contentType`` contains unknown OID, then no automatic decoding is
383 You can specify multiple fields, that will be autodecoded -- that is why
384 ``defines`` kwarg is a sequence. You can specify defined field
385 relatively or absolutely to current decode path. For example ``defines``
386 for AlgorithmIdentifier of X.509's
387 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
391 id_ecPublicKey: ECParameters(),
392 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
394 (("..", "subjectPublicKey"), {
395 id_rsaEncryption: RSAPublicKey(),
396 id_GostR3410_2001: OctetString(),
400 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
401 autodecode its parameters inside SPKI's algorithm and its public key
404 Following types can be automatically decoded (DEFINED BY):
406 * :py:class:`pyderasn.Any`
407 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
408 * :py:class:`pyderasn.OctetString`
409 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
410 ``Any``/``BitString``/``OctetString``-s
412 When any of those fields is automatically decoded, then ``.defined``
413 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
414 was defined, ``value`` contains corresponding decoded value. For example
415 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
417 .. _defines_by_path_ctx:
419 defines_by_path context option
420 ______________________________
422 Sometimes you either can not or do not want to explicitly set *defines*
423 in the scheme. You can dynamically apply those definitions when calling
424 ``.decode()`` method.
426 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
427 value must be sequence of following tuples::
429 (decode_path, defines)
431 where ``decode_path`` is a tuple holding so-called decode path to the
432 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
433 ``defines``, holding exactly the same value as accepted in its
434 :ref:`keyword argument <defines>`.
436 For example, again for CMS, you want to automatically decode
437 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
438 structures it may hold. Also, automatically decode ``controlSequence``
441 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
444 ((("content",), {id_signedData: SignedData()}),),
449 DecodePathDefBy(id_signedData),
454 id_cct_PKIData: PKIData(),
455 id_cct_PKIResponse: PKIResponse(),
461 DecodePathDefBy(id_signedData),
464 DecodePathDefBy(id_cct_PKIResponse),
470 id_cmc_recipientNonce: RecipientNonce(),
471 id_cmc_senderNonce: SenderNonce(),
472 id_cmc_statusInfoV2: CMCStatusInfoV2(),
473 id_cmc_transactionId: TransactionId(),
478 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
479 First function is useful for path construction when some automatic
480 decoding is already done. ``any`` means literally any value it meet --
481 useful for SEQUENCE/SET OF-s.
488 By default PyDERASN accepts only DER encoded data. It always encodes to
489 DER. But you can optionally enable BER decoding with setting ``bered``
490 :ref:`context <ctx>` argument to True. Indefinite lengths and
491 constructed primitive types should be parsed successfully.
493 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
494 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
495 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
496 ``UTCTime``, ``GeneralizedTime`` can contain it.
497 * If object has an indefinite length encoding, then its ``lenindef``
498 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
499 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
501 * If object has an indefinite length encoded explicit tag, then
502 ``expl_lenindef`` is set to True.
503 * If object has either any of BER-related encoding (explicit tag
504 indefinite length, object's indefinite length, BER-encoding) or any
505 underlying component has that kind of encoding, then ``bered``
506 attribute is set to True. For example SignedData CMS can have
507 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
508 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
510 EOC (end-of-contents) token's length is taken in advance in object's
513 .. _allow_expl_oob_ctx:
515 Allow explicit tag out-of-bound
516 -------------------------------
518 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
519 one value, more than one object. If you set ``allow_expl_oob`` context
520 option to True, then no error will be raised and that invalid encoding
521 will be silently further processed. But pay attention that offsets and
522 lengths will be invalid in that case.
526 This option should be used only for skipping some decode errors, just
527 to see the decoded structure somehow.
531 .. autoclass:: pyderasn.Obj
539 .. autoclass:: pyderasn.Boolean
544 .. autoclass:: pyderasn.Integer
549 .. autoclass:: pyderasn.BitString
554 .. autoclass:: pyderasn.OctetString
559 .. autoclass:: pyderasn.Null
564 .. autoclass:: pyderasn.ObjectIdentifier
569 .. autoclass:: pyderasn.Enumerated
573 .. autoclass:: pyderasn.CommonString
577 .. autoclass:: pyderasn.NumericString
581 .. autoclass:: pyderasn.PrintableString
586 .. autoclass:: pyderasn.UTCTime
587 :members: __init__, todatetime
591 .. autoclass:: pyderasn.GeneralizedTime
598 .. autoclass:: pyderasn.Choice
603 .. autoclass:: PrimitiveTypes
607 .. autoclass:: pyderasn.Any
615 .. autoclass:: pyderasn.Sequence
620 .. autoclass:: pyderasn.Set
625 .. autoclass:: pyderasn.SequenceOf
630 .. autoclass:: pyderasn.SetOf
636 .. autofunction:: pyderasn.abs_decode_path
637 .. autofunction:: pyderasn.colonize_hex
638 .. autofunction:: pyderasn.hexenc
639 .. autofunction:: pyderasn.hexdec
640 .. autofunction:: pyderasn.tag_encode
641 .. autofunction:: pyderasn.tag_decode
642 .. autofunction:: pyderasn.tag_ctxp
643 .. autofunction:: pyderasn.tag_ctxc
644 .. autoclass:: pyderasn.DecodeError
646 .. autoclass:: pyderasn.NotEnoughData
647 .. autoclass:: pyderasn.ExceedingData
648 .. autoclass:: pyderasn.LenIndefForm
649 .. autoclass:: pyderasn.TagMismatch
650 .. autoclass:: pyderasn.InvalidLength
651 .. autoclass:: pyderasn.InvalidOID
652 .. autoclass:: pyderasn.ObjUnknown
653 .. autoclass:: pyderasn.ObjNotReady
654 .. autoclass:: pyderasn.InvalidValueType
655 .. autoclass:: pyderasn.BoundsError
658 from codecs import getdecoder
659 from codecs import getencoder
660 from collections import namedtuple
661 from collections import OrderedDict
662 from copy import copy
663 from datetime import datetime
664 from datetime import timedelta
665 from math import ceil
666 from os import environ
667 from string import ascii_letters
668 from string import digits
669 from unicodedata import category as unicat
671 from six import add_metaclass
672 from six import binary_type
673 from six import byte2int
674 from six import indexbytes
675 from six import int2byte
676 from six import integer_types
677 from six import iterbytes
678 from six import iteritems
679 from six import itervalues
681 from six import string_types
682 from six import text_type
683 from six import unichr as six_unichr
684 from six.moves import xrange as six_xrange
688 from termcolor import colored
689 except ImportError: # pragma: no cover
690 def colored(what, *args, **kwargs):
736 "TagClassApplication",
740 "TagFormConstructed",
751 TagClassUniversal = 0
752 TagClassApplication = 1 << 6
753 TagClassContext = 1 << 7
754 TagClassPrivate = 1 << 6 | 1 << 7
756 TagFormConstructed = 1 << 5
759 TagClassApplication: "APPLICATION ",
760 TagClassPrivate: "PRIVATE ",
761 TagClassUniversal: "UNIV ",
765 LENINDEF = b"\x80" # length indefinite mark
766 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
767 NAMEDTUPLE_KWARGS = {} if PY2 else {"module": __name__}
768 SET01 = frozenset(("0", "1"))
774 if (value[0] in "+- ") or (value[-1] == " "):
775 raise ValueError("non-pure integer")
778 def fractions2float(fractions_raw):
779 pureint(fractions_raw)
780 return float("0." + fractions_raw)
783 ########################################################################
785 ########################################################################
787 class ASN1Error(ValueError):
791 class DecodeError(ASN1Error):
792 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
794 :param str msg: reason of decode failing
795 :param klass: optional exact DecodeError inherited class (like
796 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
797 :py:exc:`InvalidLength`)
798 :param decode_path: tuple of strings. It contains human
799 readable names of the fields through which
800 decoding process has passed
801 :param int offset: binary offset where failure happened
803 super(DecodeError, self).__init__()
806 self.decode_path = decode_path
812 "" if self.klass is None else self.klass.__name__,
814 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
815 if len(self.decode_path) > 0 else ""
817 ("(at %d)" % self.offset) if self.offset > 0 else "",
823 return "%s(%s)" % (self.__class__.__name__, self)
826 class NotEnoughData(DecodeError):
830 class ExceedingData(ASN1Error):
831 def __init__(self, nbytes):
832 super(ExceedingData, self).__init__()
836 return "%d trailing bytes" % self.nbytes
839 return "%s(%s)" % (self.__class__.__name__, self)
842 class LenIndefForm(DecodeError):
846 class TagMismatch(DecodeError):
850 class InvalidLength(DecodeError):
854 class InvalidOID(DecodeError):
858 class ObjUnknown(ASN1Error):
859 def __init__(self, name):
860 super(ObjUnknown, self).__init__()
864 return "object is unknown: %s" % self.name
867 return "%s(%s)" % (self.__class__.__name__, self)
870 class ObjNotReady(ASN1Error):
871 def __init__(self, name):
872 super(ObjNotReady, self).__init__()
876 return "object is not ready: %s" % self.name
879 return "%s(%s)" % (self.__class__.__name__, self)
882 class InvalidValueType(ASN1Error):
883 def __init__(self, expected_types):
884 super(InvalidValueType, self).__init__()
885 self.expected_types = expected_types
888 return "invalid value type, expected: %s" % ", ".join(
889 [repr(t) for t in self.expected_types]
893 return "%s(%s)" % (self.__class__.__name__, self)
896 class BoundsError(ASN1Error):
897 def __init__(self, bound_min, value, bound_max):
898 super(BoundsError, self).__init__()
899 self.bound_min = bound_min
901 self.bound_max = bound_max
904 return "unsatisfied bounds: %s <= %s <= %s" % (
911 return "%s(%s)" % (self.__class__.__name__, self)
914 ########################################################################
916 ########################################################################
918 _hexdecoder = getdecoder("hex")
919 _hexencoder = getencoder("hex")
923 """Binary data to hexadecimal string convert
925 return _hexdecoder(data)[0]
929 """Hexadecimal string to binary data convert
931 return _hexencoder(data)[0].decode("ascii")
934 def int_bytes_len(num, byte_len=8):
937 return int(ceil(float(num.bit_length()) / byte_len))
940 def zero_ended_encode(num):
941 octets = bytearray(int_bytes_len(num, 7))
943 octets[i] = num & 0x7F
947 octets[i] = 0x80 | (num & 0x7F)
953 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
954 """Encode tag to binary form
956 :param int num: tag's number
957 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
958 :py:data:`pyderasn.TagClassContext`,
959 :py:data:`pyderasn.TagClassApplication`,
960 :py:data:`pyderasn.TagClassPrivate`)
961 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
962 :py:data:`pyderasn.TagFormConstructed`)
966 return int2byte(klass | form | num)
967 # [XX|X|11111][1.......][1.......] ... [0.......]
968 return int2byte(klass | form | 31) + zero_ended_encode(num)
972 """Decode tag from binary form
976 No validation is performed, assuming that it has already passed.
978 It returns tuple with three integers, as
979 :py:func:`pyderasn.tag_encode` accepts.
981 first_octet = byte2int(tag)
982 klass = first_octet & 0xC0
983 form = first_octet & 0x20
984 if first_octet & 0x1F < 0x1F:
985 return (klass, form, first_octet & 0x1F)
987 for octet in iterbytes(tag[1:]):
990 return (klass, form, num)
994 """Create CONTEXT PRIMITIVE tag
996 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1000 """Create CONTEXT CONSTRUCTED tag
1002 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1005 def tag_strip(data):
1006 """Take off tag from the data
1008 :returns: (encoded tag, tag length, remaining data)
1011 raise NotEnoughData("no data at all")
1012 if byte2int(data) & 0x1F < 31:
1013 return data[:1], 1, data[1:]
1018 raise DecodeError("unfinished tag")
1019 if indexbytes(data, i) & 0x80 == 0:
1022 return data[:i], i, data[i:]
1028 octets = bytearray(int_bytes_len(l) + 1)
1029 octets[0] = 0x80 | (len(octets) - 1)
1030 for i in six_xrange(len(octets) - 1, 0, -1):
1031 octets[i] = l & 0xFF
1033 return bytes(octets)
1036 def len_decode(data):
1039 :returns: (decoded length, length's length, remaining data)
1040 :raises LenIndefForm: if indefinite form encoding is met
1043 raise NotEnoughData("no data at all")
1044 first_octet = byte2int(data)
1045 if first_octet & 0x80 == 0:
1046 return first_octet, 1, data[1:]
1047 octets_num = first_octet & 0x7F
1048 if octets_num + 1 > len(data):
1049 raise NotEnoughData("encoded length is longer than data")
1051 raise LenIndefForm()
1052 if byte2int(data[1:]) == 0:
1053 raise DecodeError("leading zeros")
1055 for v in iterbytes(data[1:1 + octets_num]):
1058 raise DecodeError("long form instead of short one")
1059 return l, 1 + octets_num, data[1 + octets_num:]
1062 ########################################################################
1064 ########################################################################
1066 class AutoAddSlots(type):
1067 def __new__(cls, name, bases, _dict):
1068 _dict["__slots__"] = _dict.get("__slots__", ())
1069 return type.__new__(cls, name, bases, _dict)
1072 @add_metaclass(AutoAddSlots)
1074 """Common ASN.1 object class
1076 All ASN.1 types are inherited from it. It has metaclass that
1077 automatically adds ``__slots__`` to all inherited classes.
1101 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1102 self._expl = getattr(self, "expl", None) if expl is None else expl
1103 if self.tag != self.tag_default and self._expl is not None:
1104 raise ValueError("implicit and explicit tags can not be set simultaneously")
1105 if default is not None:
1107 self.optional = optional
1108 self.offset, self.llen, self.vlen = _decoded
1110 self.expl_lenindef = False
1111 self.lenindef = False
1112 self.ber_encoded = False
1115 def ready(self): # pragma: no cover
1116 """Is object ready to be encoded?
1118 raise NotImplementedError()
1120 def _assert_ready(self):
1122 raise ObjNotReady(self.__class__.__name__)
1126 """Is either object or any elements inside is BER encoded?
1128 return self.expl_lenindef or self.lenindef or self.ber_encoded
1132 """Is object decoded?
1134 return (self.llen + self.vlen) > 0
1136 def __getstate__(self): # pragma: no cover
1137 """Used for making safe to be mutable pickleable copies
1139 raise NotImplementedError()
1141 def __setstate__(self, state):
1142 if state.version != __version__:
1143 raise ValueError("data is pickled by different PyDERASN version")
1144 self.tag = self.tag_default
1148 self.optional = False
1152 self.expl_lenindef = False
1153 self.lenindef = False
1154 self.ber_encoded = False
1158 """See :ref:`decoding`
1160 return len(self.tag)
1164 """See :ref:`decoding`
1166 return self.tlen + self.llen + self.vlen
1168 def __str__(self): # pragma: no cover
1169 return self.__bytes__() if PY2 else self.__unicode__()
1171 def __ne__(self, their):
1172 return not(self == their)
1174 def __gt__(self, their): # pragma: no cover
1175 return not(self < their)
1177 def __le__(self, their): # pragma: no cover
1178 return (self == their) or (self < their)
1180 def __ge__(self, their): # pragma: no cover
1181 return (self == their) or (self > their)
1183 def _encode(self): # pragma: no cover
1184 raise NotImplementedError()
1186 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1187 raise NotImplementedError()
1190 """Encode the structure
1192 :returns: DER representation
1194 raw = self._encode()
1195 if self._expl is None:
1197 return b"".join((self._expl, len_encode(len(raw)), raw))
1199 def hexencode(self):
1200 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1202 return hexenc(self.encode())
1212 _ctx_immutable=True,
1216 :param data: either binary or memoryview
1217 :param int offset: initial data's offset
1218 :param bool leavemm: do we need to leave memoryview of remaining
1219 data as is, or convert it to bytes otherwise
1220 :param ctx: optional :ref:`context <ctx>` governing decoding process
1221 :param tag_only: decode only the tag, without length and contents
1222 (used only in Choice and Set structures, trying to
1223 determine if tag satisfies the scheme)
1224 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1226 :returns: (Obj, remaining data)
1228 .. seealso:: :ref:`decoding`
1232 elif _ctx_immutable:
1234 tlv = memoryview(data)
1235 if self._expl is None:
1236 result = self._decode(
1239 decode_path=decode_path,
1248 t, tlen, lv = tag_strip(tlv)
1249 except DecodeError as err:
1250 raise err.__class__(
1252 klass=self.__class__,
1253 decode_path=decode_path,
1258 klass=self.__class__,
1259 decode_path=decode_path,
1263 l, llen, v = len_decode(lv)
1264 except LenIndefForm as err:
1265 if not ctx.get("bered", False):
1266 raise err.__class__(
1268 klass=self.__class__,
1269 decode_path=decode_path,
1273 offset += tlen + llen
1274 result = self._decode(
1277 decode_path=decode_path,
1281 if tag_only: # pragma: no cover
1284 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1285 if eoc_expected.tobytes() != EOC:
1288 klass=self.__class__,
1289 decode_path=decode_path,
1293 obj.expl_lenindef = True
1294 except DecodeError as err:
1295 raise err.__class__(
1297 klass=self.__class__,
1298 decode_path=decode_path,
1303 raise NotEnoughData(
1304 "encoded length is longer than data",
1305 klass=self.__class__,
1306 decode_path=decode_path,
1309 result = self._decode(
1311 offset=offset + tlen + llen,
1312 decode_path=decode_path,
1316 if tag_only: # pragma: no cover
1319 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1321 "explicit tag out-of-bound, longer than data",
1322 klass=self.__class__,
1323 decode_path=decode_path,
1326 return obj, (tail if leavemm else tail.tobytes())
1328 def decod(self, data, offset=0, decode_path=(), ctx=None):
1329 """Decode the data, check that tail is empty
1331 :raises ExceedingData: if tail is not empty
1333 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1334 (decode without tail) that also checks that there is no
1337 obj, tail = self.decode(
1340 decode_path=decode_path,
1345 raise ExceedingData(len(tail))
1348 def hexdecode(self, data, *args, **kwargs):
1349 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1351 return self.decode(hexdec(data), *args, **kwargs)
1353 def hexdecod(self, data, *args, **kwargs):
1354 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1356 return self.decod(hexdec(data), *args, **kwargs)
1360 """See :ref:`decoding`
1362 return self._expl is not None
1366 """See :ref:`decoding`
1371 def expl_tlen(self):
1372 """See :ref:`decoding`
1374 return len(self._expl)
1377 def expl_llen(self):
1378 """See :ref:`decoding`
1380 if self.expl_lenindef:
1382 return len(len_encode(self.tlvlen))
1385 def expl_offset(self):
1386 """See :ref:`decoding`
1388 return self.offset - self.expl_tlen - self.expl_llen
1391 def expl_vlen(self):
1392 """See :ref:`decoding`
1397 def expl_tlvlen(self):
1398 """See :ref:`decoding`
1400 return self.expl_tlen + self.expl_llen + self.expl_vlen
1403 def fulloffset(self):
1404 """See :ref:`decoding`
1406 return self.expl_offset if self.expled else self.offset
1410 """See :ref:`decoding`
1412 return self.expl_tlvlen if self.expled else self.tlvlen
1414 def pps_lenindef(self, decode_path):
1415 if self.lenindef and not (
1416 getattr(self, "defined", None) is not None and
1417 self.defined[1].lenindef
1420 asn1_type_name="EOC",
1422 decode_path=decode_path,
1424 self.offset + self.tlvlen -
1425 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1433 if self.expl_lenindef:
1435 asn1_type_name="EOC",
1436 obj_name="EXPLICIT",
1437 decode_path=decode_path,
1438 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1447 class DecodePathDefBy(object):
1448 """DEFINED BY representation inside decode path
1450 __slots__ = ("defined_by",)
1452 def __init__(self, defined_by):
1453 self.defined_by = defined_by
1455 def __ne__(self, their):
1456 return not(self == their)
1458 def __eq__(self, their):
1459 if not isinstance(their, self.__class__):
1461 return self.defined_by == their.defined_by
1464 return "DEFINED BY " + str(self.defined_by)
1467 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1470 ########################################################################
1472 ########################################################################
1474 PP = namedtuple("PP", (
1497 ), **NAMEDTUPLE_KWARGS)
1502 asn1_type_name="unknown",
1519 expl_lenindef=False,
1550 def _colourize(what, colour, with_colours, attrs=("bold",)):
1551 return colored(what, colour, attrs=attrs) if with_colours else what
1554 def colonize_hex(hexed):
1555 """Separate hexadecimal string with colons
1557 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1566 with_decode_path=False,
1567 decode_path_len_decrease=0,
1574 " " if pp.expl_offset is None else
1575 ("-%d" % (pp.offset - pp.expl_offset))
1577 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1579 col = _colourize(col, "red", with_colours, ())
1580 col += _colourize("B", "red", with_colours) if pp.bered else " "
1582 col = "[%d,%d,%4d]%s" % (
1586 LENINDEF_PP_CHAR if pp.lenindef else " "
1588 col = _colourize(col, "green", with_colours, ())
1590 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1591 if decode_path_len > 0:
1592 cols.append(" ." * decode_path_len)
1593 ent = pp.decode_path[-1]
1594 if isinstance(ent, DecodePathDefBy):
1595 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1596 value = str(ent.defined_by)
1599 len(oid_maps) > 0 and
1600 ent.defined_by.asn1_type_name ==
1601 ObjectIdentifier.asn1_type_name
1603 for oid_map in oid_maps:
1604 oid_name = oid_map.get(value)
1605 if oid_name is not None:
1606 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1608 if oid_name is None:
1609 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1611 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1612 if pp.expl is not None:
1613 klass, _, num = pp.expl
1614 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1615 cols.append(_colourize(col, "blue", with_colours))
1616 if pp.impl is not None:
1617 klass, _, num = pp.impl
1618 col = "[%s%d]" % (TagClassReprs[klass], num)
1619 cols.append(_colourize(col, "blue", with_colours))
1620 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1621 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1623 cols.append(_colourize("BER", "red", with_colours))
1624 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1625 if pp.value is not None:
1627 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1629 len(oid_maps) > 0 and
1630 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1632 for oid_map in oid_maps:
1633 oid_name = oid_map.get(value)
1634 if oid_name is not None:
1635 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1637 if pp.asn1_type_name == Integer.asn1_type_name:
1638 hex_repr = hex(int(pp.obj._value))[2:].upper()
1639 if len(hex_repr) % 2 != 0:
1640 hex_repr = "0" + hex_repr
1641 cols.append(_colourize(
1642 "(%s)" % colonize_hex(hex_repr),
1647 if isinstance(pp.blob, binary_type):
1648 cols.append(hexenc(pp.blob))
1649 elif isinstance(pp.blob, tuple):
1650 cols.append(", ".join(pp.blob))
1652 cols.append(_colourize("OPTIONAL", "red", with_colours))
1654 cols.append(_colourize("DEFAULT", "red", with_colours))
1655 if with_decode_path:
1656 cols.append(_colourize(
1657 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1661 return " ".join(cols)
1664 def pp_console_blob(pp, decode_path_len_decrease=0):
1665 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1666 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1667 if decode_path_len > 0:
1668 cols.append(" ." * (decode_path_len + 1))
1669 if isinstance(pp.blob, binary_type):
1670 blob = hexenc(pp.blob).upper()
1671 for i in six_xrange(0, len(blob), 32):
1672 chunk = blob[i:i + 32]
1673 yield " ".join(cols + [colonize_hex(chunk)])
1674 elif isinstance(pp.blob, tuple):
1675 yield " ".join(cols + [", ".join(pp.blob)])
1683 with_decode_path=False,
1684 decode_path_only=(),
1686 """Pretty print object
1688 :param Obj obj: object you want to pretty print
1689 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1690 Its human readable form is printed when OID is met
1691 :param big_blobs: if large binary objects are met (like OctetString
1692 values), do we need to print them too, on separate
1694 :param with_colours: colourize output, if ``termcolor`` library
1696 :param with_decode_path: print decode path
1697 :param decode_path_only: print only that specified decode path
1699 def _pprint_pps(pps):
1701 if hasattr(pp, "_fields"):
1703 decode_path_only != () and
1705 str(p) for p in pp.decode_path[:len(decode_path_only)]
1706 ) != decode_path_only
1710 yield pp_console_row(
1715 with_colours=with_colours,
1716 with_decode_path=with_decode_path,
1717 decode_path_len_decrease=len(decode_path_only),
1719 for row in pp_console_blob(
1721 decode_path_len_decrease=len(decode_path_only),
1725 yield pp_console_row(
1730 with_colours=with_colours,
1731 with_decode_path=with_decode_path,
1732 decode_path_len_decrease=len(decode_path_only),
1735 for row in _pprint_pps(pp):
1737 return "\n".join(_pprint_pps(obj.pps()))
1740 ########################################################################
1741 # ASN.1 primitive types
1742 ########################################################################
1744 BooleanState = namedtuple("BooleanState", (
1757 ), **NAMEDTUPLE_KWARGS)
1761 """``BOOLEAN`` boolean type
1763 >>> b = Boolean(True)
1765 >>> b == Boolean(True)
1771 tag_default = tag_encode(1)
1772 asn1_type_name = "BOOLEAN"
1784 :param value: set the value. Either boolean type, or
1785 :py:class:`pyderasn.Boolean` object
1786 :param bytes impl: override default tag with ``IMPLICIT`` one
1787 :param bytes expl: override default tag with ``EXPLICIT`` one
1788 :param default: set default value. Type same as in ``value``
1789 :param bool optional: is object ``OPTIONAL`` in sequence
1791 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1792 self._value = None if value is None else self._value_sanitize(value)
1793 if default is not None:
1794 default = self._value_sanitize(default)
1795 self.default = self.__class__(
1801 self._value = default
1803 def _value_sanitize(self, value):
1804 if isinstance(value, bool):
1806 if issubclass(value.__class__, Boolean):
1808 raise InvalidValueType((self.__class__, bool))
1812 return self._value is not None
1814 def __getstate__(self):
1815 return BooleanState(
1830 def __setstate__(self, state):
1831 super(Boolean, self).__setstate__(state)
1832 self._value = state.value
1833 self.tag = state.tag
1834 self._expl = state.expl
1835 self.default = state.default
1836 self.optional = state.optional
1837 self.offset = state.offset
1838 self.llen = state.llen
1839 self.vlen = state.vlen
1840 self.expl_lenindef = state.expl_lenindef
1841 self.lenindef = state.lenindef
1842 self.ber_encoded = state.ber_encoded
1844 def __nonzero__(self):
1845 self._assert_ready()
1849 self._assert_ready()
1852 def __eq__(self, their):
1853 if isinstance(their, bool):
1854 return self._value == their
1855 if not issubclass(their.__class__, Boolean):
1858 self._value == their._value and
1859 self.tag == their.tag and
1860 self._expl == their._expl
1871 return self.__class__(
1873 impl=self.tag if impl is None else impl,
1874 expl=self._expl if expl is None else expl,
1875 default=self.default if default is None else default,
1876 optional=self.optional if optional is None else optional,
1880 self._assert_ready()
1884 (b"\xFF" if self._value else b"\x00"),
1887 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1889 t, _, lv = tag_strip(tlv)
1890 except DecodeError as err:
1891 raise err.__class__(
1893 klass=self.__class__,
1894 decode_path=decode_path,
1899 klass=self.__class__,
1900 decode_path=decode_path,
1906 l, _, v = len_decode(lv)
1907 except DecodeError as err:
1908 raise err.__class__(
1910 klass=self.__class__,
1911 decode_path=decode_path,
1915 raise InvalidLength(
1916 "Boolean's length must be equal to 1",
1917 klass=self.__class__,
1918 decode_path=decode_path,
1922 raise NotEnoughData(
1923 "encoded length is longer than data",
1924 klass=self.__class__,
1925 decode_path=decode_path,
1928 first_octet = byte2int(v)
1930 if first_octet == 0:
1932 elif first_octet == 0xFF:
1934 elif ctx.get("bered", False):
1939 "unacceptable Boolean value",
1940 klass=self.__class__,
1941 decode_path=decode_path,
1944 obj = self.__class__(
1948 default=self.default,
1949 optional=self.optional,
1950 _decoded=(offset, 1, 1),
1952 obj.ber_encoded = ber_encoded
1956 return pp_console_row(next(self.pps()))
1958 def pps(self, decode_path=()):
1961 asn1_type_name=self.asn1_type_name,
1962 obj_name=self.__class__.__name__,
1963 decode_path=decode_path,
1964 value=str(self._value) if self.ready else None,
1965 optional=self.optional,
1966 default=self == self.default,
1967 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1968 expl=None if self._expl is None else tag_decode(self._expl),
1973 expl_offset=self.expl_offset if self.expled else None,
1974 expl_tlen=self.expl_tlen if self.expled else None,
1975 expl_llen=self.expl_llen if self.expled else None,
1976 expl_vlen=self.expl_vlen if self.expled else None,
1977 expl_lenindef=self.expl_lenindef,
1978 ber_encoded=self.ber_encoded,
1981 for pp in self.pps_lenindef(decode_path):
1985 IntegerState = namedtuple("IntegerState", (
2001 ), **NAMEDTUPLE_KWARGS)
2005 """``INTEGER`` integer type
2007 >>> b = Integer(-123)
2009 >>> b == Integer(-123)
2014 >>> Integer(2, bounds=(1, 3))
2016 >>> Integer(5, bounds=(1, 3))
2017 Traceback (most recent call last):
2018 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2022 class Version(Integer):
2029 >>> v = Version("v1")
2036 {'v3': 2, 'v1': 0, 'v2': 1}
2038 __slots__ = ("specs", "_bound_min", "_bound_max")
2039 tag_default = tag_encode(2)
2040 asn1_type_name = "INTEGER"
2054 :param value: set the value. Either integer type, named value
2055 (if ``schema`` is specified in the class), or
2056 :py:class:`pyderasn.Integer` object
2057 :param bounds: set ``(MIN, MAX)`` value constraint.
2058 (-inf, +inf) by default
2059 :param bytes impl: override default tag with ``IMPLICIT`` one
2060 :param bytes expl: override default tag with ``EXPLICIT`` one
2061 :param default: set default value. Type same as in ``value``
2062 :param bool optional: is object ``OPTIONAL`` in sequence
2064 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2066 specs = getattr(self, "schema", {}) if _specs is None else _specs
2067 self.specs = specs if isinstance(specs, dict) else dict(specs)
2068 self._bound_min, self._bound_max = getattr(
2071 (float("-inf"), float("+inf")),
2072 ) if bounds is None else bounds
2073 if value is not None:
2074 self._value = self._value_sanitize(value)
2075 if default is not None:
2076 default = self._value_sanitize(default)
2077 self.default = self.__class__(
2083 if self._value is None:
2084 self._value = default
2086 def _value_sanitize(self, value):
2087 if isinstance(value, integer_types):
2089 elif issubclass(value.__class__, Integer):
2090 value = value._value
2091 elif isinstance(value, str):
2092 value = self.specs.get(value)
2094 raise ObjUnknown("integer value: %s" % value)
2096 raise InvalidValueType((self.__class__, int, str))
2097 if not self._bound_min <= value <= self._bound_max:
2098 raise BoundsError(self._bound_min, value, self._bound_max)
2103 return self._value is not None
2105 def __getstate__(self):
2106 return IntegerState(
2124 def __setstate__(self, state):
2125 super(Integer, self).__setstate__(state)
2126 self.specs = state.specs
2127 self._value = state.value
2128 self._bound_min = state.bound_min
2129 self._bound_max = state.bound_max
2130 self.tag = state.tag
2131 self._expl = state.expl
2132 self.default = state.default
2133 self.optional = state.optional
2134 self.offset = state.offset
2135 self.llen = state.llen
2136 self.vlen = state.vlen
2137 self.expl_lenindef = state.expl_lenindef
2138 self.lenindef = state.lenindef
2139 self.ber_encoded = state.ber_encoded
2142 self._assert_ready()
2143 return int(self._value)
2146 self._assert_ready()
2149 bytes(self._expl or b"") +
2150 str(self._value).encode("ascii"),
2153 def __eq__(self, their):
2154 if isinstance(their, integer_types):
2155 return self._value == their
2156 if not issubclass(their.__class__, Integer):
2159 self._value == their._value and
2160 self.tag == their.tag and
2161 self._expl == their._expl
2164 def __lt__(self, their):
2165 return self._value < their._value
2169 for name, value in iteritems(self.specs):
2170 if value == self._value:
2183 return self.__class__(
2186 (self._bound_min, self._bound_max)
2187 if bounds is None else bounds
2189 impl=self.tag if impl is None else impl,
2190 expl=self._expl if expl is None else expl,
2191 default=self.default if default is None else default,
2192 optional=self.optional if optional is None else optional,
2197 self._assert_ready()
2201 octets = bytearray([0])
2205 octets = bytearray()
2207 octets.append((value & 0xFF) ^ 0xFF)
2209 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2212 octets = bytearray()
2214 octets.append(value & 0xFF)
2216 if octets[-1] & 0x80 > 0:
2219 octets = bytes(octets)
2221 bytes_len = ceil(value.bit_length() / 8) or 1
2224 octets = value.to_bytes(
2229 except OverflowError:
2233 return b"".join((self.tag, len_encode(len(octets)), octets))
2235 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2237 t, _, lv = tag_strip(tlv)
2238 except DecodeError as err:
2239 raise err.__class__(
2241 klass=self.__class__,
2242 decode_path=decode_path,
2247 klass=self.__class__,
2248 decode_path=decode_path,
2254 l, llen, v = len_decode(lv)
2255 except DecodeError as err:
2256 raise err.__class__(
2258 klass=self.__class__,
2259 decode_path=decode_path,
2263 raise NotEnoughData(
2264 "encoded length is longer than data",
2265 klass=self.__class__,
2266 decode_path=decode_path,
2270 raise NotEnoughData(
2272 klass=self.__class__,
2273 decode_path=decode_path,
2276 v, tail = v[:l], v[l:]
2277 first_octet = byte2int(v)
2279 second_octet = byte2int(v[1:])
2281 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2282 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2285 "non normalized integer",
2286 klass=self.__class__,
2287 decode_path=decode_path,
2292 if first_octet & 0x80 > 0:
2293 octets = bytearray()
2294 for octet in bytearray(v):
2295 octets.append(octet ^ 0xFF)
2296 for octet in octets:
2297 value = (value << 8) | octet
2301 for octet in bytearray(v):
2302 value = (value << 8) | octet
2304 value = int.from_bytes(v, byteorder="big", signed=True)
2306 obj = self.__class__(
2308 bounds=(self._bound_min, self._bound_max),
2311 default=self.default,
2312 optional=self.optional,
2314 _decoded=(offset, llen, l),
2316 except BoundsError as err:
2319 klass=self.__class__,
2320 decode_path=decode_path,
2326 return pp_console_row(next(self.pps()))
2328 def pps(self, decode_path=()):
2331 asn1_type_name=self.asn1_type_name,
2332 obj_name=self.__class__.__name__,
2333 decode_path=decode_path,
2334 value=(self.named or str(self._value)) if self.ready else None,
2335 optional=self.optional,
2336 default=self == self.default,
2337 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2338 expl=None if self._expl is None else tag_decode(self._expl),
2343 expl_offset=self.expl_offset if self.expled else None,
2344 expl_tlen=self.expl_tlen if self.expled else None,
2345 expl_llen=self.expl_llen if self.expled else None,
2346 expl_vlen=self.expl_vlen if self.expled else None,
2347 expl_lenindef=self.expl_lenindef,
2350 for pp in self.pps_lenindef(decode_path):
2354 BitStringState = namedtuple("BitStringState", (
2370 ), **NAMEDTUPLE_KWARGS)
2373 class BitString(Obj):
2374 """``BIT STRING`` bit string type
2376 >>> BitString(b"hello world")
2377 BIT STRING 88 bits 68656c6c6f20776f726c64
2380 >>> b == b"hello world"
2385 >>> BitString("'0A3B5F291CD'H")
2386 BIT STRING 44 bits 0a3b5f291cd0
2387 >>> b = BitString("'010110000000'B")
2388 BIT STRING 12 bits 5800
2391 >>> b[0], b[1], b[2], b[3]
2392 (False, True, False, True)
2396 [False, True, False, True, True, False, False, False, False, False, False, False]
2400 class KeyUsage(BitString):
2402 ("digitalSignature", 0),
2403 ("nonRepudiation", 1),
2404 ("keyEncipherment", 2),
2407 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2408 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2410 ['nonRepudiation', 'keyEncipherment']
2412 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2416 Pay attention that BIT STRING can be encoded both in primitive
2417 and constructed forms. Decoder always checks constructed form tag
2418 additionally to specified primitive one. If BER decoding is
2419 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2420 of DER restrictions.
2422 __slots__ = ("tag_constructed", "specs", "defined")
2423 tag_default = tag_encode(3)
2424 asn1_type_name = "BIT STRING"
2437 :param value: set the value. Either binary type, tuple of named
2438 values (if ``schema`` is specified in the class),
2439 string in ``'XXX...'B`` form, or
2440 :py:class:`pyderasn.BitString` object
2441 :param bytes impl: override default tag with ``IMPLICIT`` one
2442 :param bytes expl: override default tag with ``EXPLICIT`` one
2443 :param default: set default value. Type same as in ``value``
2444 :param bool optional: is object ``OPTIONAL`` in sequence
2446 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2447 specs = getattr(self, "schema", {}) if _specs is None else _specs
2448 self.specs = specs if isinstance(specs, dict) else dict(specs)
2449 self._value = None if value is None else self._value_sanitize(value)
2450 if default is not None:
2451 default = self._value_sanitize(default)
2452 self.default = self.__class__(
2458 self._value = default
2460 tag_klass, _, tag_num = tag_decode(self.tag)
2461 self.tag_constructed = tag_encode(
2463 form=TagFormConstructed,
2467 def _bits2octets(self, bits):
2468 if len(self.specs) > 0:
2469 bits = bits.rstrip("0")
2471 bits += "0" * ((8 - (bit_len % 8)) % 8)
2472 octets = bytearray(len(bits) // 8)
2473 for i in six_xrange(len(octets)):
2474 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2475 return bit_len, bytes(octets)
2477 def _value_sanitize(self, value):
2478 if isinstance(value, (string_types, binary_type)):
2480 isinstance(value, string_types) and
2481 value.startswith("'")
2483 if value.endswith("'B"):
2485 if not frozenset(value) <= SET01:
2486 raise ValueError("B's coding contains unacceptable chars")
2487 return self._bits2octets(value)
2488 if value.endswith("'H"):
2492 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2494 if isinstance(value, binary_type):
2495 return (len(value) * 8, value)
2496 raise InvalidValueType((self.__class__, string_types, binary_type))
2497 if isinstance(value, tuple):
2500 isinstance(value[0], integer_types) and
2501 isinstance(value[1], binary_type)
2506 bit = self.specs.get(name)
2508 raise ObjUnknown("BitString value: %s" % name)
2511 return self._bits2octets("")
2512 bits = frozenset(bits)
2513 return self._bits2octets("".join(
2514 ("1" if bit in bits else "0")
2515 for bit in six_xrange(max(bits) + 1)
2517 if issubclass(value.__class__, BitString):
2519 raise InvalidValueType((self.__class__, binary_type, string_types))
2523 return self._value is not None
2525 def __getstate__(self):
2526 return BitStringState(
2540 self.tag_constructed,
2544 def __setstate__(self, state):
2545 super(BitString, self).__setstate__(state)
2546 self.specs = state.specs
2547 self._value = state.value
2548 self.tag = state.tag
2549 self._expl = state.expl
2550 self.default = state.default
2551 self.optional = state.optional
2552 self.offset = state.offset
2553 self.llen = state.llen
2554 self.vlen = state.vlen
2555 self.expl_lenindef = state.expl_lenindef
2556 self.lenindef = state.lenindef
2557 self.ber_encoded = state.ber_encoded
2558 self.tag_constructed = state.tag_constructed
2559 self.defined = state.defined
2562 self._assert_ready()
2563 for i in six_xrange(self._value[0]):
2568 self._assert_ready()
2569 return self._value[0]
2571 def __bytes__(self):
2572 self._assert_ready()
2573 return self._value[1]
2575 def __eq__(self, their):
2576 if isinstance(their, bytes):
2577 return self._value[1] == their
2578 if not issubclass(their.__class__, BitString):
2581 self._value == their._value and
2582 self.tag == their.tag and
2583 self._expl == their._expl
2588 return [name for name, bit in iteritems(self.specs) if self[bit]]
2598 return self.__class__(
2600 impl=self.tag if impl is None else impl,
2601 expl=self._expl if expl is None else expl,
2602 default=self.default if default is None else default,
2603 optional=self.optional if optional is None else optional,
2607 def __getitem__(self, key):
2608 if isinstance(key, int):
2609 bit_len, octets = self._value
2613 byte2int(memoryview(octets)[key // 8:]) >>
2616 if isinstance(key, string_types):
2617 value = self.specs.get(key)
2619 raise ObjUnknown("BitString value: %s" % key)
2621 raise InvalidValueType((int, str))
2624 self._assert_ready()
2625 bit_len, octets = self._value
2628 len_encode(len(octets) + 1),
2629 int2byte((8 - bit_len % 8) % 8),
2633 def _decode_chunk(self, lv, offset, decode_path):
2635 l, llen, v = len_decode(lv)
2636 except DecodeError as err:
2637 raise err.__class__(
2639 klass=self.__class__,
2640 decode_path=decode_path,
2644 raise NotEnoughData(
2645 "encoded length is longer than data",
2646 klass=self.__class__,
2647 decode_path=decode_path,
2651 raise NotEnoughData(
2653 klass=self.__class__,
2654 decode_path=decode_path,
2657 pad_size = byte2int(v)
2658 if l == 1 and pad_size != 0:
2660 "invalid empty value",
2661 klass=self.__class__,
2662 decode_path=decode_path,
2668 klass=self.__class__,
2669 decode_path=decode_path,
2672 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2675 klass=self.__class__,
2676 decode_path=decode_path,
2679 v, tail = v[:l], v[l:]
2680 obj = self.__class__(
2681 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2684 default=self.default,
2685 optional=self.optional,
2687 _decoded=(offset, llen, l),
2691 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2693 t, tlen, lv = tag_strip(tlv)
2694 except DecodeError as err:
2695 raise err.__class__(
2697 klass=self.__class__,
2698 decode_path=decode_path,
2702 if tag_only: # pragma: no cover
2704 return self._decode_chunk(lv, offset, decode_path)
2705 if t == self.tag_constructed:
2706 if not ctx.get("bered", False):
2708 "unallowed BER constructed encoding",
2709 klass=self.__class__,
2710 decode_path=decode_path,
2713 if tag_only: # pragma: no cover
2717 l, llen, v = len_decode(lv)
2718 except LenIndefForm:
2719 llen, l, v = 1, 0, lv[1:]
2721 except DecodeError as err:
2722 raise err.__class__(
2724 klass=self.__class__,
2725 decode_path=decode_path,
2729 raise NotEnoughData(
2730 "encoded length is longer than data",
2731 klass=self.__class__,
2732 decode_path=decode_path,
2735 if not lenindef and l == 0:
2736 raise NotEnoughData(
2738 klass=self.__class__,
2739 decode_path=decode_path,
2743 sub_offset = offset + tlen + llen
2747 if v[:EOC_LEN].tobytes() == EOC:
2754 "chunk out of bounds",
2755 klass=self.__class__,
2756 decode_path=decode_path + (str(len(chunks) - 1),),
2757 offset=chunks[-1].offset,
2759 sub_decode_path = decode_path + (str(len(chunks)),)
2761 chunk, v_tail = BitString().decode(
2764 decode_path=sub_decode_path,
2767 _ctx_immutable=False,
2771 "expected BitString encoded chunk",
2772 klass=self.__class__,
2773 decode_path=sub_decode_path,
2776 chunks.append(chunk)
2777 sub_offset += chunk.tlvlen
2778 vlen += chunk.tlvlen
2780 if len(chunks) == 0:
2783 klass=self.__class__,
2784 decode_path=decode_path,
2789 for chunk_i, chunk in enumerate(chunks[:-1]):
2790 if chunk.bit_len % 8 != 0:
2792 "BitString chunk is not multiple of 8 bits",
2793 klass=self.__class__,
2794 decode_path=decode_path + (str(chunk_i),),
2795 offset=chunk.offset,
2797 values.append(bytes(chunk))
2798 bit_len += chunk.bit_len
2799 chunk_last = chunks[-1]
2800 values.append(bytes(chunk_last))
2801 bit_len += chunk_last.bit_len
2802 obj = self.__class__(
2803 value=(bit_len, b"".join(values)),
2806 default=self.default,
2807 optional=self.optional,
2809 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2811 obj.lenindef = lenindef
2812 obj.ber_encoded = True
2813 return obj, (v[EOC_LEN:] if lenindef else v)
2815 klass=self.__class__,
2816 decode_path=decode_path,
2821 return pp_console_row(next(self.pps()))
2823 def pps(self, decode_path=()):
2827 bit_len, blob = self._value
2828 value = "%d bits" % bit_len
2829 if len(self.specs) > 0:
2830 blob = tuple(self.named)
2833 asn1_type_name=self.asn1_type_name,
2834 obj_name=self.__class__.__name__,
2835 decode_path=decode_path,
2838 optional=self.optional,
2839 default=self == self.default,
2840 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2841 expl=None if self._expl is None else tag_decode(self._expl),
2846 expl_offset=self.expl_offset if self.expled else None,
2847 expl_tlen=self.expl_tlen if self.expled else None,
2848 expl_llen=self.expl_llen if self.expled else None,
2849 expl_vlen=self.expl_vlen if self.expled else None,
2850 expl_lenindef=self.expl_lenindef,
2851 lenindef=self.lenindef,
2852 ber_encoded=self.ber_encoded,
2855 defined_by, defined = self.defined or (None, None)
2856 if defined_by is not None:
2858 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2860 for pp in self.pps_lenindef(decode_path):
2864 OctetStringState = namedtuple("OctetStringState", (
2881 ), **NAMEDTUPLE_KWARGS)
2884 class OctetString(Obj):
2885 """``OCTET STRING`` binary string type
2887 >>> s = OctetString(b"hello world")
2888 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2889 >>> s == OctetString(b"hello world")
2894 >>> OctetString(b"hello", bounds=(4, 4))
2895 Traceback (most recent call last):
2896 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2897 >>> OctetString(b"hell", bounds=(4, 4))
2898 OCTET STRING 4 bytes 68656c6c
2902 Pay attention that OCTET STRING can be encoded both in primitive
2903 and constructed forms. Decoder always checks constructed form tag
2904 additionally to specified primitive one. If BER decoding is
2905 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2906 of DER restrictions.
2908 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2909 tag_default = tag_encode(4)
2910 asn1_type_name = "OCTET STRING"
2924 :param value: set the value. Either binary type, or
2925 :py:class:`pyderasn.OctetString` object
2926 :param bounds: set ``(MIN, MAX)`` value size constraint.
2927 (-inf, +inf) by default
2928 :param bytes impl: override default tag with ``IMPLICIT`` one
2929 :param bytes expl: override default tag with ``EXPLICIT`` one
2930 :param default: set default value. Type same as in ``value``
2931 :param bool optional: is object ``OPTIONAL`` in sequence
2933 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2935 self._bound_min, self._bound_max = getattr(
2939 ) if bounds is None else bounds
2940 if value is not None:
2941 self._value = self._value_sanitize(value)
2942 if default is not None:
2943 default = self._value_sanitize(default)
2944 self.default = self.__class__(
2949 if self._value is None:
2950 self._value = default
2952 tag_klass, _, tag_num = tag_decode(self.tag)
2953 self.tag_constructed = tag_encode(
2955 form=TagFormConstructed,
2959 def _value_sanitize(self, value):
2960 if isinstance(value, binary_type):
2962 elif issubclass(value.__class__, OctetString):
2963 value = value._value
2965 raise InvalidValueType((self.__class__, bytes))
2966 if not self._bound_min <= len(value) <= self._bound_max:
2967 raise BoundsError(self._bound_min, len(value), self._bound_max)
2972 return self._value is not None
2974 def __getstate__(self):
2975 return OctetStringState(
2990 self.tag_constructed,
2994 def __setstate__(self, state):
2995 super(OctetString, self).__setstate__(state)
2996 self._value = state.value
2997 self._bound_min = state.bound_min
2998 self._bound_max = state.bound_max
2999 self.tag = state.tag
3000 self._expl = state.expl
3001 self.default = state.default
3002 self.optional = state.optional
3003 self.offset = state.offset
3004 self.llen = state.llen
3005 self.vlen = state.vlen
3006 self.expl_lenindef = state.expl_lenindef
3007 self.lenindef = state.lenindef
3008 self.ber_encoded = state.ber_encoded
3009 self.tag_constructed = state.tag_constructed
3010 self.defined = state.defined
3012 def __bytes__(self):
3013 self._assert_ready()
3016 def __eq__(self, their):
3017 if isinstance(their, binary_type):
3018 return self._value == their
3019 if not issubclass(their.__class__, OctetString):
3022 self._value == their._value and
3023 self.tag == their.tag and
3024 self._expl == their._expl
3027 def __lt__(self, their):
3028 return self._value < their._value
3039 return self.__class__(
3042 (self._bound_min, self._bound_max)
3043 if bounds is None else bounds
3045 impl=self.tag if impl is None else impl,
3046 expl=self._expl if expl is None else expl,
3047 default=self.default if default is None else default,
3048 optional=self.optional if optional is None else optional,
3052 self._assert_ready()
3055 len_encode(len(self._value)),
3059 def _decode_chunk(self, lv, offset, decode_path, ctx):
3061 l, llen, v = len_decode(lv)
3062 except DecodeError as err:
3063 raise err.__class__(
3065 klass=self.__class__,
3066 decode_path=decode_path,
3070 raise NotEnoughData(
3071 "encoded length is longer than data",
3072 klass=self.__class__,
3073 decode_path=decode_path,
3076 v, tail = v[:l], v[l:]
3078 obj = self.__class__(
3080 bounds=(self._bound_min, self._bound_max),
3083 default=self.default,
3084 optional=self.optional,
3085 _decoded=(offset, llen, l),
3088 except DecodeError as err:
3091 klass=self.__class__,
3092 decode_path=decode_path,
3095 except BoundsError as err:
3098 klass=self.__class__,
3099 decode_path=decode_path,
3104 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3106 t, tlen, lv = tag_strip(tlv)
3107 except DecodeError as err:
3108 raise err.__class__(
3110 klass=self.__class__,
3111 decode_path=decode_path,
3117 return self._decode_chunk(lv, offset, decode_path, ctx)
3118 if t == self.tag_constructed:
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)
3215 klass=self.__class__,
3216 decode_path=decode_path,
3221 return pp_console_row(next(self.pps()))
3223 def pps(self, decode_path=()):
3226 asn1_type_name=self.asn1_type_name,
3227 obj_name=self.__class__.__name__,
3228 decode_path=decode_path,
3229 value=("%d bytes" % len(self._value)) if self.ready else None,
3230 blob=self._value if self.ready else None,
3231 optional=self.optional,
3232 default=self == self.default,
3233 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3234 expl=None if self._expl is None else tag_decode(self._expl),
3239 expl_offset=self.expl_offset if self.expled else None,
3240 expl_tlen=self.expl_tlen if self.expled else None,
3241 expl_llen=self.expl_llen if self.expled else None,
3242 expl_vlen=self.expl_vlen if self.expled else None,
3243 expl_lenindef=self.expl_lenindef,
3244 lenindef=self.lenindef,
3245 ber_encoded=self.ber_encoded,
3248 defined_by, defined = self.defined or (None, None)
3249 if defined_by is not None:
3251 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3253 for pp in self.pps_lenindef(decode_path):
3257 NullState = namedtuple("NullState", (
3269 ), **NAMEDTUPLE_KWARGS)
3273 """``NULL`` null object
3281 tag_default = tag_encode(5)
3282 asn1_type_name = "NULL"
3286 value=None, # unused, but Sequence passes it
3293 :param bytes impl: override default tag with ``IMPLICIT`` one
3294 :param bytes expl: override default tag with ``EXPLICIT`` one
3295 :param bool optional: is object ``OPTIONAL`` in sequence
3297 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3304 def __getstate__(self):
3319 def __setstate__(self, state):
3320 super(Null, self).__setstate__(state)
3321 self.tag = state.tag
3322 self._expl = state.expl
3323 self.default = state.default
3324 self.optional = state.optional
3325 self.offset = state.offset
3326 self.llen = state.llen
3327 self.vlen = state.vlen
3328 self.expl_lenindef = state.expl_lenindef
3329 self.lenindef = state.lenindef
3330 self.ber_encoded = state.ber_encoded
3332 def __eq__(self, their):
3333 if not issubclass(their.__class__, Null):
3336 self.tag == their.tag and
3337 self._expl == their._expl
3347 return self.__class__(
3348 impl=self.tag if impl is None else impl,
3349 expl=self._expl if expl is None else expl,
3350 optional=self.optional if optional is None else optional,
3354 return self.tag + len_encode(0)
3356 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3358 t, _, lv = tag_strip(tlv)
3359 except DecodeError as err:
3360 raise err.__class__(
3362 klass=self.__class__,
3363 decode_path=decode_path,
3368 klass=self.__class__,
3369 decode_path=decode_path,
3372 if tag_only: # pragma: no cover
3375 l, _, v = len_decode(lv)
3376 except DecodeError as err:
3377 raise err.__class__(
3379 klass=self.__class__,
3380 decode_path=decode_path,
3384 raise InvalidLength(
3385 "Null must have zero length",
3386 klass=self.__class__,
3387 decode_path=decode_path,
3390 obj = self.__class__(
3393 optional=self.optional,
3394 _decoded=(offset, 1, 0),
3399 return pp_console_row(next(self.pps()))
3401 def pps(self, decode_path=()):
3404 asn1_type_name=self.asn1_type_name,
3405 obj_name=self.__class__.__name__,
3406 decode_path=decode_path,
3407 optional=self.optional,
3408 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3409 expl=None if self._expl is None else tag_decode(self._expl),
3414 expl_offset=self.expl_offset if self.expled else None,
3415 expl_tlen=self.expl_tlen if self.expled else None,
3416 expl_llen=self.expl_llen if self.expled else None,
3417 expl_vlen=self.expl_vlen if self.expled else None,
3418 expl_lenindef=self.expl_lenindef,
3421 for pp in self.pps_lenindef(decode_path):
3425 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3439 ), **NAMEDTUPLE_KWARGS)
3442 class ObjectIdentifier(Obj):
3443 """``OBJECT IDENTIFIER`` OID type
3445 >>> oid = ObjectIdentifier((1, 2, 3))
3446 OBJECT IDENTIFIER 1.2.3
3447 >>> oid == ObjectIdentifier("1.2.3")
3453 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3454 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3456 >>> str(ObjectIdentifier((3, 1)))
3457 Traceback (most recent call last):
3458 pyderasn.InvalidOID: unacceptable first arc value
3460 __slots__ = ("defines",)
3461 tag_default = tag_encode(6)
3462 asn1_type_name = "OBJECT IDENTIFIER"
3475 :param value: set the value. Either tuples of integers,
3476 string of "."-concatenated integers, or
3477 :py:class:`pyderasn.ObjectIdentifier` object
3478 :param defines: sequence of tuples. Each tuple has two elements.
3479 First one is relative to current one decode
3480 path, aiming to the field defined by that OID.
3481 Read about relative path in
3482 :py:func:`pyderasn.abs_decode_path`. Second
3483 tuple element is ``{OID: pyderasn.Obj()}``
3484 dictionary, mapping between current OID value
3485 and structure applied to defined field.
3486 :ref:`Read about DEFINED BY <definedby>`
3487 :param bytes impl: override default tag with ``IMPLICIT`` one
3488 :param bytes expl: override default tag with ``EXPLICIT`` one
3489 :param default: set default value. Type same as in ``value``
3490 :param bool optional: is object ``OPTIONAL`` in sequence
3492 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3494 if value is not None:
3495 self._value = self._value_sanitize(value)
3496 if default is not None:
3497 default = self._value_sanitize(default)
3498 self.default = self.__class__(
3503 if self._value is None:
3504 self._value = default
3505 self.defines = defines
3507 def __add__(self, their):
3508 if isinstance(their, self.__class__):
3509 return self.__class__(self._value + their._value)
3510 if isinstance(their, tuple):
3511 return self.__class__(self._value + their)
3512 raise InvalidValueType((self.__class__, tuple))
3514 def _value_sanitize(self, value):
3515 if issubclass(value.__class__, ObjectIdentifier):
3517 if isinstance(value, string_types):
3519 value = tuple(pureint(arc) for arc in value.split("."))
3521 raise InvalidOID("unacceptable arcs values")
3522 if isinstance(value, tuple):
3524 raise InvalidOID("less than 2 arcs")
3525 first_arc = value[0]
3526 if first_arc in (0, 1):
3527 if not (0 <= value[1] <= 39):
3528 raise InvalidOID("second arc is too wide")
3529 elif first_arc == 2:
3532 raise InvalidOID("unacceptable first arc value")
3533 if not all(arc >= 0 for arc in value):
3534 raise InvalidOID("negative arc value")
3536 raise InvalidValueType((self.__class__, str, tuple))
3540 return self._value is not None
3542 def __getstate__(self):
3543 return ObjectIdentifierState(
3559 def __setstate__(self, state):
3560 super(ObjectIdentifier, self).__setstate__(state)
3561 self._value = state.value
3562 self.tag = state.tag
3563 self._expl = state.expl
3564 self.default = state.default
3565 self.optional = state.optional
3566 self.offset = state.offset
3567 self.llen = state.llen
3568 self.vlen = state.vlen
3569 self.expl_lenindef = state.expl_lenindef
3570 self.lenindef = state.lenindef
3571 self.ber_encoded = state.ber_encoded
3572 self.defines = state.defines
3575 self._assert_ready()
3576 return iter(self._value)
3579 return ".".join(str(arc) for arc in self._value or ())
3582 self._assert_ready()
3585 bytes(self._expl or b"") +
3586 str(self._value).encode("ascii"),
3589 def __eq__(self, their):
3590 if isinstance(their, tuple):
3591 return self._value == their
3592 if not issubclass(their.__class__, ObjectIdentifier):
3595 self.tag == their.tag and
3596 self._expl == their._expl and
3597 self._value == their._value
3600 def __lt__(self, their):
3601 return self._value < their._value
3612 return self.__class__(
3614 defines=self.defines if defines is None else defines,
3615 impl=self.tag if impl is None else impl,
3616 expl=self._expl if expl is None else expl,
3617 default=self.default if default is None else default,
3618 optional=self.optional if optional is None else optional,
3622 self._assert_ready()
3624 first_value = value[1]
3625 first_arc = value[0]
3628 elif first_arc == 1:
3630 elif first_arc == 2:
3632 else: # pragma: no cover
3633 raise RuntimeError("invalid arc is stored")
3634 octets = [zero_ended_encode(first_value)]
3635 for arc in value[2:]:
3636 octets.append(zero_ended_encode(arc))
3637 v = b"".join(octets)
3638 return b"".join((self.tag, len_encode(len(v)), v))
3640 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3642 t, _, lv = tag_strip(tlv)
3643 except DecodeError as err:
3644 raise err.__class__(
3646 klass=self.__class__,
3647 decode_path=decode_path,
3652 klass=self.__class__,
3653 decode_path=decode_path,
3656 if tag_only: # pragma: no cover
3659 l, llen, v = len_decode(lv)
3660 except DecodeError as err:
3661 raise err.__class__(
3663 klass=self.__class__,
3664 decode_path=decode_path,
3668 raise NotEnoughData(
3669 "encoded length is longer than data",
3670 klass=self.__class__,
3671 decode_path=decode_path,
3675 raise NotEnoughData(
3677 klass=self.__class__,
3678 decode_path=decode_path,
3681 v, tail = v[:l], v[l:]
3688 octet = indexbytes(v, i)
3689 if i == 0 and octet == 0x80:
3690 if ctx.get("bered", False):
3693 raise DecodeError("non normalized arc encoding")
3694 arc = (arc << 7) | (octet & 0x7F)
3695 if octet & 0x80 == 0:
3703 klass=self.__class__,
3704 decode_path=decode_path,
3708 second_arc = arcs[0]
3709 if 0 <= second_arc <= 39:
3711 elif 40 <= second_arc <= 79:
3717 obj = self.__class__(
3718 value=tuple([first_arc, second_arc] + arcs[1:]),
3721 default=self.default,
3722 optional=self.optional,
3723 _decoded=(offset, llen, l),
3726 obj.ber_encoded = True
3730 return pp_console_row(next(self.pps()))
3732 def pps(self, decode_path=()):
3735 asn1_type_name=self.asn1_type_name,
3736 obj_name=self.__class__.__name__,
3737 decode_path=decode_path,
3738 value=str(self) if self.ready else None,
3739 optional=self.optional,
3740 default=self == self.default,
3741 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3742 expl=None if self._expl is None else tag_decode(self._expl),
3747 expl_offset=self.expl_offset if self.expled else None,
3748 expl_tlen=self.expl_tlen if self.expled else None,
3749 expl_llen=self.expl_llen if self.expled else None,
3750 expl_vlen=self.expl_vlen if self.expled else None,
3751 expl_lenindef=self.expl_lenindef,
3752 ber_encoded=self.ber_encoded,
3755 for pp in self.pps_lenindef(decode_path):
3759 class Enumerated(Integer):
3760 """``ENUMERATED`` integer type
3762 This type is identical to :py:class:`pyderasn.Integer`, but requires
3763 schema to be specified and does not accept values missing from it.
3766 tag_default = tag_encode(10)
3767 asn1_type_name = "ENUMERATED"
3778 bounds=None, # dummy argument, workability for Integer.decode
3780 super(Enumerated, self).__init__(
3781 value, bounds, impl, expl, default, optional, _specs, _decoded,
3783 if len(self.specs) == 0:
3784 raise ValueError("schema must be specified")
3786 def _value_sanitize(self, value):
3787 if isinstance(value, self.__class__):
3788 value = value._value
3789 elif isinstance(value, integer_types):
3790 for _value in itervalues(self.specs):
3795 "unknown integer value: %s" % value,
3796 klass=self.__class__,
3798 elif isinstance(value, string_types):
3799 value = self.specs.get(value)
3801 raise ObjUnknown("integer value: %s" % value)
3803 raise InvalidValueType((self.__class__, int, str))
3815 return self.__class__(
3817 impl=self.tag if impl is None else impl,
3818 expl=self._expl if expl is None else expl,
3819 default=self.default if default is None else default,
3820 optional=self.optional if optional is None else optional,
3825 def escape_control_unicode(c):
3826 if unicat(c)[0] == "C":
3827 c = repr(c).lstrip("u").strip("'")
3831 class CommonString(OctetString):
3832 """Common class for all strings
3834 Everything resembles :py:class:`pyderasn.OctetString`, except
3835 ability to deal with unicode text strings.
3837 >>> hexenc("привет мир".encode("utf-8"))
3838 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3839 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3841 >>> s = UTF8String("привет мир")
3842 UTF8String UTF8String привет мир
3844 'привет мир'
3845 >>> hexenc(bytes(s))
3846 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3848 >>> PrintableString("привет мир")
3849 Traceback (most recent call last):
3850 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3852 >>> BMPString("ада", bounds=(2, 2))
3853 Traceback (most recent call last):
3854 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3855 >>> s = BMPString("ад", bounds=(2, 2))
3858 >>> hexenc(bytes(s))
3866 * - :py:class:`pyderasn.UTF8String`
3868 * - :py:class:`pyderasn.NumericString`
3870 * - :py:class:`pyderasn.PrintableString`
3872 * - :py:class:`pyderasn.TeletexString`
3874 * - :py:class:`pyderasn.T61String`
3876 * - :py:class:`pyderasn.VideotexString`
3878 * - :py:class:`pyderasn.IA5String`
3880 * - :py:class:`pyderasn.GraphicString`
3882 * - :py:class:`pyderasn.VisibleString`
3884 * - :py:class:`pyderasn.ISO646String`
3886 * - :py:class:`pyderasn.GeneralString`
3888 * - :py:class:`pyderasn.UniversalString`
3890 * - :py:class:`pyderasn.BMPString`
3895 def _value_sanitize(self, value):
3897 value_decoded = None
3898 if isinstance(value, self.__class__):
3899 value_raw = value._value
3900 elif isinstance(value, text_type):
3901 value_decoded = value
3902 elif isinstance(value, binary_type):
3905 raise InvalidValueType((self.__class__, text_type, binary_type))
3908 value_decoded.encode(self.encoding)
3909 if value_raw is None else value_raw
3912 value_raw.decode(self.encoding)
3913 if value_decoded is None else value_decoded
3915 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3916 raise DecodeError(str(err))
3917 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3925 def __eq__(self, their):
3926 if isinstance(their, binary_type):
3927 return self._value == their
3928 if isinstance(their, text_type):
3929 return self._value == their.encode(self.encoding)
3930 if not isinstance(their, self.__class__):
3933 self._value == their._value and
3934 self.tag == their.tag and
3935 self._expl == their._expl
3938 def __unicode__(self):
3940 return self._value.decode(self.encoding)
3941 return text_type(self._value)
3944 return pp_console_row(next(self.pps(no_unicode=PY2)))
3946 def pps(self, decode_path=(), no_unicode=False):
3950 hexenc(bytes(self)) if no_unicode else
3951 "".join(escape_control_unicode(c) for c in self.__unicode__())
3955 asn1_type_name=self.asn1_type_name,
3956 obj_name=self.__class__.__name__,
3957 decode_path=decode_path,
3959 optional=self.optional,
3960 default=self == self.default,
3961 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3962 expl=None if self._expl is None else tag_decode(self._expl),
3967 expl_offset=self.expl_offset if self.expled else None,
3968 expl_tlen=self.expl_tlen if self.expled else None,
3969 expl_llen=self.expl_llen if self.expled else None,
3970 expl_vlen=self.expl_vlen if self.expled else None,
3971 expl_lenindef=self.expl_lenindef,
3972 ber_encoded=self.ber_encoded,
3975 for pp in self.pps_lenindef(decode_path):
3979 class UTF8String(CommonString):
3981 tag_default = tag_encode(12)
3983 asn1_type_name = "UTF8String"
3986 class AllowableCharsMixin(object):
3988 def allowable_chars(self):
3990 return self._allowable_chars
3991 return frozenset(six_unichr(c) for c in self._allowable_chars)
3994 class NumericString(AllowableCharsMixin, CommonString):
3997 Its value is properly sanitized: only ASCII digits with spaces can
4000 >>> NumericString().allowable_chars
4001 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4004 tag_default = tag_encode(18)
4006 asn1_type_name = "NumericString"
4007 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4009 def _value_sanitize(self, value):
4010 value = super(NumericString, self)._value_sanitize(value)
4011 if not frozenset(value) <= self._allowable_chars:
4012 raise DecodeError("non-numeric value")
4016 PrintableStringState = namedtuple(
4017 "PrintableStringState",
4018 OctetStringState._fields + ("allowable_chars",),
4023 class PrintableString(AllowableCharsMixin, CommonString):
4026 Its value is properly sanitized: see X.680 41.4 table 10.
4028 >>> PrintableString().allowable_chars
4029 frozenset([' ', "'", ..., 'z'])
4030 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4031 PrintableString PrintableString foo*bar
4032 >>> obj.allow_asterisk, obj.allow_ampersand
4036 tag_default = tag_encode(19)
4038 asn1_type_name = "PrintableString"
4039 _allowable_chars = frozenset(
4040 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4042 _asterisk = frozenset("*".encode("ascii"))
4043 _ampersand = frozenset("&".encode("ascii"))
4055 allow_asterisk=False,
4056 allow_ampersand=False,
4059 :param allow_asterisk: allow asterisk character
4060 :param allow_ampersand: allow ampersand character
4063 self._allowable_chars |= self._asterisk
4065 self._allowable_chars |= self._ampersand
4066 super(PrintableString, self).__init__(
4067 value, bounds, impl, expl, default, optional, _decoded, ctx,
4071 def allow_asterisk(self):
4072 """Is asterisk character allowed?
4074 return self._asterisk <= self._allowable_chars
4077 def allow_ampersand(self):
4078 """Is ampersand character allowed?
4080 return self._ampersand <= self._allowable_chars
4082 def _value_sanitize(self, value):
4083 value = super(PrintableString, self)._value_sanitize(value)
4084 if not frozenset(value) <= self._allowable_chars:
4085 raise DecodeError("non-printable value")
4088 def __getstate__(self):
4089 return PrintableStringState(
4090 *super(PrintableString, self).__getstate__(),
4091 **{"allowable_chars": self._allowable_chars}
4094 def __setstate__(self, state):
4095 super(PrintableString, self).__setstate__(state)
4096 self._allowable_chars = state.allowable_chars
4107 return self.__class__(
4110 (self._bound_min, self._bound_max)
4111 if bounds is None else bounds
4113 impl=self.tag if impl is None else impl,
4114 expl=self._expl if expl is None else expl,
4115 default=self.default if default is None else default,
4116 optional=self.optional if optional is None else optional,
4117 allow_asterisk=self.allow_asterisk,
4118 allow_ampersand=self.allow_ampersand,
4122 class TeletexString(CommonString):
4124 tag_default = tag_encode(20)
4126 asn1_type_name = "TeletexString"
4129 class T61String(TeletexString):
4131 asn1_type_name = "T61String"
4134 class VideotexString(CommonString):
4136 tag_default = tag_encode(21)
4137 encoding = "iso-8859-1"
4138 asn1_type_name = "VideotexString"
4141 class IA5String(CommonString):
4143 tag_default = tag_encode(22)
4145 asn1_type_name = "IA5"
4148 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4149 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4150 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4153 class VisibleString(CommonString):
4155 tag_default = tag_encode(26)
4157 asn1_type_name = "VisibleString"
4160 UTCTimeState = namedtuple(
4162 OctetStringState._fields + ("ber_raw",),
4167 def str_to_time_fractions(value):
4169 year, v = (v // 10**10), (v % 10**10)
4170 month, v = (v // 10**8), (v % 10**8)
4171 day, v = (v // 10**6), (v % 10**6)
4172 hour, v = (v // 10**4), (v % 10**4)
4173 minute, second = (v // 100), (v % 100)
4174 return year, month, day, hour, minute, second
4177 class UTCTime(VisibleString):
4178 """``UTCTime`` datetime type
4180 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4181 UTCTime UTCTime 2017-09-30T22:07:50
4187 datetime.datetime(2017, 9, 30, 22, 7, 50)
4188 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4189 datetime.datetime(1957, 9, 30, 22, 7, 50)
4193 Pay attention that UTCTime can not hold full year, so all years
4194 having < 50 years are treated as 20xx, 19xx otherwise, according
4195 to X.509 recommendation.
4199 No strict validation of UTC offsets are made, but very crude:
4201 * minutes are not exceeding 60
4202 * offset value is not exceeding 14 hours
4204 __slots__ = ("_ber_raw",)
4205 tag_default = tag_encode(23)
4207 asn1_type_name = "UTCTime"
4217 bounds=None, # dummy argument, workability for OctetString.decode
4221 :param value: set the value. Either datetime type, or
4222 :py:class:`pyderasn.UTCTime` object
4223 :param bytes impl: override default tag with ``IMPLICIT`` one
4224 :param bytes expl: override default tag with ``EXPLICIT`` one
4225 :param default: set default value. Type same as in ``value``
4226 :param bool optional: is object ``OPTIONAL`` in sequence
4228 super(UTCTime, self).__init__(
4229 None, None, impl, expl, None, optional, _decoded, ctx,
4232 self._ber_raw = None
4233 if value is not None:
4234 self._value, self._ber_raw = self._value_sanitize(value, ctx)
4235 self.ber_encoded = self._ber_raw is not None
4236 if default is not None:
4237 default, _ = self._value_sanitize(default)
4238 self.default = self.__class__(
4243 if self._value is None:
4244 self._value = default
4246 self.optional = optional
4248 def _strptime_bered(self, value):
4249 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4252 raise ValueError("no timezone")
4253 year += 2000 if year < 50 else 1900
4254 decoded = datetime(year, month, day, hour, minute)
4256 if value[-1] == "Z":
4260 raise ValueError("invalid UTC offset")
4261 if value[-5] == "-":
4263 elif value[-5] == "+":
4266 raise ValueError("invalid UTC offset")
4267 v = pureint(value[-4:])
4268 offset, v = (60 * (v % 100)), v // 100
4270 raise ValueError("invalid UTC offset minutes")
4272 if offset > 14 * 3600:
4273 raise ValueError("too big UTC offset")
4277 return offset, decoded
4279 raise ValueError("invalid UTC offset seconds")
4280 seconds = pureint(value)
4282 raise ValueError("invalid seconds value")
4283 return offset, decoded + timedelta(seconds=seconds)
4285 def _strptime(self, value):
4286 # datetime.strptime's format: %y%m%d%H%M%SZ
4287 if len(value) != LEN_YYMMDDHHMMSSZ:
4288 raise ValueError("invalid UTCTime length")
4289 if value[-1] != "Z":
4290 raise ValueError("non UTC timezone")
4291 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4292 year += 2000 if year < 50 else 1900
4293 return datetime(year, month, day, hour, minute, second)
4295 def _dt_sanitize(self, value):
4296 if value.year < 1950 or value.year > 2049:
4297 raise ValueError("UTCTime can hold only 1950-2049 years")
4298 return value.replace(microsecond=0)
4300 def _value_sanitize(self, value, ctx=None):
4301 if isinstance(value, binary_type):
4303 value_decoded = value.decode("ascii")
4304 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4305 raise DecodeError("invalid UTCTime encoding: %r" % err)
4308 return self._strptime(value_decoded), None
4309 except (TypeError, ValueError) as _err:
4311 if (ctx is not None) and ctx.get("bered", False):
4313 offset, _value = self._strptime_bered(value_decoded)
4314 _value = _value - timedelta(seconds=offset)
4315 return self._dt_sanitize(_value), value_decoded
4316 except (TypeError, ValueError, OverflowError) as _err:
4319 "invalid %s format: %r" % (self.asn1_type_name, err),
4320 klass=self.__class__,
4322 if isinstance(value, self.__class__):
4323 return value._value, None
4324 if isinstance(value, datetime):
4325 return self._dt_sanitize(value), None
4326 raise InvalidValueType((self.__class__, datetime))
4328 def _pp_value(self):
4330 value = self._value.isoformat()
4331 if self.ber_encoded:
4332 value += " (%s)" % self._ber_raw
4335 def __unicode__(self):
4337 value = self._value.isoformat()
4338 if self.ber_encoded:
4339 value += " (%s)" % self._ber_raw
4341 return text_type(self._pp_value())
4343 def __getstate__(self):
4344 return UTCTimeState(
4345 *super(UTCTime, self).__getstate__(),
4346 **{"ber_raw": self._ber_raw}
4349 def __setstate__(self, state):
4350 super(UTCTime, self).__setstate__(state)
4351 self._ber_raw = state.ber_raw
4353 def __bytes__(self):
4354 self._assert_ready()
4355 return self._encode_time()
4357 def __eq__(self, their):
4358 if isinstance(their, binary_type):
4359 return self._encode_time() == their
4360 if isinstance(their, datetime):
4361 return self.todatetime() == their
4362 if not isinstance(their, self.__class__):
4365 self._value == their._value and
4366 self.tag == their.tag and
4367 self._expl == their._expl
4370 def _encode_time(self):
4371 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4374 self._assert_ready()
4375 value = self._encode_time()
4376 return b"".join((self.tag, len_encode(len(value)), value))
4378 def todatetime(self):
4382 return pp_console_row(next(self.pps()))
4384 def pps(self, decode_path=()):
4387 asn1_type_name=self.asn1_type_name,
4388 obj_name=self.__class__.__name__,
4389 decode_path=decode_path,
4390 value=self._pp_value(),
4391 optional=self.optional,
4392 default=self == self.default,
4393 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4394 expl=None if self._expl is None else tag_decode(self._expl),
4399 expl_offset=self.expl_offset if self.expled else None,
4400 expl_tlen=self.expl_tlen if self.expled else None,
4401 expl_llen=self.expl_llen if self.expled else None,
4402 expl_vlen=self.expl_vlen if self.expled else None,
4403 expl_lenindef=self.expl_lenindef,
4404 ber_encoded=self.ber_encoded,
4407 for pp in self.pps_lenindef(decode_path):
4411 class GeneralizedTime(UTCTime):
4412 """``GeneralizedTime`` datetime type
4414 This type is similar to :py:class:`pyderasn.UTCTime`.
4416 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4417 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4419 '20170930220750.000123Z'
4420 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4421 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4425 Only microsecond fractions are supported in DER encoding.
4426 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4427 higher precision values.
4431 BER encoded data can loss information (accuracy) during decoding
4432 because of float transformations.
4436 Local times (without explicit timezone specification) are treated
4437 as UTC one, no transformations are made.
4441 Zero year is unsupported.
4444 tag_default = tag_encode(24)
4445 asn1_type_name = "GeneralizedTime"
4447 def _dt_sanitize(self, value):
4450 def _strptime_bered(self, value):
4451 if len(value) < 4 + 3 * 2:
4452 raise ValueError("invalid GeneralizedTime")
4453 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4454 decoded = datetime(year, month, day, hour)
4455 offset, value = 0, value[10:]
4457 return offset, decoded
4458 if value[-1] == "Z":
4461 for char, sign in (("-", -1), ("+", 1)):
4462 idx = value.rfind(char)
4465 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4466 v = pureint(offset_raw)
4467 if len(offset_raw) == 4:
4468 offset, v = (60 * (v % 100)), v // 100
4470 raise ValueError("invalid UTC offset minutes")
4471 elif len(offset_raw) == 2:
4474 raise ValueError("invalid UTC offset")
4476 if offset > 14 * 3600:
4477 raise ValueError("too big UTC offset")
4481 return offset, decoded
4482 if value[0] in DECIMAL_SIGNS:
4484 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4487 raise ValueError("stripped minutes")
4488 decoded += timedelta(seconds=60 * pureint(value[:2]))
4491 return offset, decoded
4492 if value[0] in DECIMAL_SIGNS:
4494 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4497 raise ValueError("stripped seconds")
4498 decoded += timedelta(seconds=pureint(value[:2]))
4501 return offset, decoded
4502 if value[0] not in DECIMAL_SIGNS:
4503 raise ValueError("invalid format after seconds")
4505 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4508 def _strptime(self, value):
4510 if l == LEN_YYYYMMDDHHMMSSZ:
4511 # datetime.strptime's format: %Y%m%d%H%M%SZ
4512 if value[-1] != "Z":
4513 raise ValueError("non UTC timezone")
4514 return datetime(*str_to_time_fractions(value[:-1]))
4515 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4516 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4517 if value[-1] != "Z":
4518 raise ValueError("non UTC timezone")
4519 if value[14] != ".":
4520 raise ValueError("no fractions separator")
4523 raise ValueError("trailing zero")
4526 raise ValueError("only microsecond fractions are supported")
4527 us = pureint(us + ("0" * (6 - us_len)))
4528 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4529 return datetime(year, month, day, hour, minute, second, us)
4530 raise ValueError("invalid GeneralizedTime length")
4532 def _encode_time(self):
4534 encoded = value.strftime("%Y%m%d%H%M%S")
4535 if value.microsecond > 0:
4536 encoded += (".%06d" % value.microsecond).rstrip("0")
4537 return (encoded + "Z").encode("ascii")
4540 class GraphicString(CommonString):
4542 tag_default = tag_encode(25)
4543 encoding = "iso-8859-1"
4544 asn1_type_name = "GraphicString"
4547 class ISO646String(VisibleString):
4549 asn1_type_name = "ISO646String"
4552 class GeneralString(CommonString):
4554 tag_default = tag_encode(27)
4555 encoding = "iso-8859-1"
4556 asn1_type_name = "GeneralString"
4559 class UniversalString(CommonString):
4561 tag_default = tag_encode(28)
4562 encoding = "utf-32-be"
4563 asn1_type_name = "UniversalString"
4566 class BMPString(CommonString):
4568 tag_default = tag_encode(30)
4569 encoding = "utf-16-be"
4570 asn1_type_name = "BMPString"
4573 ChoiceState = namedtuple("ChoiceState", (
4587 ), **NAMEDTUPLE_KWARGS)
4591 """``CHOICE`` special type
4595 class GeneralName(Choice):
4597 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4598 ("dNSName", IA5String(impl=tag_ctxp(2))),
4601 >>> gn = GeneralName()
4603 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4604 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4605 >>> gn["dNSName"] = IA5String("bar.baz")
4606 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4607 >>> gn["rfc822Name"]
4610 [2] IA5String IA5 bar.baz
4613 >>> gn.value == gn["dNSName"]
4616 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4618 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4619 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4621 __slots__ = ("specs",)
4623 asn1_type_name = "CHOICE"
4636 :param value: set the value. Either ``(choice, value)`` tuple, or
4637 :py:class:`pyderasn.Choice` object
4638 :param bytes impl: can not be set, do **not** use it
4639 :param bytes expl: override default tag with ``EXPLICIT`` one
4640 :param default: set default value. Type same as in ``value``
4641 :param bool optional: is object ``OPTIONAL`` in sequence
4643 if impl is not None:
4644 raise ValueError("no implicit tag allowed for CHOICE")
4645 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4647 schema = getattr(self, "schema", ())
4648 if len(schema) == 0:
4649 raise ValueError("schema must be specified")
4651 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4654 if value is not None:
4655 self._value = self._value_sanitize(value)
4656 if default is not None:
4657 default_value = self._value_sanitize(default)
4658 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4659 default_obj.specs = self.specs
4660 default_obj._value = default_value
4661 self.default = default_obj
4663 self._value = copy(default_obj._value)
4665 def _value_sanitize(self, value):
4666 if isinstance(value, tuple) and len(value) == 2:
4668 spec = self.specs.get(choice)
4670 raise ObjUnknown(choice)
4671 if not isinstance(obj, spec.__class__):
4672 raise InvalidValueType((spec,))
4673 return (choice, spec(obj))
4674 if isinstance(value, self.__class__):
4676 raise InvalidValueType((self.__class__, tuple))
4680 return self._value is not None and self._value[1].ready
4684 return self.expl_lenindef or (
4685 (self._value is not None) and
4686 self._value[1].bered
4689 def __getstate__(self):
4706 def __setstate__(self, state):
4707 super(Choice, self).__setstate__(state)
4708 self.specs = state.specs
4709 self._value = state.value
4710 self._expl = state.expl
4711 self.default = state.default
4712 self.optional = state.optional
4713 self.offset = state.offset
4714 self.llen = state.llen
4715 self.vlen = state.vlen
4716 self.expl_lenindef = state.expl_lenindef
4717 self.lenindef = state.lenindef
4718 self.ber_encoded = state.ber_encoded
4720 def __eq__(self, their):
4721 if isinstance(their, tuple) and len(their) == 2:
4722 return self._value == their
4723 if not isinstance(their, self.__class__):
4726 self.specs == their.specs and
4727 self._value == their._value
4737 return self.__class__(
4740 expl=self._expl if expl is None else expl,
4741 default=self.default if default is None else default,
4742 optional=self.optional if optional is None else optional,
4747 self._assert_ready()
4748 return self._value[0]
4752 self._assert_ready()
4753 return self._value[1]
4755 def __getitem__(self, key):
4756 if key not in self.specs:
4757 raise ObjUnknown(key)
4758 if self._value is None:
4760 choice, value = self._value
4765 def __setitem__(self, key, value):
4766 spec = self.specs.get(key)
4768 raise ObjUnknown(key)
4769 if not isinstance(value, spec.__class__):
4770 raise InvalidValueType((spec.__class__,))
4771 self._value = (key, spec(value))
4779 return self._value[1].decoded if self.ready else False
4782 self._assert_ready()
4783 return self._value[1].encode()
4785 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4786 for choice, spec in iteritems(self.specs):
4787 sub_decode_path = decode_path + (choice,)
4793 decode_path=sub_decode_path,
4796 _ctx_immutable=False,
4803 klass=self.__class__,
4804 decode_path=decode_path,
4807 if tag_only: # pragma: no cover
4809 value, tail = spec.decode(
4813 decode_path=sub_decode_path,
4815 _ctx_immutable=False,
4817 obj = self.__class__(
4820 default=self.default,
4821 optional=self.optional,
4822 _decoded=(offset, 0, value.fulllen),
4824 obj._value = (choice, value)
4828 value = pp_console_row(next(self.pps()))
4830 value = "%s[%r]" % (value, self.value)
4833 def pps(self, decode_path=()):
4836 asn1_type_name=self.asn1_type_name,
4837 obj_name=self.__class__.__name__,
4838 decode_path=decode_path,
4839 value=self.choice if self.ready else None,
4840 optional=self.optional,
4841 default=self == self.default,
4842 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4843 expl=None if self._expl is None else tag_decode(self._expl),
4848 expl_lenindef=self.expl_lenindef,
4852 yield self.value.pps(decode_path=decode_path + (self.choice,))
4853 for pp in self.pps_lenindef(decode_path):
4857 class PrimitiveTypes(Choice):
4858 """Predefined ``CHOICE`` for all generic primitive types
4860 It could be useful for general decoding of some unspecified values:
4862 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4863 OCTET STRING 3 bytes 666f6f
4864 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4868 schema = tuple((klass.__name__, klass()) for klass in (
4892 AnyState = namedtuple("AnyState", (
4905 ), **NAMEDTUPLE_KWARGS)
4909 """``ANY`` special type
4911 >>> Any(Integer(-123))
4913 >>> a = Any(OctetString(b"hello world").encode())
4914 ANY 040b68656c6c6f20776f726c64
4915 >>> hexenc(bytes(a))
4916 b'0x040x0bhello world'
4918 __slots__ = ("defined",)
4919 tag_default = tag_encode(0)
4920 asn1_type_name = "ANY"
4930 :param value: set the value. Either any kind of pyderasn's
4931 **ready** object, or bytes. Pay attention that
4932 **no** validation is performed is raw binary value
4934 :param bytes expl: override default tag with ``EXPLICIT`` one
4935 :param bool optional: is object ``OPTIONAL`` in sequence
4937 super(Any, self).__init__(None, expl, None, optional, _decoded)
4938 self._value = None if value is None else self._value_sanitize(value)
4941 def _value_sanitize(self, value):
4942 if isinstance(value, binary_type):
4944 if isinstance(value, self.__class__):
4946 if isinstance(value, Obj):
4947 return value.encode()
4948 raise InvalidValueType((self.__class__, Obj, binary_type))
4952 return self._value is not None
4956 if self.expl_lenindef or self.lenindef:
4958 if self.defined is None:
4960 return self.defined[1].bered
4962 def __getstate__(self):
4978 def __setstate__(self, state):
4979 super(Any, self).__setstate__(state)
4980 self._value = state.value
4981 self.tag = state.tag
4982 self._expl = state.expl
4983 self.optional = state.optional
4984 self.offset = state.offset
4985 self.llen = state.llen
4986 self.vlen = state.vlen
4987 self.expl_lenindef = state.expl_lenindef
4988 self.lenindef = state.lenindef
4989 self.ber_encoded = state.ber_encoded
4990 self.defined = state.defined
4992 def __eq__(self, their):
4993 if isinstance(their, binary_type):
4994 return self._value == their
4995 if issubclass(their.__class__, Any):
4996 return self._value == their._value
5005 return self.__class__(
5007 expl=self._expl if expl is None else expl,
5008 optional=self.optional if optional is None else optional,
5011 def __bytes__(self):
5012 self._assert_ready()
5020 self._assert_ready()
5023 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5025 t, tlen, lv = tag_strip(tlv)
5026 except DecodeError as err:
5027 raise err.__class__(
5029 klass=self.__class__,
5030 decode_path=decode_path,
5034 l, llen, v = len_decode(lv)
5035 except LenIndefForm as err:
5036 if not ctx.get("bered", False):
5037 raise err.__class__(
5039 klass=self.__class__,
5040 decode_path=decode_path,
5043 llen, vlen, v = 1, 0, lv[1:]
5044 sub_offset = offset + tlen + llen
5046 while v[:EOC_LEN].tobytes() != EOC:
5047 chunk, v = Any().decode(
5050 decode_path=decode_path + (str(chunk_i),),
5053 _ctx_immutable=False,
5055 vlen += chunk.tlvlen
5056 sub_offset += chunk.tlvlen
5058 tlvlen = tlen + llen + vlen + EOC_LEN
5059 obj = self.__class__(
5060 value=tlv[:tlvlen].tobytes(),
5062 optional=self.optional,
5063 _decoded=(offset, 0, tlvlen),
5066 obj.tag = t.tobytes()
5067 return obj, v[EOC_LEN:]
5068 except DecodeError as err:
5069 raise err.__class__(
5071 klass=self.__class__,
5072 decode_path=decode_path,
5076 raise NotEnoughData(
5077 "encoded length is longer than data",
5078 klass=self.__class__,
5079 decode_path=decode_path,
5082 tlvlen = tlen + llen + l
5083 v, tail = tlv[:tlvlen], v[l:]
5084 obj = self.__class__(
5087 optional=self.optional,
5088 _decoded=(offset, 0, tlvlen),
5090 obj.tag = t.tobytes()
5094 return pp_console_row(next(self.pps()))
5096 def pps(self, decode_path=()):
5099 asn1_type_name=self.asn1_type_name,
5100 obj_name=self.__class__.__name__,
5101 decode_path=decode_path,
5102 blob=self._value if self.ready else None,
5103 optional=self.optional,
5104 default=self == self.default,
5105 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5106 expl=None if self._expl is None else tag_decode(self._expl),
5111 expl_offset=self.expl_offset if self.expled else None,
5112 expl_tlen=self.expl_tlen if self.expled else None,
5113 expl_llen=self.expl_llen if self.expled else None,
5114 expl_vlen=self.expl_vlen if self.expled else None,
5115 expl_lenindef=self.expl_lenindef,
5116 lenindef=self.lenindef,
5119 defined_by, defined = self.defined or (None, None)
5120 if defined_by is not None:
5122 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5124 for pp in self.pps_lenindef(decode_path):
5128 ########################################################################
5129 # ASN.1 constructed types
5130 ########################################################################
5132 def get_def_by_path(defines_by_path, sub_decode_path):
5133 """Get define by decode path
5135 for path, define in defines_by_path:
5136 if len(path) != len(sub_decode_path):
5138 for p1, p2 in zip(path, sub_decode_path):
5139 if (p1 != any) and (p1 != p2):
5145 def abs_decode_path(decode_path, rel_path):
5146 """Create an absolute decode path from current and relative ones
5148 :param decode_path: current decode path, starting point. Tuple of strings
5149 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5150 If first tuple's element is "/", then treat it as
5151 an absolute path, ignoring ``decode_path`` as
5152 starting point. Also this tuple can contain ".."
5153 elements, stripping the leading element from
5156 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5157 ("foo", "bar", "baz", "whatever")
5158 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5160 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5163 if rel_path[0] == "/":
5165 if rel_path[0] == "..":
5166 return abs_decode_path(decode_path[:-1], rel_path[1:])
5167 return decode_path + rel_path
5170 SequenceState = namedtuple("SequenceState", (
5184 ), **NAMEDTUPLE_KWARGS)
5187 class Sequence(Obj):
5188 """``SEQUENCE`` structure type
5190 You have to make specification of sequence::
5192 class Extension(Sequence):
5194 ("extnID", ObjectIdentifier()),
5195 ("critical", Boolean(default=False)),
5196 ("extnValue", OctetString()),
5199 Then, you can work with it as with dictionary.
5201 >>> ext = Extension()
5202 >>> Extension().specs
5204 ('extnID', OBJECT IDENTIFIER),
5205 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5206 ('extnValue', OCTET STRING),
5208 >>> ext["extnID"] = "1.2.3"
5209 Traceback (most recent call last):
5210 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5211 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5213 You can determine if sequence is ready to be encoded:
5218 Traceback (most recent call last):
5219 pyderasn.ObjNotReady: object is not ready: extnValue
5220 >>> ext["extnValue"] = OctetString(b"foobar")
5224 Value you want to assign, must have the same **type** as in
5225 corresponding specification, but it can have different tags,
5226 optional/default attributes -- they will be taken from specification
5229 class TBSCertificate(Sequence):
5231 ("version", Version(expl=tag_ctxc(0), default="v1")),
5234 >>> tbs = TBSCertificate()
5235 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5237 Assign ``None`` to remove value from sequence.
5239 You can set values in Sequence during its initialization:
5241 >>> AlgorithmIdentifier((
5242 ("algorithm", ObjectIdentifier("1.2.3")),
5243 ("parameters", Any(Null()))
5245 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5247 You can determine if value exists/set in the sequence and take its value:
5249 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5252 OBJECT IDENTIFIER 1.2.3
5254 But pay attention that if value has default, then it won't be (not
5255 in) in the sequence (because ``DEFAULT`` must not be encoded in
5256 DER), but you can read its value:
5258 >>> "critical" in ext, ext["critical"]
5259 (False, BOOLEAN False)
5260 >>> ext["critical"] = Boolean(True)
5261 >>> "critical" in ext, ext["critical"]
5262 (True, BOOLEAN True)
5264 All defaulted values are always optional.
5266 .. _allow_default_values_ctx:
5268 DER prohibits default value encoding and will raise an error if
5269 default value is unexpectedly met during decode.
5270 If :ref:`bered <bered_ctx>` context option is set, then no error
5271 will be raised, but ``bered`` attribute set. You can disable strict
5272 defaulted values existence validation by setting
5273 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5275 Two sequences are equal if they have equal specification (schema),
5276 implicit/explicit tagging and the same values.
5278 __slots__ = ("specs",)
5279 tag_default = tag_encode(form=TagFormConstructed, num=16)
5280 asn1_type_name = "SEQUENCE"
5292 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5294 schema = getattr(self, "schema", ())
5296 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5299 if value is not None:
5300 if issubclass(value.__class__, Sequence):
5301 self._value = value._value
5302 elif hasattr(value, "__iter__"):
5303 for seq_key, seq_value in value:
5304 self[seq_key] = seq_value
5306 raise InvalidValueType((Sequence,))
5307 if default is not None:
5308 if not issubclass(default.__class__, Sequence):
5309 raise InvalidValueType((Sequence,))
5310 default_value = default._value
5311 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5312 default_obj.specs = self.specs
5313 default_obj._value = default_value
5314 self.default = default_obj
5316 self._value = copy(default_obj._value)
5320 for name, spec in iteritems(self.specs):
5321 value = self._value.get(name)
5332 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5334 return any(value.bered for value in itervalues(self._value))
5336 def __getstate__(self):
5337 return SequenceState(
5340 {k: copy(v) for k, v in iteritems(self._value)},
5353 def __setstate__(self, state):
5354 super(Sequence, self).__setstate__(state)
5355 self.specs = state.specs
5356 self._value = state.value
5357 self.tag = state.tag
5358 self._expl = state.expl
5359 self.default = state.default
5360 self.optional = state.optional
5361 self.offset = state.offset
5362 self.llen = state.llen
5363 self.vlen = state.vlen
5364 self.expl_lenindef = state.expl_lenindef
5365 self.lenindef = state.lenindef
5366 self.ber_encoded = state.ber_encoded
5368 def __eq__(self, their):
5369 if not isinstance(their, self.__class__):
5372 self.specs == their.specs and
5373 self.tag == their.tag and
5374 self._expl == their._expl and
5375 self._value == their._value
5386 return self.__class__(
5389 impl=self.tag if impl is None else impl,
5390 expl=self._expl if expl is None else expl,
5391 default=self.default if default is None else default,
5392 optional=self.optional if optional is None else optional,
5395 def __contains__(self, key):
5396 return key in self._value
5398 def __setitem__(self, key, value):
5399 spec = self.specs.get(key)
5401 raise ObjUnknown(key)
5403 self._value.pop(key, None)
5405 if not isinstance(value, spec.__class__):
5406 raise InvalidValueType((spec.__class__,))
5407 value = spec(value=value)
5408 if spec.default is not None and value == spec.default:
5409 self._value.pop(key, None)
5411 self._value[key] = value
5413 def __getitem__(self, key):
5414 value = self._value.get(key)
5415 if value is not None:
5417 spec = self.specs.get(key)
5419 raise ObjUnknown(key)
5420 if spec.default is not None:
5424 def _encoded_values(self):
5426 for name, spec in iteritems(self.specs):
5427 value = self._value.get(name)
5431 raise ObjNotReady(name)
5432 raws.append(value.encode())
5436 v = b"".join(self._encoded_values())
5437 return b"".join((self.tag, len_encode(len(v)), v))
5439 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5441 t, tlen, lv = tag_strip(tlv)
5442 except DecodeError as err:
5443 raise err.__class__(
5445 klass=self.__class__,
5446 decode_path=decode_path,
5451 klass=self.__class__,
5452 decode_path=decode_path,
5455 if tag_only: # pragma: no cover
5458 ctx_bered = ctx.get("bered", False)
5460 l, llen, v = len_decode(lv)
5461 except LenIndefForm as err:
5463 raise err.__class__(
5465 klass=self.__class__,
5466 decode_path=decode_path,
5469 l, llen, v = 0, 1, lv[1:]
5471 except DecodeError as err:
5472 raise err.__class__(
5474 klass=self.__class__,
5475 decode_path=decode_path,
5479 raise NotEnoughData(
5480 "encoded length is longer than data",
5481 klass=self.__class__,
5482 decode_path=decode_path,
5486 v, tail = v[:l], v[l:]
5488 sub_offset = offset + tlen + llen
5491 ctx_allow_default_values = ctx.get("allow_default_values", False)
5492 for name, spec in iteritems(self.specs):
5493 if spec.optional and (
5494 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5498 sub_decode_path = decode_path + (name,)
5500 value, v_tail = spec.decode(
5504 decode_path=sub_decode_path,
5506 _ctx_immutable=False,
5508 except TagMismatch as err:
5509 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5513 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5514 if defined is not None:
5515 defined_by, defined_spec = defined
5516 if issubclass(value.__class__, SequenceOf):
5517 for i, _value in enumerate(value):
5518 sub_sub_decode_path = sub_decode_path + (
5520 DecodePathDefBy(defined_by),
5522 defined_value, defined_tail = defined_spec.decode(
5523 memoryview(bytes(_value)),
5525 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5526 if value.expled else (value.tlen + value.llen)
5529 decode_path=sub_sub_decode_path,
5531 _ctx_immutable=False,
5533 if len(defined_tail) > 0:
5536 klass=self.__class__,
5537 decode_path=sub_sub_decode_path,
5540 _value.defined = (defined_by, defined_value)
5542 defined_value, defined_tail = defined_spec.decode(
5543 memoryview(bytes(value)),
5545 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5546 if value.expled else (value.tlen + value.llen)
5549 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5551 _ctx_immutable=False,
5553 if len(defined_tail) > 0:
5556 klass=self.__class__,
5557 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5560 value.defined = (defined_by, defined_value)
5562 value_len = value.fulllen
5564 sub_offset += value_len
5566 if spec.default is not None and value == spec.default:
5567 if ctx_bered or ctx_allow_default_values:
5571 "DEFAULT value met",
5572 klass=self.__class__,
5573 decode_path=sub_decode_path,
5576 values[name] = value
5578 spec_defines = getattr(spec, "defines", ())
5579 if len(spec_defines) == 0:
5580 defines_by_path = ctx.get("defines_by_path", ())
5581 if len(defines_by_path) > 0:
5582 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5583 if spec_defines is not None and len(spec_defines) > 0:
5584 for rel_path, schema in spec_defines:
5585 defined = schema.get(value, None)
5586 if defined is not None:
5587 ctx.setdefault("_defines", []).append((
5588 abs_decode_path(sub_decode_path[:-1], rel_path),
5592 if v[:EOC_LEN].tobytes() != EOC:
5595 klass=self.__class__,
5596 decode_path=decode_path,
5604 klass=self.__class__,
5605 decode_path=decode_path,
5608 obj = self.__class__(
5612 default=self.default,
5613 optional=self.optional,
5614 _decoded=(offset, llen, vlen),
5617 obj.lenindef = lenindef
5618 obj.ber_encoded = ber_encoded
5622 value = pp_console_row(next(self.pps()))
5624 for name in self.specs:
5625 _value = self._value.get(name)
5628 cols.append("%s: %s" % (name, repr(_value)))
5629 return "%s[%s]" % (value, "; ".join(cols))
5631 def pps(self, decode_path=()):
5634 asn1_type_name=self.asn1_type_name,
5635 obj_name=self.__class__.__name__,
5636 decode_path=decode_path,
5637 optional=self.optional,
5638 default=self == self.default,
5639 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5640 expl=None if self._expl is None else tag_decode(self._expl),
5645 expl_offset=self.expl_offset if self.expled else None,
5646 expl_tlen=self.expl_tlen if self.expled else None,
5647 expl_llen=self.expl_llen if self.expled else None,
5648 expl_vlen=self.expl_vlen if self.expled else None,
5649 expl_lenindef=self.expl_lenindef,
5650 lenindef=self.lenindef,
5651 ber_encoded=self.ber_encoded,
5654 for name in self.specs:
5655 value = self._value.get(name)
5658 yield value.pps(decode_path=decode_path + (name,))
5659 for pp in self.pps_lenindef(decode_path):
5663 class Set(Sequence):
5664 """``SET`` structure type
5666 Its usage is identical to :py:class:`pyderasn.Sequence`.
5668 .. _allow_unordered_set_ctx:
5670 DER prohibits unordered values encoding and will raise an error
5671 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5672 then no error will occure. Also you can disable strict values
5673 ordering check by setting ``"allow_unordered_set": True``
5674 :ref:`context <ctx>` option.
5677 tag_default = tag_encode(form=TagFormConstructed, num=17)
5678 asn1_type_name = "SET"
5681 raws = self._encoded_values()
5684 return b"".join((self.tag, len_encode(len(v)), v))
5686 def _specs_items(self):
5687 return iteritems(self.specs)
5689 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5691 t, tlen, lv = tag_strip(tlv)
5692 except DecodeError as err:
5693 raise err.__class__(
5695 klass=self.__class__,
5696 decode_path=decode_path,
5701 klass=self.__class__,
5702 decode_path=decode_path,
5708 ctx_bered = ctx.get("bered", False)
5710 l, llen, v = len_decode(lv)
5711 except LenIndefForm as err:
5713 raise err.__class__(
5715 klass=self.__class__,
5716 decode_path=decode_path,
5719 l, llen, v = 0, 1, lv[1:]
5721 except DecodeError as err:
5722 raise err.__class__(
5724 klass=self.__class__,
5725 decode_path=decode_path,
5729 raise NotEnoughData(
5730 "encoded length is longer than data",
5731 klass=self.__class__,
5735 v, tail = v[:l], v[l:]
5737 sub_offset = offset + tlen + llen
5740 ctx_allow_default_values = ctx.get("allow_default_values", False)
5741 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5742 value_prev = memoryview(v[:0])
5745 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5747 for name, spec in self._specs_items():
5748 sub_decode_path = decode_path + (name,)
5754 decode_path=sub_decode_path,
5757 _ctx_immutable=False,
5764 klass=self.__class__,
5765 decode_path=decode_path,
5768 value, v_tail = spec.decode(
5772 decode_path=sub_decode_path,
5774 _ctx_immutable=False,
5776 value_len = value.fulllen
5777 if value_prev.tobytes() > v[:value_len].tobytes():
5778 if ctx_bered or ctx_allow_unordered_set:
5782 "unordered " + self.asn1_type_name,
5783 klass=self.__class__,
5784 decode_path=sub_decode_path,
5787 if spec.default is None or value != spec.default:
5789 elif ctx_bered or ctx_allow_default_values:
5793 "DEFAULT value met",
5794 klass=self.__class__,
5795 decode_path=sub_decode_path,
5798 values[name] = value
5799 value_prev = v[:value_len]
5800 sub_offset += value_len
5803 obj = self.__class__(
5807 default=self.default,
5808 optional=self.optional,
5809 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5812 if v[:EOC_LEN].tobytes() != EOC:
5815 klass=self.__class__,
5816 decode_path=decode_path,
5824 "not all values are ready",
5825 klass=self.__class__,
5826 decode_path=decode_path,
5829 obj.ber_encoded = ber_encoded
5833 SequenceOfState = namedtuple("SequenceOfState", (
5849 ), **NAMEDTUPLE_KWARGS)
5852 class SequenceOf(Obj):
5853 """``SEQUENCE OF`` sequence type
5855 For that kind of type you must specify the object it will carry on
5856 (bounds are for example here, not required)::
5858 class Ints(SequenceOf):
5863 >>> ints.append(Integer(123))
5864 >>> ints.append(Integer(234))
5866 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5867 >>> [int(i) for i in ints]
5869 >>> ints.append(Integer(345))
5870 Traceback (most recent call last):
5871 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5874 >>> ints[1] = Integer(345)
5876 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5878 Also you can initialize sequence with preinitialized values:
5880 >>> ints = Ints([Integer(123), Integer(234)])
5882 __slots__ = ("spec", "_bound_min", "_bound_max")
5883 tag_default = tag_encode(form=TagFormConstructed, num=16)
5884 asn1_type_name = "SEQUENCE OF"
5897 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5899 schema = getattr(self, "schema", None)
5901 raise ValueError("schema must be specified")
5903 self._bound_min, self._bound_max = getattr(
5907 ) if bounds is None else bounds
5909 if value is not None:
5910 self._value = self._value_sanitize(value)
5911 if default is not None:
5912 default_value = self._value_sanitize(default)
5913 default_obj = self.__class__(
5918 default_obj._value = default_value
5919 self.default = default_obj
5921 self._value = copy(default_obj._value)
5923 def _value_sanitize(self, value):
5924 if issubclass(value.__class__, SequenceOf):
5925 value = value._value
5926 elif hasattr(value, "__iter__"):
5929 raise InvalidValueType((self.__class__, iter))
5930 if not self._bound_min <= len(value) <= self._bound_max:
5931 raise BoundsError(self._bound_min, len(value), self._bound_max)
5933 if not isinstance(v, self.spec.__class__):
5934 raise InvalidValueType((self.spec.__class__,))
5939 return all(v.ready for v in self._value)
5943 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5945 return any(v.bered for v in self._value)
5947 def __getstate__(self):
5948 return SequenceOfState(
5951 [copy(v) for v in self._value],
5966 def __setstate__(self, state):
5967 super(SequenceOf, self).__setstate__(state)
5968 self.spec = state.spec
5969 self._value = state.value
5970 self._bound_min = state.bound_min
5971 self._bound_max = state.bound_max
5972 self.tag = state.tag
5973 self._expl = state.expl
5974 self.default = state.default
5975 self.optional = state.optional
5976 self.offset = state.offset
5977 self.llen = state.llen
5978 self.vlen = state.vlen
5979 self.expl_lenindef = state.expl_lenindef
5980 self.lenindef = state.lenindef
5981 self.ber_encoded = state.ber_encoded
5983 def __eq__(self, their):
5984 if isinstance(their, self.__class__):
5986 self.spec == their.spec and
5987 self.tag == their.tag and
5988 self._expl == their._expl and
5989 self._value == their._value
5991 if hasattr(their, "__iter__"):
5992 return self._value == list(their)
6004 return self.__class__(
6008 (self._bound_min, self._bound_max)
6009 if bounds is None else bounds
6011 impl=self.tag if impl is None else impl,
6012 expl=self._expl if expl is None else expl,
6013 default=self.default if default is None else default,
6014 optional=self.optional if optional is None else optional,
6017 def __contains__(self, key):
6018 return key in self._value
6020 def append(self, value):
6021 if not isinstance(value, self.spec.__class__):
6022 raise InvalidValueType((self.spec.__class__,))
6023 if len(self._value) + 1 > self._bound_max:
6026 len(self._value) + 1,
6029 self._value.append(value)
6032 self._assert_ready()
6033 return iter(self._value)
6036 self._assert_ready()
6037 return len(self._value)
6039 def __setitem__(self, key, value):
6040 if not isinstance(value, self.spec.__class__):
6041 raise InvalidValueType((self.spec.__class__,))
6042 self._value[key] = self.spec(value=value)
6044 def __getitem__(self, key):
6045 return self._value[key]
6047 def _encoded_values(self):
6048 return [v.encode() for v in self._value]
6051 v = b"".join(self._encoded_values())
6052 return b"".join((self.tag, len_encode(len(v)), v))
6054 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6056 t, tlen, lv = tag_strip(tlv)
6057 except DecodeError as err:
6058 raise err.__class__(
6060 klass=self.__class__,
6061 decode_path=decode_path,
6066 klass=self.__class__,
6067 decode_path=decode_path,
6073 ctx_bered = ctx.get("bered", False)
6075 l, llen, v = len_decode(lv)
6076 except LenIndefForm as err:
6078 raise err.__class__(
6080 klass=self.__class__,
6081 decode_path=decode_path,
6084 l, llen, v = 0, 1, lv[1:]
6086 except DecodeError as err:
6087 raise err.__class__(
6089 klass=self.__class__,
6090 decode_path=decode_path,
6094 raise NotEnoughData(
6095 "encoded length is longer than data",
6096 klass=self.__class__,
6097 decode_path=decode_path,
6101 v, tail = v[:l], v[l:]
6103 sub_offset = offset + tlen + llen
6105 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6106 value_prev = memoryview(v[:0])
6110 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6112 sub_decode_path = decode_path + (str(len(_value)),)
6113 value, v_tail = spec.decode(
6117 decode_path=sub_decode_path,
6119 _ctx_immutable=False,
6121 value_len = value.fulllen
6123 if value_prev.tobytes() > v[:value_len].tobytes():
6124 if ctx_bered or ctx_allow_unordered_set:
6128 "unordered " + self.asn1_type_name,
6129 klass=self.__class__,
6130 decode_path=sub_decode_path,
6133 value_prev = v[:value_len]
6134 _value.append(value)
6135 sub_offset += value_len
6139 obj = self.__class__(
6142 bounds=(self._bound_min, self._bound_max),
6145 default=self.default,
6146 optional=self.optional,
6147 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6149 except BoundsError as err:
6152 klass=self.__class__,
6153 decode_path=decode_path,
6157 if v[:EOC_LEN].tobytes() != EOC:
6160 klass=self.__class__,
6161 decode_path=decode_path,
6166 obj.ber_encoded = ber_encoded
6171 pp_console_row(next(self.pps())),
6172 ", ".join(repr(v) for v in self._value),
6175 def pps(self, decode_path=()):
6178 asn1_type_name=self.asn1_type_name,
6179 obj_name=self.__class__.__name__,
6180 decode_path=decode_path,
6181 optional=self.optional,
6182 default=self == self.default,
6183 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6184 expl=None if self._expl is None else tag_decode(self._expl),
6189 expl_offset=self.expl_offset if self.expled else None,
6190 expl_tlen=self.expl_tlen if self.expled else None,
6191 expl_llen=self.expl_llen if self.expled else None,
6192 expl_vlen=self.expl_vlen if self.expled else None,
6193 expl_lenindef=self.expl_lenindef,
6194 lenindef=self.lenindef,
6195 ber_encoded=self.ber_encoded,
6198 for i, value in enumerate(self._value):
6199 yield value.pps(decode_path=decode_path + (str(i),))
6200 for pp in self.pps_lenindef(decode_path):
6204 class SetOf(SequenceOf):
6205 """``SET OF`` sequence type
6207 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6210 tag_default = tag_encode(form=TagFormConstructed, num=17)
6211 asn1_type_name = "SET OF"
6214 raws = self._encoded_values()
6217 return b"".join((self.tag, len_encode(len(v)), v))
6219 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6220 return super(SetOf, self)._decode(
6226 ordering_check=True,
6230 def obj_by_path(pypath): # pragma: no cover
6231 """Import object specified as string Python path
6233 Modules must be separated from classes/functions with ``:``.
6235 >>> obj_by_path("foo.bar:Baz")
6236 <class 'foo.bar.Baz'>
6237 >>> obj_by_path("foo.bar:Baz.boo")
6238 <classmethod 'foo.bar.Baz.boo'>
6240 mod, objs = pypath.rsplit(":", 1)
6241 from importlib import import_module
6242 obj = import_module(mod)
6243 for obj_name in objs.split("."):
6244 obj = getattr(obj, obj_name)
6248 def generic_decoder(): # pragma: no cover
6249 # All of this below is a big hack with self references
6250 choice = PrimitiveTypes()
6251 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6252 choice.specs["SetOf"] = SetOf(schema=choice)
6253 for i in six_xrange(31):
6254 choice.specs["SequenceOf%d" % i] = SequenceOf(
6258 choice.specs["Any"] = Any()
6260 # Class name equals to type name, to omit it from output
6261 class SEQUENCEOF(SequenceOf):
6269 with_decode_path=False,
6270 decode_path_only=(),
6272 def _pprint_pps(pps):
6274 if hasattr(pp, "_fields"):
6276 decode_path_only != () and
6277 pp.decode_path[:len(decode_path_only)] != decode_path_only
6280 if pp.asn1_type_name == Choice.asn1_type_name:
6282 pp_kwargs = pp._asdict()
6283 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6284 pp = _pp(**pp_kwargs)
6285 yield pp_console_row(
6290 with_colours=with_colours,
6291 with_decode_path=with_decode_path,
6292 decode_path_len_decrease=len(decode_path_only),
6294 for row in pp_console_blob(
6296 decode_path_len_decrease=len(decode_path_only),
6300 for row in _pprint_pps(pp):
6302 return "\n".join(_pprint_pps(obj.pps()))
6303 return SEQUENCEOF(), pprint_any
6306 def main(): # pragma: no cover
6308 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6309 parser.add_argument(
6313 help="Skip that number of bytes from the beginning",
6315 parser.add_argument(
6317 help="Python paths to dictionary with OIDs, comma separated",
6319 parser.add_argument(
6321 help="Python path to schema definition to use",
6323 parser.add_argument(
6324 "--defines-by-path",
6325 help="Python path to decoder's defines_by_path",
6327 parser.add_argument(
6329 action="store_true",
6330 help="Disallow BER encoding",
6332 parser.add_argument(
6333 "--print-decode-path",
6334 action="store_true",
6335 help="Print decode paths",
6337 parser.add_argument(
6338 "--decode-path-only",
6339 help="Print only specified decode path",
6341 parser.add_argument(
6343 action="store_true",
6344 help="Allow explicit tag out-of-bound",
6346 parser.add_argument(
6348 type=argparse.FileType("rb"),
6349 help="Path to DER file you want to decode",
6351 args = parser.parse_args()
6352 args.DERFile.seek(args.skip)
6353 der = memoryview(args.DERFile.read())
6354 args.DERFile.close()
6356 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6357 if args.oids else ()
6360 schema = obj_by_path(args.schema)
6361 from functools import partial
6362 pprinter = partial(pprint, big_blobs=True)
6364 schema, pprinter = generic_decoder()
6366 "bered": not args.nobered,
6367 "allow_expl_oob": args.allow_expl_oob,
6369 if args.defines_by_path is not None:
6370 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6371 obj, tail = schema().decode(der, ctx=ctx)
6375 with_colours=environ.get("NO_COLOR") is None,
6376 with_decode_path=args.print_decode_path,
6378 () if args.decode_path_only is None else
6379 tuple(args.decode_path_only.split(":"))
6383 print("\nTrailing data: %s" % hexenc(tail))
6386 if __name__ == "__main__":