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("01")
769 DECIMALS = frozenset(digits)
774 if not set(value) <= DECIMALS:
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 pp.blob.__class__ == binary_type:
1648 cols.append(hexenc(pp.blob))
1649 elif pp.blob.__class__ == 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 pp.blob.__class__ == 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 pp.blob.__class__ == 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 value.__class__ == 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 their.__class__ == 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 specs.__class__ == 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 value.__class__ == 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 specs.__class__ == 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 value.__class__ == binary_type:
2495 return (len(value) * 8, value)
2496 raise InvalidValueType((self.__class__, string_types, binary_type))
2497 if value.__class__ == tuple:
2500 isinstance(value[0], integer_types) and
2501 value[1].__class__ == 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 their.__class__ == 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 key.__class__ == 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 value.__class__ == 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 their.__class__ == 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 their.__class__ == tuple:
3509 return self.__class__(self._value + their)
3510 if isinstance(their, self.__class__):
3511 return self.__class__(self._value + their._value)
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 value.__class__ == 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 their.__class__ == 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 value.__class__ == text_type:
3901 value_decoded = value
3902 elif value.__class__ == 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 their.__class__ == binary_type:
3927 return self._value == their
3928 if their.__class__ == 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)
4191 If BER encoded value was met, then ``ber_raw`` attribute will hold
4192 its raw representation.
4196 Pay attention that UTCTime can not hold full year, so all years
4197 having < 50 years are treated as 20xx, 19xx otherwise, according
4198 to X.509 recommendation.
4202 No strict validation of UTC offsets are made, but very crude:
4204 * minutes are not exceeding 60
4205 * offset value is not exceeding 14 hours
4207 __slots__ = ("ber_raw",)
4208 tag_default = tag_encode(23)
4210 asn1_type_name = "UTCTime"
4220 bounds=None, # dummy argument, workability for OctetString.decode
4224 :param value: set the value. Either datetime type, or
4225 :py:class:`pyderasn.UTCTime` object
4226 :param bytes impl: override default tag with ``IMPLICIT`` one
4227 :param bytes expl: override default tag with ``EXPLICIT`` one
4228 :param default: set default value. Type same as in ``value``
4229 :param bool optional: is object ``OPTIONAL`` in sequence
4231 super(UTCTime, self).__init__(
4232 None, None, impl, expl, None, optional, _decoded, ctx,
4236 if value is not None:
4237 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4238 self.ber_encoded = self.ber_raw is not None
4239 if default is not None:
4240 default, _ = self._value_sanitize(default)
4241 self.default = self.__class__(
4246 if self._value is None:
4247 self._value = default
4249 self.optional = optional
4251 def _strptime_bered(self, value):
4252 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4255 raise ValueError("no timezone")
4256 year += 2000 if year < 50 else 1900
4257 decoded = datetime(year, month, day, hour, minute)
4259 if value[-1] == "Z":
4263 raise ValueError("invalid UTC offset")
4264 if value[-5] == "-":
4266 elif value[-5] == "+":
4269 raise ValueError("invalid UTC offset")
4270 v = pureint(value[-4:])
4271 offset, v = (60 * (v % 100)), v // 100
4273 raise ValueError("invalid UTC offset minutes")
4275 if offset > 14 * 3600:
4276 raise ValueError("too big UTC offset")
4280 return offset, decoded
4282 raise ValueError("invalid UTC offset seconds")
4283 seconds = pureint(value)
4285 raise ValueError("invalid seconds value")
4286 return offset, decoded + timedelta(seconds=seconds)
4288 def _strptime(self, value):
4289 # datetime.strptime's format: %y%m%d%H%M%SZ
4290 if len(value) != LEN_YYMMDDHHMMSSZ:
4291 raise ValueError("invalid UTCTime length")
4292 if value[-1] != "Z":
4293 raise ValueError("non UTC timezone")
4294 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4295 year += 2000 if year < 50 else 1900
4296 return datetime(year, month, day, hour, minute, second)
4298 def _dt_sanitize(self, value):
4299 if value.year < 1950 or value.year > 2049:
4300 raise ValueError("UTCTime can hold only 1950-2049 years")
4301 return value.replace(microsecond=0)
4303 def _value_sanitize(self, value, ctx=None):
4304 if value.__class__ == binary_type:
4306 value_decoded = value.decode("ascii")
4307 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4308 raise DecodeError("invalid UTCTime encoding: %r" % err)
4311 return self._strptime(value_decoded), None
4312 except (TypeError, ValueError) as _err:
4314 if (ctx is not None) and ctx.get("bered", False):
4316 offset, _value = self._strptime_bered(value_decoded)
4317 _value = _value - timedelta(seconds=offset)
4318 return self._dt_sanitize(_value), value
4319 except (TypeError, ValueError, OverflowError) as _err:
4322 "invalid %s format: %r" % (self.asn1_type_name, err),
4323 klass=self.__class__,
4325 if isinstance(value, self.__class__):
4326 return value._value, None
4327 if value.__class__ == datetime:
4328 return self._dt_sanitize(value), None
4329 raise InvalidValueType((self.__class__, datetime))
4331 def _pp_value(self):
4333 value = self._value.isoformat()
4334 if self.ber_encoded:
4335 value += " (%s)" % self.ber_raw
4338 def __unicode__(self):
4340 value = self._value.isoformat()
4341 if self.ber_encoded:
4342 value += " (%s)" % self.ber_raw
4344 return text_type(self._pp_value())
4346 def __getstate__(self):
4347 return UTCTimeState(
4348 *super(UTCTime, self).__getstate__(),
4349 **{"ber_raw": self.ber_raw}
4352 def __setstate__(self, state):
4353 super(UTCTime, self).__setstate__(state)
4354 self.ber_raw = state.ber_raw
4356 def __bytes__(self):
4357 self._assert_ready()
4358 return self._encode_time()
4360 def __eq__(self, their):
4361 if their.__class__ == binary_type:
4362 return self._encode_time() == their
4363 if their.__class__ == datetime:
4364 return self.todatetime() == their
4365 if not isinstance(their, self.__class__):
4368 self._value == their._value and
4369 self.tag == their.tag and
4370 self._expl == their._expl
4373 def _encode_time(self):
4374 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4377 self._assert_ready()
4378 value = self._encode_time()
4379 return b"".join((self.tag, len_encode(len(value)), value))
4381 def todatetime(self):
4385 return pp_console_row(next(self.pps()))
4387 def pps(self, decode_path=()):
4390 asn1_type_name=self.asn1_type_name,
4391 obj_name=self.__class__.__name__,
4392 decode_path=decode_path,
4393 value=self._pp_value(),
4394 optional=self.optional,
4395 default=self == self.default,
4396 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4397 expl=None if self._expl is None else tag_decode(self._expl),
4402 expl_offset=self.expl_offset if self.expled else None,
4403 expl_tlen=self.expl_tlen if self.expled else None,
4404 expl_llen=self.expl_llen if self.expled else None,
4405 expl_vlen=self.expl_vlen if self.expled else None,
4406 expl_lenindef=self.expl_lenindef,
4407 ber_encoded=self.ber_encoded,
4410 for pp in self.pps_lenindef(decode_path):
4414 class GeneralizedTime(UTCTime):
4415 """``GeneralizedTime`` datetime type
4417 This type is similar to :py:class:`pyderasn.UTCTime`.
4419 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4420 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4422 '20170930220750.000123Z'
4423 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4424 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4428 Only microsecond fractions are supported in DER encoding.
4429 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4430 higher precision values.
4434 BER encoded data can loss information (accuracy) during decoding
4435 because of float transformations.
4439 Local times (without explicit timezone specification) are treated
4440 as UTC one, no transformations are made.
4444 Zero year is unsupported.
4447 tag_default = tag_encode(24)
4448 asn1_type_name = "GeneralizedTime"
4450 def _dt_sanitize(self, value):
4453 def _strptime_bered(self, value):
4454 if len(value) < 4 + 3 * 2:
4455 raise ValueError("invalid GeneralizedTime")
4456 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4457 decoded = datetime(year, month, day, hour)
4458 offset, value = 0, value[10:]
4460 return offset, decoded
4461 if value[-1] == "Z":
4464 for char, sign in (("-", -1), ("+", 1)):
4465 idx = value.rfind(char)
4468 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4469 v = pureint(offset_raw)
4470 if len(offset_raw) == 4:
4471 offset, v = (60 * (v % 100)), v // 100
4473 raise ValueError("invalid UTC offset minutes")
4474 elif len(offset_raw) == 2:
4477 raise ValueError("invalid UTC offset")
4479 if offset > 14 * 3600:
4480 raise ValueError("too big UTC offset")
4484 return offset, decoded
4485 if value[0] in DECIMAL_SIGNS:
4487 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4490 raise ValueError("stripped minutes")
4491 decoded += timedelta(seconds=60 * pureint(value[:2]))
4494 return offset, decoded
4495 if value[0] in DECIMAL_SIGNS:
4497 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4500 raise ValueError("stripped seconds")
4501 decoded += timedelta(seconds=pureint(value[:2]))
4504 return offset, decoded
4505 if value[0] not in DECIMAL_SIGNS:
4506 raise ValueError("invalid format after seconds")
4508 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4511 def _strptime(self, value):
4513 if l == LEN_YYYYMMDDHHMMSSZ:
4514 # datetime.strptime's format: %Y%m%d%H%M%SZ
4515 if value[-1] != "Z":
4516 raise ValueError("non UTC timezone")
4517 return datetime(*str_to_time_fractions(value[:-1]))
4518 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4519 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4520 if value[-1] != "Z":
4521 raise ValueError("non UTC timezone")
4522 if value[14] != ".":
4523 raise ValueError("no fractions separator")
4526 raise ValueError("trailing zero")
4529 raise ValueError("only microsecond fractions are supported")
4530 us = pureint(us + ("0" * (6 - us_len)))
4531 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4532 return datetime(year, month, day, hour, minute, second, us)
4533 raise ValueError("invalid GeneralizedTime length")
4535 def _encode_time(self):
4537 encoded = value.strftime("%Y%m%d%H%M%S")
4538 if value.microsecond > 0:
4539 encoded += (".%06d" % value.microsecond).rstrip("0")
4540 return (encoded + "Z").encode("ascii")
4543 class GraphicString(CommonString):
4545 tag_default = tag_encode(25)
4546 encoding = "iso-8859-1"
4547 asn1_type_name = "GraphicString"
4550 class ISO646String(VisibleString):
4552 asn1_type_name = "ISO646String"
4555 class GeneralString(CommonString):
4557 tag_default = tag_encode(27)
4558 encoding = "iso-8859-1"
4559 asn1_type_name = "GeneralString"
4562 class UniversalString(CommonString):
4564 tag_default = tag_encode(28)
4565 encoding = "utf-32-be"
4566 asn1_type_name = "UniversalString"
4569 class BMPString(CommonString):
4571 tag_default = tag_encode(30)
4572 encoding = "utf-16-be"
4573 asn1_type_name = "BMPString"
4576 ChoiceState = namedtuple("ChoiceState", (
4590 ), **NAMEDTUPLE_KWARGS)
4594 """``CHOICE`` special type
4598 class GeneralName(Choice):
4600 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4601 ("dNSName", IA5String(impl=tag_ctxp(2))),
4604 >>> gn = GeneralName()
4606 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4607 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4608 >>> gn["dNSName"] = IA5String("bar.baz")
4609 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4610 >>> gn["rfc822Name"]
4613 [2] IA5String IA5 bar.baz
4616 >>> gn.value == gn["dNSName"]
4619 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4621 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4622 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4624 __slots__ = ("specs",)
4626 asn1_type_name = "CHOICE"
4639 :param value: set the value. Either ``(choice, value)`` tuple, or
4640 :py:class:`pyderasn.Choice` object
4641 :param bytes impl: can not be set, do **not** use it
4642 :param bytes expl: override default tag with ``EXPLICIT`` one
4643 :param default: set default value. Type same as in ``value``
4644 :param bool optional: is object ``OPTIONAL`` in sequence
4646 if impl is not None:
4647 raise ValueError("no implicit tag allowed for CHOICE")
4648 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4650 schema = getattr(self, "schema", ())
4651 if len(schema) == 0:
4652 raise ValueError("schema must be specified")
4654 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4657 if value is not None:
4658 self._value = self._value_sanitize(value)
4659 if default is not None:
4660 default_value = self._value_sanitize(default)
4661 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4662 default_obj.specs = self.specs
4663 default_obj._value = default_value
4664 self.default = default_obj
4666 self._value = copy(default_obj._value)
4668 def _value_sanitize(self, value):
4669 if (value.__class__ == tuple) and len(value) == 2:
4671 spec = self.specs.get(choice)
4673 raise ObjUnknown(choice)
4674 if not isinstance(obj, spec.__class__):
4675 raise InvalidValueType((spec,))
4676 return (choice, spec(obj))
4677 if isinstance(value, self.__class__):
4679 raise InvalidValueType((self.__class__, tuple))
4683 return self._value is not None and self._value[1].ready
4687 return self.expl_lenindef or (
4688 (self._value is not None) and
4689 self._value[1].bered
4692 def __getstate__(self):
4709 def __setstate__(self, state):
4710 super(Choice, self).__setstate__(state)
4711 self.specs = state.specs
4712 self._value = state.value
4713 self._expl = state.expl
4714 self.default = state.default
4715 self.optional = state.optional
4716 self.offset = state.offset
4717 self.llen = state.llen
4718 self.vlen = state.vlen
4719 self.expl_lenindef = state.expl_lenindef
4720 self.lenindef = state.lenindef
4721 self.ber_encoded = state.ber_encoded
4723 def __eq__(self, their):
4724 if (their.__class__ == tuple) and len(their) == 2:
4725 return self._value == their
4726 if not isinstance(their, self.__class__):
4729 self.specs == their.specs and
4730 self._value == their._value
4740 return self.__class__(
4743 expl=self._expl if expl is None else expl,
4744 default=self.default if default is None else default,
4745 optional=self.optional if optional is None else optional,
4750 self._assert_ready()
4751 return self._value[0]
4755 self._assert_ready()
4756 return self._value[1]
4758 def __getitem__(self, key):
4759 if key not in self.specs:
4760 raise ObjUnknown(key)
4761 if self._value is None:
4763 choice, value = self._value
4768 def __setitem__(self, key, value):
4769 spec = self.specs.get(key)
4771 raise ObjUnknown(key)
4772 if not isinstance(value, spec.__class__):
4773 raise InvalidValueType((spec.__class__,))
4774 self._value = (key, spec(value))
4782 return self._value[1].decoded if self.ready else False
4785 self._assert_ready()
4786 return self._value[1].encode()
4788 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4789 for choice, spec in iteritems(self.specs):
4790 sub_decode_path = decode_path + (choice,)
4796 decode_path=sub_decode_path,
4799 _ctx_immutable=False,
4806 klass=self.__class__,
4807 decode_path=decode_path,
4810 if tag_only: # pragma: no cover
4812 value, tail = spec.decode(
4816 decode_path=sub_decode_path,
4818 _ctx_immutable=False,
4820 obj = self.__class__(
4823 default=self.default,
4824 optional=self.optional,
4825 _decoded=(offset, 0, value.fulllen),
4827 obj._value = (choice, value)
4831 value = pp_console_row(next(self.pps()))
4833 value = "%s[%r]" % (value, self.value)
4836 def pps(self, decode_path=()):
4839 asn1_type_name=self.asn1_type_name,
4840 obj_name=self.__class__.__name__,
4841 decode_path=decode_path,
4842 value=self.choice if self.ready else None,
4843 optional=self.optional,
4844 default=self == self.default,
4845 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4846 expl=None if self._expl is None else tag_decode(self._expl),
4851 expl_lenindef=self.expl_lenindef,
4855 yield self.value.pps(decode_path=decode_path + (self.choice,))
4856 for pp in self.pps_lenindef(decode_path):
4860 class PrimitiveTypes(Choice):
4861 """Predefined ``CHOICE`` for all generic primitive types
4863 It could be useful for general decoding of some unspecified values:
4865 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4866 OCTET STRING 3 bytes 666f6f
4867 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4871 schema = tuple((klass.__name__, klass()) for klass in (
4895 AnyState = namedtuple("AnyState", (
4908 ), **NAMEDTUPLE_KWARGS)
4912 """``ANY`` special type
4914 >>> Any(Integer(-123))
4916 >>> a = Any(OctetString(b"hello world").encode())
4917 ANY 040b68656c6c6f20776f726c64
4918 >>> hexenc(bytes(a))
4919 b'0x040x0bhello world'
4921 __slots__ = ("defined",)
4922 tag_default = tag_encode(0)
4923 asn1_type_name = "ANY"
4933 :param value: set the value. Either any kind of pyderasn's
4934 **ready** object, or bytes. Pay attention that
4935 **no** validation is performed is raw binary value
4937 :param bytes expl: override default tag with ``EXPLICIT`` one
4938 :param bool optional: is object ``OPTIONAL`` in sequence
4940 super(Any, self).__init__(None, expl, None, optional, _decoded)
4941 self._value = None if value is None else self._value_sanitize(value)
4944 def _value_sanitize(self, value):
4945 if value.__class__ == binary_type:
4947 if isinstance(value, self.__class__):
4949 if isinstance(value, Obj):
4950 return value.encode()
4951 raise InvalidValueType((self.__class__, Obj, binary_type))
4955 return self._value is not None
4959 if self.expl_lenindef or self.lenindef:
4961 if self.defined is None:
4963 return self.defined[1].bered
4965 def __getstate__(self):
4981 def __setstate__(self, state):
4982 super(Any, self).__setstate__(state)
4983 self._value = state.value
4984 self.tag = state.tag
4985 self._expl = state.expl
4986 self.optional = state.optional
4987 self.offset = state.offset
4988 self.llen = state.llen
4989 self.vlen = state.vlen
4990 self.expl_lenindef = state.expl_lenindef
4991 self.lenindef = state.lenindef
4992 self.ber_encoded = state.ber_encoded
4993 self.defined = state.defined
4995 def __eq__(self, their):
4996 if their.__class__ == binary_type:
4997 return self._value == their
4998 if issubclass(their.__class__, Any):
4999 return self._value == their._value
5008 return self.__class__(
5010 expl=self._expl if expl is None else expl,
5011 optional=self.optional if optional is None else optional,
5014 def __bytes__(self):
5015 self._assert_ready()
5023 self._assert_ready()
5026 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5028 t, tlen, lv = tag_strip(tlv)
5029 except DecodeError as err:
5030 raise err.__class__(
5032 klass=self.__class__,
5033 decode_path=decode_path,
5037 l, llen, v = len_decode(lv)
5038 except LenIndefForm as err:
5039 if not ctx.get("bered", False):
5040 raise err.__class__(
5042 klass=self.__class__,
5043 decode_path=decode_path,
5046 llen, vlen, v = 1, 0, lv[1:]
5047 sub_offset = offset + tlen + llen
5049 while v[:EOC_LEN].tobytes() != EOC:
5050 chunk, v = Any().decode(
5053 decode_path=decode_path + (str(chunk_i),),
5056 _ctx_immutable=False,
5058 vlen += chunk.tlvlen
5059 sub_offset += chunk.tlvlen
5061 tlvlen = tlen + llen + vlen + EOC_LEN
5062 obj = self.__class__(
5063 value=tlv[:tlvlen].tobytes(),
5065 optional=self.optional,
5066 _decoded=(offset, 0, tlvlen),
5069 obj.tag = t.tobytes()
5070 return obj, v[EOC_LEN:]
5071 except DecodeError as err:
5072 raise err.__class__(
5074 klass=self.__class__,
5075 decode_path=decode_path,
5079 raise NotEnoughData(
5080 "encoded length is longer than data",
5081 klass=self.__class__,
5082 decode_path=decode_path,
5085 tlvlen = tlen + llen + l
5086 v, tail = tlv[:tlvlen], v[l:]
5087 obj = self.__class__(
5090 optional=self.optional,
5091 _decoded=(offset, 0, tlvlen),
5093 obj.tag = t.tobytes()
5097 return pp_console_row(next(self.pps()))
5099 def pps(self, decode_path=()):
5102 asn1_type_name=self.asn1_type_name,
5103 obj_name=self.__class__.__name__,
5104 decode_path=decode_path,
5105 blob=self._value if self.ready else None,
5106 optional=self.optional,
5107 default=self == self.default,
5108 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5109 expl=None if self._expl is None else tag_decode(self._expl),
5114 expl_offset=self.expl_offset if self.expled else None,
5115 expl_tlen=self.expl_tlen if self.expled else None,
5116 expl_llen=self.expl_llen if self.expled else None,
5117 expl_vlen=self.expl_vlen if self.expled else None,
5118 expl_lenindef=self.expl_lenindef,
5119 lenindef=self.lenindef,
5122 defined_by, defined = self.defined or (None, None)
5123 if defined_by is not None:
5125 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5127 for pp in self.pps_lenindef(decode_path):
5131 ########################################################################
5132 # ASN.1 constructed types
5133 ########################################################################
5135 def get_def_by_path(defines_by_path, sub_decode_path):
5136 """Get define by decode path
5138 for path, define in defines_by_path:
5139 if len(path) != len(sub_decode_path):
5141 for p1, p2 in zip(path, sub_decode_path):
5142 if (p1 != any) and (p1 != p2):
5148 def abs_decode_path(decode_path, rel_path):
5149 """Create an absolute decode path from current and relative ones
5151 :param decode_path: current decode path, starting point. Tuple of strings
5152 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5153 If first tuple's element is "/", then treat it as
5154 an absolute path, ignoring ``decode_path`` as
5155 starting point. Also this tuple can contain ".."
5156 elements, stripping the leading element from
5159 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5160 ("foo", "bar", "baz", "whatever")
5161 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5163 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5166 if rel_path[0] == "/":
5168 if rel_path[0] == "..":
5169 return abs_decode_path(decode_path[:-1], rel_path[1:])
5170 return decode_path + rel_path
5173 SequenceState = namedtuple("SequenceState", (
5187 ), **NAMEDTUPLE_KWARGS)
5190 class Sequence(Obj):
5191 """``SEQUENCE`` structure type
5193 You have to make specification of sequence::
5195 class Extension(Sequence):
5197 ("extnID", ObjectIdentifier()),
5198 ("critical", Boolean(default=False)),
5199 ("extnValue", OctetString()),
5202 Then, you can work with it as with dictionary.
5204 >>> ext = Extension()
5205 >>> Extension().specs
5207 ('extnID', OBJECT IDENTIFIER),
5208 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5209 ('extnValue', OCTET STRING),
5211 >>> ext["extnID"] = "1.2.3"
5212 Traceback (most recent call last):
5213 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5214 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5216 You can determine if sequence is ready to be encoded:
5221 Traceback (most recent call last):
5222 pyderasn.ObjNotReady: object is not ready: extnValue
5223 >>> ext["extnValue"] = OctetString(b"foobar")
5227 Value you want to assign, must have the same **type** as in
5228 corresponding specification, but it can have different tags,
5229 optional/default attributes -- they will be taken from specification
5232 class TBSCertificate(Sequence):
5234 ("version", Version(expl=tag_ctxc(0), default="v1")),
5237 >>> tbs = TBSCertificate()
5238 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5240 Assign ``None`` to remove value from sequence.
5242 You can set values in Sequence during its initialization:
5244 >>> AlgorithmIdentifier((
5245 ("algorithm", ObjectIdentifier("1.2.3")),
5246 ("parameters", Any(Null()))
5248 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5250 You can determine if value exists/set in the sequence and take its value:
5252 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5255 OBJECT IDENTIFIER 1.2.3
5257 But pay attention that if value has default, then it won't be (not
5258 in) in the sequence (because ``DEFAULT`` must not be encoded in
5259 DER), but you can read its value:
5261 >>> "critical" in ext, ext["critical"]
5262 (False, BOOLEAN False)
5263 >>> ext["critical"] = Boolean(True)
5264 >>> "critical" in ext, ext["critical"]
5265 (True, BOOLEAN True)
5267 All defaulted values are always optional.
5269 .. _allow_default_values_ctx:
5271 DER prohibits default value encoding and will raise an error if
5272 default value is unexpectedly met during decode.
5273 If :ref:`bered <bered_ctx>` context option is set, then no error
5274 will be raised, but ``bered`` attribute set. You can disable strict
5275 defaulted values existence validation by setting
5276 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5278 Two sequences are equal if they have equal specification (schema),
5279 implicit/explicit tagging and the same values.
5281 __slots__ = ("specs",)
5282 tag_default = tag_encode(form=TagFormConstructed, num=16)
5283 asn1_type_name = "SEQUENCE"
5295 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5297 schema = getattr(self, "schema", ())
5299 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5302 if value is not None:
5303 if issubclass(value.__class__, Sequence):
5304 self._value = value._value
5305 elif hasattr(value, "__iter__"):
5306 for seq_key, seq_value in value:
5307 self[seq_key] = seq_value
5309 raise InvalidValueType((Sequence,))
5310 if default is not None:
5311 if not issubclass(default.__class__, Sequence):
5312 raise InvalidValueType((Sequence,))
5313 default_value = default._value
5314 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5315 default_obj.specs = self.specs
5316 default_obj._value = default_value
5317 self.default = default_obj
5319 self._value = copy(default_obj._value)
5323 for name, spec in iteritems(self.specs):
5324 value = self._value.get(name)
5335 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5337 return any(value.bered for value in itervalues(self._value))
5339 def __getstate__(self):
5340 return SequenceState(
5343 {k: copy(v) for k, v in iteritems(self._value)},
5356 def __setstate__(self, state):
5357 super(Sequence, self).__setstate__(state)
5358 self.specs = state.specs
5359 self._value = state.value
5360 self.tag = state.tag
5361 self._expl = state.expl
5362 self.default = state.default
5363 self.optional = state.optional
5364 self.offset = state.offset
5365 self.llen = state.llen
5366 self.vlen = state.vlen
5367 self.expl_lenindef = state.expl_lenindef
5368 self.lenindef = state.lenindef
5369 self.ber_encoded = state.ber_encoded
5371 def __eq__(self, their):
5372 if not isinstance(their, self.__class__):
5375 self.specs == their.specs and
5376 self.tag == their.tag and
5377 self._expl == their._expl and
5378 self._value == their._value
5389 return self.__class__(
5392 impl=self.tag if impl is None else impl,
5393 expl=self._expl if expl is None else expl,
5394 default=self.default if default is None else default,
5395 optional=self.optional if optional is None else optional,
5398 def __contains__(self, key):
5399 return key in self._value
5401 def __setitem__(self, key, value):
5402 spec = self.specs.get(key)
5404 raise ObjUnknown(key)
5406 self._value.pop(key, None)
5408 if not isinstance(value, spec.__class__):
5409 raise InvalidValueType((spec.__class__,))
5410 value = spec(value=value)
5411 if spec.default is not None and value == spec.default:
5412 self._value.pop(key, None)
5414 self._value[key] = value
5416 def __getitem__(self, key):
5417 value = self._value.get(key)
5418 if value is not None:
5420 spec = self.specs.get(key)
5422 raise ObjUnknown(key)
5423 if spec.default is not None:
5427 def _encoded_values(self):
5429 for name, spec in iteritems(self.specs):
5430 value = self._value.get(name)
5434 raise ObjNotReady(name)
5435 raws.append(value.encode())
5439 v = b"".join(self._encoded_values())
5440 return b"".join((self.tag, len_encode(len(v)), v))
5442 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5444 t, tlen, lv = tag_strip(tlv)
5445 except DecodeError as err:
5446 raise err.__class__(
5448 klass=self.__class__,
5449 decode_path=decode_path,
5454 klass=self.__class__,
5455 decode_path=decode_path,
5458 if tag_only: # pragma: no cover
5461 ctx_bered = ctx.get("bered", False)
5463 l, llen, v = len_decode(lv)
5464 except LenIndefForm as err:
5466 raise err.__class__(
5468 klass=self.__class__,
5469 decode_path=decode_path,
5472 l, llen, v = 0, 1, lv[1:]
5474 except DecodeError as err:
5475 raise err.__class__(
5477 klass=self.__class__,
5478 decode_path=decode_path,
5482 raise NotEnoughData(
5483 "encoded length is longer than data",
5484 klass=self.__class__,
5485 decode_path=decode_path,
5489 v, tail = v[:l], v[l:]
5491 sub_offset = offset + tlen + llen
5494 ctx_allow_default_values = ctx.get("allow_default_values", False)
5495 for name, spec in iteritems(self.specs):
5496 if spec.optional and (
5497 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5501 sub_decode_path = decode_path + (name,)
5503 value, v_tail = spec.decode(
5507 decode_path=sub_decode_path,
5509 _ctx_immutable=False,
5511 except TagMismatch as err:
5512 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5516 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5517 if defined is not None:
5518 defined_by, defined_spec = defined
5519 if issubclass(value.__class__, SequenceOf):
5520 for i, _value in enumerate(value):
5521 sub_sub_decode_path = sub_decode_path + (
5523 DecodePathDefBy(defined_by),
5525 defined_value, defined_tail = defined_spec.decode(
5526 memoryview(bytes(_value)),
5528 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5529 if value.expled else (value.tlen + value.llen)
5532 decode_path=sub_sub_decode_path,
5534 _ctx_immutable=False,
5536 if len(defined_tail) > 0:
5539 klass=self.__class__,
5540 decode_path=sub_sub_decode_path,
5543 _value.defined = (defined_by, defined_value)
5545 defined_value, defined_tail = defined_spec.decode(
5546 memoryview(bytes(value)),
5548 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5549 if value.expled else (value.tlen + value.llen)
5552 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5554 _ctx_immutable=False,
5556 if len(defined_tail) > 0:
5559 klass=self.__class__,
5560 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5563 value.defined = (defined_by, defined_value)
5565 value_len = value.fulllen
5567 sub_offset += value_len
5569 if spec.default is not None and value == spec.default:
5570 if ctx_bered or ctx_allow_default_values:
5574 "DEFAULT value met",
5575 klass=self.__class__,
5576 decode_path=sub_decode_path,
5579 values[name] = value
5581 spec_defines = getattr(spec, "defines", ())
5582 if len(spec_defines) == 0:
5583 defines_by_path = ctx.get("defines_by_path", ())
5584 if len(defines_by_path) > 0:
5585 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5586 if spec_defines is not None and len(spec_defines) > 0:
5587 for rel_path, schema in spec_defines:
5588 defined = schema.get(value, None)
5589 if defined is not None:
5590 ctx.setdefault("_defines", []).append((
5591 abs_decode_path(sub_decode_path[:-1], rel_path),
5595 if v[:EOC_LEN].tobytes() != EOC:
5598 klass=self.__class__,
5599 decode_path=decode_path,
5607 klass=self.__class__,
5608 decode_path=decode_path,
5611 obj = self.__class__(
5615 default=self.default,
5616 optional=self.optional,
5617 _decoded=(offset, llen, vlen),
5620 obj.lenindef = lenindef
5621 obj.ber_encoded = ber_encoded
5625 value = pp_console_row(next(self.pps()))
5627 for name in self.specs:
5628 _value = self._value.get(name)
5631 cols.append("%s: %s" % (name, repr(_value)))
5632 return "%s[%s]" % (value, "; ".join(cols))
5634 def pps(self, decode_path=()):
5637 asn1_type_name=self.asn1_type_name,
5638 obj_name=self.__class__.__name__,
5639 decode_path=decode_path,
5640 optional=self.optional,
5641 default=self == self.default,
5642 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5643 expl=None if self._expl is None else tag_decode(self._expl),
5648 expl_offset=self.expl_offset if self.expled else None,
5649 expl_tlen=self.expl_tlen if self.expled else None,
5650 expl_llen=self.expl_llen if self.expled else None,
5651 expl_vlen=self.expl_vlen if self.expled else None,
5652 expl_lenindef=self.expl_lenindef,
5653 lenindef=self.lenindef,
5654 ber_encoded=self.ber_encoded,
5657 for name in self.specs:
5658 value = self._value.get(name)
5661 yield value.pps(decode_path=decode_path + (name,))
5662 for pp in self.pps_lenindef(decode_path):
5666 class Set(Sequence):
5667 """``SET`` structure type
5669 Its usage is identical to :py:class:`pyderasn.Sequence`.
5671 .. _allow_unordered_set_ctx:
5673 DER prohibits unordered values encoding and will raise an error
5674 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5675 then no error will occure. Also you can disable strict values
5676 ordering check by setting ``"allow_unordered_set": True``
5677 :ref:`context <ctx>` option.
5680 tag_default = tag_encode(form=TagFormConstructed, num=17)
5681 asn1_type_name = "SET"
5684 raws = self._encoded_values()
5687 return b"".join((self.tag, len_encode(len(v)), v))
5689 def _specs_items(self):
5690 return iteritems(self.specs)
5692 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5694 t, tlen, lv = tag_strip(tlv)
5695 except DecodeError as err:
5696 raise err.__class__(
5698 klass=self.__class__,
5699 decode_path=decode_path,
5704 klass=self.__class__,
5705 decode_path=decode_path,
5711 ctx_bered = ctx.get("bered", False)
5713 l, llen, v = len_decode(lv)
5714 except LenIndefForm as err:
5716 raise err.__class__(
5718 klass=self.__class__,
5719 decode_path=decode_path,
5722 l, llen, v = 0, 1, lv[1:]
5724 except DecodeError as err:
5725 raise err.__class__(
5727 klass=self.__class__,
5728 decode_path=decode_path,
5732 raise NotEnoughData(
5733 "encoded length is longer than data",
5734 klass=self.__class__,
5738 v, tail = v[:l], v[l:]
5740 sub_offset = offset + tlen + llen
5743 ctx_allow_default_values = ctx.get("allow_default_values", False)
5744 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5745 value_prev = memoryview(v[:0])
5748 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5750 for name, spec in self._specs_items():
5751 sub_decode_path = decode_path + (name,)
5757 decode_path=sub_decode_path,
5760 _ctx_immutable=False,
5767 klass=self.__class__,
5768 decode_path=decode_path,
5771 value, v_tail = spec.decode(
5775 decode_path=sub_decode_path,
5777 _ctx_immutable=False,
5779 value_len = value.fulllen
5780 if value_prev.tobytes() > v[:value_len].tobytes():
5781 if ctx_bered or ctx_allow_unordered_set:
5785 "unordered " + self.asn1_type_name,
5786 klass=self.__class__,
5787 decode_path=sub_decode_path,
5790 if spec.default is None or value != spec.default:
5792 elif ctx_bered or ctx_allow_default_values:
5796 "DEFAULT value met",
5797 klass=self.__class__,
5798 decode_path=sub_decode_path,
5801 values[name] = value
5802 value_prev = v[:value_len]
5803 sub_offset += value_len
5806 obj = self.__class__(
5810 default=self.default,
5811 optional=self.optional,
5812 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5815 if v[:EOC_LEN].tobytes() != EOC:
5818 klass=self.__class__,
5819 decode_path=decode_path,
5827 "not all values are ready",
5828 klass=self.__class__,
5829 decode_path=decode_path,
5832 obj.ber_encoded = ber_encoded
5836 SequenceOfState = namedtuple("SequenceOfState", (
5852 ), **NAMEDTUPLE_KWARGS)
5855 class SequenceOf(Obj):
5856 """``SEQUENCE OF`` sequence type
5858 For that kind of type you must specify the object it will carry on
5859 (bounds are for example here, not required)::
5861 class Ints(SequenceOf):
5866 >>> ints.append(Integer(123))
5867 >>> ints.append(Integer(234))
5869 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5870 >>> [int(i) for i in ints]
5872 >>> ints.append(Integer(345))
5873 Traceback (most recent call last):
5874 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5877 >>> ints[1] = Integer(345)
5879 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5881 Also you can initialize sequence with preinitialized values:
5883 >>> ints = Ints([Integer(123), Integer(234)])
5885 __slots__ = ("spec", "_bound_min", "_bound_max")
5886 tag_default = tag_encode(form=TagFormConstructed, num=16)
5887 asn1_type_name = "SEQUENCE OF"
5900 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5902 schema = getattr(self, "schema", None)
5904 raise ValueError("schema must be specified")
5906 self._bound_min, self._bound_max = getattr(
5910 ) if bounds is None else bounds
5912 if value is not None:
5913 self._value = self._value_sanitize(value)
5914 if default is not None:
5915 default_value = self._value_sanitize(default)
5916 default_obj = self.__class__(
5921 default_obj._value = default_value
5922 self.default = default_obj
5924 self._value = copy(default_obj._value)
5926 def _value_sanitize(self, value):
5927 if issubclass(value.__class__, SequenceOf):
5928 value = value._value
5929 elif hasattr(value, "__iter__"):
5932 raise InvalidValueType((self.__class__, iter))
5933 if not self._bound_min <= len(value) <= self._bound_max:
5934 raise BoundsError(self._bound_min, len(value), self._bound_max)
5936 if not isinstance(v, self.spec.__class__):
5937 raise InvalidValueType((self.spec.__class__,))
5942 return all(v.ready for v in self._value)
5946 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5948 return any(v.bered for v in self._value)
5950 def __getstate__(self):
5951 return SequenceOfState(
5954 [copy(v) for v in self._value],
5969 def __setstate__(self, state):
5970 super(SequenceOf, self).__setstate__(state)
5971 self.spec = state.spec
5972 self._value = state.value
5973 self._bound_min = state.bound_min
5974 self._bound_max = state.bound_max
5975 self.tag = state.tag
5976 self._expl = state.expl
5977 self.default = state.default
5978 self.optional = state.optional
5979 self.offset = state.offset
5980 self.llen = state.llen
5981 self.vlen = state.vlen
5982 self.expl_lenindef = state.expl_lenindef
5983 self.lenindef = state.lenindef
5984 self.ber_encoded = state.ber_encoded
5986 def __eq__(self, their):
5987 if isinstance(their, self.__class__):
5989 self.spec == their.spec and
5990 self.tag == their.tag and
5991 self._expl == their._expl and
5992 self._value == their._value
5994 if hasattr(their, "__iter__"):
5995 return self._value == list(their)
6007 return self.__class__(
6011 (self._bound_min, self._bound_max)
6012 if bounds is None else bounds
6014 impl=self.tag if impl is None else impl,
6015 expl=self._expl if expl is None else expl,
6016 default=self.default if default is None else default,
6017 optional=self.optional if optional is None else optional,
6020 def __contains__(self, key):
6021 return key in self._value
6023 def append(self, value):
6024 if not isinstance(value, self.spec.__class__):
6025 raise InvalidValueType((self.spec.__class__,))
6026 if len(self._value) + 1 > self._bound_max:
6029 len(self._value) + 1,
6032 self._value.append(value)
6035 self._assert_ready()
6036 return iter(self._value)
6039 self._assert_ready()
6040 return len(self._value)
6042 def __setitem__(self, key, value):
6043 if not isinstance(value, self.spec.__class__):
6044 raise InvalidValueType((self.spec.__class__,))
6045 self._value[key] = self.spec(value=value)
6047 def __getitem__(self, key):
6048 return self._value[key]
6050 def _encoded_values(self):
6051 return [v.encode() for v in self._value]
6054 v = b"".join(self._encoded_values())
6055 return b"".join((self.tag, len_encode(len(v)), v))
6057 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6059 t, tlen, lv = tag_strip(tlv)
6060 except DecodeError as err:
6061 raise err.__class__(
6063 klass=self.__class__,
6064 decode_path=decode_path,
6069 klass=self.__class__,
6070 decode_path=decode_path,
6076 ctx_bered = ctx.get("bered", False)
6078 l, llen, v = len_decode(lv)
6079 except LenIndefForm as err:
6081 raise err.__class__(
6083 klass=self.__class__,
6084 decode_path=decode_path,
6087 l, llen, v = 0, 1, lv[1:]
6089 except DecodeError as err:
6090 raise err.__class__(
6092 klass=self.__class__,
6093 decode_path=decode_path,
6097 raise NotEnoughData(
6098 "encoded length is longer than data",
6099 klass=self.__class__,
6100 decode_path=decode_path,
6104 v, tail = v[:l], v[l:]
6106 sub_offset = offset + tlen + llen
6108 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6109 value_prev = memoryview(v[:0])
6113 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6115 sub_decode_path = decode_path + (str(len(_value)),)
6116 value, v_tail = spec.decode(
6120 decode_path=sub_decode_path,
6122 _ctx_immutable=False,
6124 value_len = value.fulllen
6126 if value_prev.tobytes() > v[:value_len].tobytes():
6127 if ctx_bered or ctx_allow_unordered_set:
6131 "unordered " + self.asn1_type_name,
6132 klass=self.__class__,
6133 decode_path=sub_decode_path,
6136 value_prev = v[:value_len]
6137 _value.append(value)
6138 sub_offset += value_len
6142 obj = self.__class__(
6145 bounds=(self._bound_min, self._bound_max),
6148 default=self.default,
6149 optional=self.optional,
6150 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6152 except BoundsError as err:
6155 klass=self.__class__,
6156 decode_path=decode_path,
6160 if v[:EOC_LEN].tobytes() != EOC:
6163 klass=self.__class__,
6164 decode_path=decode_path,
6169 obj.ber_encoded = ber_encoded
6174 pp_console_row(next(self.pps())),
6175 ", ".join(repr(v) for v in self._value),
6178 def pps(self, decode_path=()):
6181 asn1_type_name=self.asn1_type_name,
6182 obj_name=self.__class__.__name__,
6183 decode_path=decode_path,
6184 optional=self.optional,
6185 default=self == self.default,
6186 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6187 expl=None if self._expl is None else tag_decode(self._expl),
6192 expl_offset=self.expl_offset if self.expled else None,
6193 expl_tlen=self.expl_tlen if self.expled else None,
6194 expl_llen=self.expl_llen if self.expled else None,
6195 expl_vlen=self.expl_vlen if self.expled else None,
6196 expl_lenindef=self.expl_lenindef,
6197 lenindef=self.lenindef,
6198 ber_encoded=self.ber_encoded,
6201 for i, value in enumerate(self._value):
6202 yield value.pps(decode_path=decode_path + (str(i),))
6203 for pp in self.pps_lenindef(decode_path):
6207 class SetOf(SequenceOf):
6208 """``SET OF`` sequence type
6210 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6213 tag_default = tag_encode(form=TagFormConstructed, num=17)
6214 asn1_type_name = "SET OF"
6217 raws = self._encoded_values()
6220 return b"".join((self.tag, len_encode(len(v)), v))
6222 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6223 return super(SetOf, self)._decode(
6229 ordering_check=True,
6233 def obj_by_path(pypath): # pragma: no cover
6234 """Import object specified as string Python path
6236 Modules must be separated from classes/functions with ``:``.
6238 >>> obj_by_path("foo.bar:Baz")
6239 <class 'foo.bar.Baz'>
6240 >>> obj_by_path("foo.bar:Baz.boo")
6241 <classmethod 'foo.bar.Baz.boo'>
6243 mod, objs = pypath.rsplit(":", 1)
6244 from importlib import import_module
6245 obj = import_module(mod)
6246 for obj_name in objs.split("."):
6247 obj = getattr(obj, obj_name)
6251 def generic_decoder(): # pragma: no cover
6252 # All of this below is a big hack with self references
6253 choice = PrimitiveTypes()
6254 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6255 choice.specs["SetOf"] = SetOf(schema=choice)
6256 for i in six_xrange(31):
6257 choice.specs["SequenceOf%d" % i] = SequenceOf(
6261 choice.specs["Any"] = Any()
6263 # Class name equals to type name, to omit it from output
6264 class SEQUENCEOF(SequenceOf):
6272 with_decode_path=False,
6273 decode_path_only=(),
6275 def _pprint_pps(pps):
6277 if hasattr(pp, "_fields"):
6279 decode_path_only != () and
6280 pp.decode_path[:len(decode_path_only)] != decode_path_only
6283 if pp.asn1_type_name == Choice.asn1_type_name:
6285 pp_kwargs = pp._asdict()
6286 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6287 pp = _pp(**pp_kwargs)
6288 yield pp_console_row(
6293 with_colours=with_colours,
6294 with_decode_path=with_decode_path,
6295 decode_path_len_decrease=len(decode_path_only),
6297 for row in pp_console_blob(
6299 decode_path_len_decrease=len(decode_path_only),
6303 for row in _pprint_pps(pp):
6305 return "\n".join(_pprint_pps(obj.pps()))
6306 return SEQUENCEOF(), pprint_any
6309 def main(): # pragma: no cover
6311 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6312 parser.add_argument(
6316 help="Skip that number of bytes from the beginning",
6318 parser.add_argument(
6320 help="Python paths to dictionary with OIDs, comma separated",
6322 parser.add_argument(
6324 help="Python path to schema definition to use",
6326 parser.add_argument(
6327 "--defines-by-path",
6328 help="Python path to decoder's defines_by_path",
6330 parser.add_argument(
6332 action="store_true",
6333 help="Disallow BER encoding",
6335 parser.add_argument(
6336 "--print-decode-path",
6337 action="store_true",
6338 help="Print decode paths",
6340 parser.add_argument(
6341 "--decode-path-only",
6342 help="Print only specified decode path",
6344 parser.add_argument(
6346 action="store_true",
6347 help="Allow explicit tag out-of-bound",
6349 parser.add_argument(
6351 type=argparse.FileType("rb"),
6352 help="Path to DER file you want to decode",
6354 args = parser.parse_args()
6355 args.DERFile.seek(args.skip)
6356 der = memoryview(args.DERFile.read())
6357 args.DERFile.close()
6359 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6360 if args.oids else ()
6363 schema = obj_by_path(args.schema)
6364 from functools import partial
6365 pprinter = partial(pprint, big_blobs=True)
6367 schema, pprinter = generic_decoder()
6369 "bered": not args.nobered,
6370 "allow_expl_oob": args.allow_expl_oob,
6372 if args.defines_by_path is not None:
6373 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6374 obj, tail = schema().decode(der, ctx=ctx)
6378 with_colours=environ.get("NO_COLOR") is None,
6379 with_decode_path=args.print_decode_path,
6381 () if args.decode_path_only is None else
6382 tuple(args.decode_path_only.split(":"))
6386 print("\nTrailing data: %s" % hexenc(tail))
6389 if __name__ == "__main__":