3 # cython: language_level=3
4 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
5 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, version 3 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Python ASN.1 DER/BER codec with abstract structures
20 This library allows you to marshal various structures in ASN.1 DER
21 format, unmarshal them in BER/CER/DER ones.
25 >>> Integer().decod(raw) == i
28 There are primitive types, holding single values
29 (:py:class:`pyderasn.BitString`,
30 :py:class:`pyderasn.Boolean`,
31 :py:class:`pyderasn.Enumerated`,
32 :py:class:`pyderasn.GeneralizedTime`,
33 :py:class:`pyderasn.Integer`,
34 :py:class:`pyderasn.Null`,
35 :py:class:`pyderasn.ObjectIdentifier`,
36 :py:class:`pyderasn.OctetString`,
37 :py:class:`pyderasn.UTCTime`,
38 :py:class:`various strings <pyderasn.CommonString>`
39 (:py:class:`pyderasn.BMPString`,
40 :py:class:`pyderasn.GeneralString`,
41 :py:class:`pyderasn.GraphicString`,
42 :py:class:`pyderasn.IA5String`,
43 :py:class:`pyderasn.ISO646String`,
44 :py:class:`pyderasn.NumericString`,
45 :py:class:`pyderasn.PrintableString`,
46 :py:class:`pyderasn.T61String`,
47 :py:class:`pyderasn.TeletexString`,
48 :py:class:`pyderasn.UniversalString`,
49 :py:class:`pyderasn.UTF8String`,
50 :py:class:`pyderasn.VideotexString`,
51 :py:class:`pyderasn.VisibleString`)),
52 constructed types, holding multiple primitive types
53 (:py:class:`pyderasn.Sequence`,
54 :py:class:`pyderasn.SequenceOf`,
55 :py:class:`pyderasn.Set`,
56 :py:class:`pyderasn.SetOf`),
57 and special types like
58 :py:class:`pyderasn.Any` and
59 :py:class:`pyderasn.Choice`.
67 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
68 the default tag used during coding process. You can override it with
69 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
70 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
71 argument or ``expl`` class attribute). Both arguments take raw binary
72 string, containing that tag. You can **not** set implicit and explicit
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
78 number. Pay attention that explicit tags always have *constructed* tag
79 (``tag_ctxc``), but implicit tags for primitive types are primitive
84 >>> Integer(impl=tag_ctxp(1))
86 >>> Integer(expl=tag_ctxc(2))
89 Implicit tag is not explicitly shown.
91 Two objects of the same type, but with different implicit/explicit tags
94 You can get object's effective tag (either default or implicited) through
95 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
98 >>> tag_decode(tag_ctxc(123))
100 >>> klass, form, num = tag_decode(tag_ctxc(123))
101 >>> klass == TagClassContext
103 >>> form == TagFormConstructed
106 To determine if object has explicit tag, use ``expled`` boolean property
107 and ``expl_tag`` property, returning explicit tag's value.
112 Many objects in sequences could be ``OPTIONAL`` and could have
113 ``DEFAULT`` value. You can specify that object's property using
114 corresponding keyword arguments.
116 >>> Integer(optional=True, default=123)
117 INTEGER 123 OPTIONAL DEFAULT
119 Those specifications do not play any role in primitive value encoding,
120 but are taken into account when dealing with sequences holding them. For
121 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
124 class Version(Integer):
130 class TBSCertificate(Sequence):
132 ("version", Version(expl=tag_ctxc(0), default="v1")),
135 When default argument is used and value is not specified, then it equals
143 Some objects give ability to set value size constraints. This is either
144 possible integer value, or allowed length of various strings and
145 sequences. Constraints are set in the following way::
150 And values satisfaction is checked as: ``MIN <= X <= MAX``.
152 For simplicity you can also set bounds the following way::
154 bounded_x = X(bounds=(MIN, MAX))
156 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
162 All objects have ``ready`` boolean property, that tells if object is
163 ready to be encoded. If that kind of action is performed on unready
164 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
166 All objects are friendly to ``copy.copy()`` and copied objects can be
169 Also all objects can be safely ``pickle``-d, but pay attention that
170 pickling among different PyDERASN versions is prohibited.
177 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
178 ``offset`` optional argument could be used to set initial object's
179 offset in the binary data, for convenience. It returns decoded object
180 and remaining unmarshalled data (tail). Internally all work is done on
181 ``memoryview(data)``, and you can leave returning tail as a memoryview,
182 by specifying ``leavemm=True`` argument.
184 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
185 immediately checks and raises if there is non-empty tail.
187 When object is decoded, ``decoded`` property is true and you can safely
188 use following properties:
190 * ``offset`` -- position including initial offset where object's tag starts
191 * ``tlen`` -- length of object's tag
192 * ``llen`` -- length of object's length value
193 * ``vlen`` -- length of object's value
194 * ``tlvlen`` -- length of the whole object
196 Pay attention that those values do **not** include anything related to
197 explicit tag. If you want to know information about it, then use:
199 * ``expled`` -- to know if explicit tag is set
200 * ``expl_offset`` (it is lesser than ``offset``)
203 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
204 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
206 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
209 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
216 You can specify so called context keyword argument during
217 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
218 various options governing decoding process.
220 Currently available context options:
222 * :ref:`allow_default_values <allow_default_values_ctx>`
223 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
224 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
225 * :ref:`bered <bered_ctx>`
226 * :ref:`defines_by_path <defines_by_path_ctx>`
233 All objects have ``pps()`` method, that is a generator of
234 :py:class:`pyderasn.PP` namedtuple, holding various raw information
235 about the object. If ``pps`` is called on sequences, then all underlying
236 ``PP`` will be yielded.
238 You can use :py:func:`pyderasn.pp_console_row` function, converting
239 those ``PP`` to human readable string. Actually exactly it is used for
240 all object ``repr``. But it is easy to write custom formatters.
242 >>> from pyderasn import pprint
243 >>> encoded = Integer(-12345).encode()
244 >>> obj, tail = Integer().decode(encoded)
245 >>> print(pprint(obj))
246 0 [1,1, 2] INTEGER -12345
250 Example certificate::
252 >>> print(pprint(crt))
253 0 [1,3,1604] Certificate SEQUENCE
254 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
255 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
256 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
257 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
258 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
259 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
261 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
262 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
263 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
264 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
265 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
266 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
267 . . . . . . . 13:02:45:53
269 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
270 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
271 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
273 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
274 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
275 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
280 Let's parse that output, human::
282 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
283 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
284 0 1 2 3 4 5 6 7 8 9 10 11
288 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
294 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
300 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
305 Offset of the object, where its DER/BER encoding begins.
306 Pay attention that it does **not** include explicit tag.
308 If explicit tag exists, then this is its length (tag + encoded length).
310 Length of object's tag. For example CHOICE does not have its own tag,
313 Length of encoded length.
315 Length of encoded value.
317 Visual indentation to show the depth of object in the hierarchy.
319 Object's name inside SEQUENCE/CHOICE.
321 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
322 here. "IMPLICIT" is omitted.
324 Object's class name, if set. Omitted if it is just an ordinary simple
325 value (like with ``algorithm`` in example above).
329 Object's value, if set. Can consist of multiple words (like OCTET/BIT
330 STRINGs above). We see ``v3`` value in Version, because it is named.
331 ``rdnSequence`` is the choice of CHOICE type.
333 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
334 default one, specified in the schema.
336 Shows does object contains any kind of BER encoded data (possibly
337 Sequence holding BER-encoded underlying value).
339 Only applicable to BER encoded data. Indefinite length encoding mark.
341 Only applicable to BER encoded data. If object has BER-specific
342 encoding, then ``BER`` will be shown. It does not depend on indefinite
343 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
344 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
353 ASN.1 structures often have ANY and OCTET STRING fields, that are
354 DEFINED BY some previously met ObjectIdentifier. This library provides
355 ability to specify mapping between some OID and field that must be
356 decoded with specific specification.
363 :py:class:`pyderasn.ObjectIdentifier` field inside
364 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
365 necessary for decoding structures. For example, CMS (:rfc:`5652`)
368 class ContentInfo(Sequence):
370 ("contentType", ContentType(defines=((("content",), {
371 id_digestedData: DigestedData(),
372 id_signedData: SignedData(),
374 ("content", Any(expl=tag_ctxc(0))),
377 ``contentType`` field tells that it defines that ``content`` must be
378 decoded with ``SignedData`` specification, if ``contentType`` equals to
379 ``id-signedData``. The same applies to ``DigestedData``. If
380 ``contentType`` contains unknown OID, then no automatic decoding is
383 You can specify multiple fields, that will be autodecoded -- that is why
384 ``defines`` kwarg is a sequence. You can specify defined field
385 relatively or absolutely to current decode path. For example ``defines``
386 for AlgorithmIdentifier of X.509's
387 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
391 id_ecPublicKey: ECParameters(),
392 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
394 (("..", "subjectPublicKey"), {
395 id_rsaEncryption: RSAPublicKey(),
396 id_GostR3410_2001: OctetString(),
400 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
401 autodecode its parameters inside SPKI's algorithm and its public key
404 Following types can be automatically decoded (DEFINED BY):
406 * :py:class:`pyderasn.Any`
407 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
408 * :py:class:`pyderasn.OctetString`
409 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
410 ``Any``/``BitString``/``OctetString``-s
412 When any of those fields is automatically decoded, then ``.defined``
413 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
414 was defined, ``value`` contains corresponding decoded value. For example
415 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
417 .. _defines_by_path_ctx:
419 defines_by_path context option
420 ______________________________
422 Sometimes you either can not or do not want to explicitly set *defines*
423 in the scheme. You can dynamically apply those definitions when calling
424 ``.decode()`` method.
426 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
427 value must be sequence of following tuples::
429 (decode_path, defines)
431 where ``decode_path`` is a tuple holding so-called decode path to the
432 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
433 ``defines``, holding exactly the same value as accepted in its
434 :ref:`keyword argument <defines>`.
436 For example, again for CMS, you want to automatically decode
437 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
438 structures it may hold. Also, automatically decode ``controlSequence``
441 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
444 ((("content",), {id_signedData: SignedData()}),),
449 DecodePathDefBy(id_signedData),
454 id_cct_PKIData: PKIData(),
455 id_cct_PKIResponse: PKIResponse(),
461 DecodePathDefBy(id_signedData),
464 DecodePathDefBy(id_cct_PKIResponse),
470 id_cmc_recipientNonce: RecipientNonce(),
471 id_cmc_senderNonce: SenderNonce(),
472 id_cmc_statusInfoV2: CMCStatusInfoV2(),
473 id_cmc_transactionId: TransactionId(),
478 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
479 First function is useful for path construction when some automatic
480 decoding is already done. ``any`` means literally any value it meet --
481 useful for SEQUENCE/SET OF-s.
488 By default PyDERASN accepts only DER encoded data. It always encodes to
489 DER. But you can optionally enable BER decoding with setting ``bered``
490 :ref:`context <ctx>` argument to True. Indefinite lengths and
491 constructed primitive types should be parsed successfully.
493 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
494 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
495 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
496 ``UTCTime``, ``GeneralizedTime`` can contain it.
497 * If object has an indefinite length encoding, then its ``lenindef``
498 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
499 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
501 * If object has an indefinite length encoded explicit tag, then
502 ``expl_lenindef`` is set to True.
503 * If object has either any of BER-related encoding (explicit tag
504 indefinite length, object's indefinite length, BER-encoding) or any
505 underlying component has that kind of encoding, then ``bered``
506 attribute is set to True. For example SignedData CMS can have
507 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
508 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
510 EOC (end-of-contents) token's length is taken in advance in object's
513 .. _allow_expl_oob_ctx:
515 Allow explicit tag out-of-bound
516 -------------------------------
518 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
519 one value, more than one object. If you set ``allow_expl_oob`` context
520 option to True, then no error will be raised and that invalid encoding
521 will be silently further processed. But pay attention that offsets and
522 lengths will be invalid in that case.
526 This option should be used only for skipping some decode errors, just
527 to see the decoded structure somehow.
531 .. autoclass:: pyderasn.Obj
539 .. autoclass:: pyderasn.Boolean
544 .. autoclass:: pyderasn.Integer
549 .. autoclass:: pyderasn.BitString
554 .. autoclass:: pyderasn.OctetString
559 .. autoclass:: pyderasn.Null
564 .. autoclass:: pyderasn.ObjectIdentifier
569 .. autoclass:: pyderasn.Enumerated
573 .. autoclass:: pyderasn.CommonString
577 .. autoclass:: pyderasn.NumericString
581 .. autoclass:: pyderasn.PrintableString
586 .. autoclass:: pyderasn.UTCTime
587 :members: __init__, todatetime
591 .. autoclass:: pyderasn.GeneralizedTime
598 .. autoclass:: pyderasn.Choice
603 .. autoclass:: PrimitiveTypes
607 .. autoclass:: pyderasn.Any
615 .. autoclass:: pyderasn.Sequence
620 .. autoclass:: pyderasn.Set
625 .. autoclass:: pyderasn.SequenceOf
630 .. autoclass:: pyderasn.SetOf
636 .. autofunction:: pyderasn.abs_decode_path
637 .. autofunction:: pyderasn.colonize_hex
638 .. autofunction:: pyderasn.hexenc
639 .. autofunction:: pyderasn.hexdec
640 .. autofunction:: pyderasn.tag_encode
641 .. autofunction:: pyderasn.tag_decode
642 .. autofunction:: pyderasn.tag_ctxp
643 .. autofunction:: pyderasn.tag_ctxc
644 .. autoclass:: pyderasn.DecodeError
646 .. autoclass:: pyderasn.NotEnoughData
647 .. autoclass:: pyderasn.ExceedingData
648 .. autoclass:: pyderasn.LenIndefForm
649 .. autoclass:: pyderasn.TagMismatch
650 .. autoclass:: pyderasn.InvalidLength
651 .. autoclass:: pyderasn.InvalidOID
652 .. autoclass:: pyderasn.ObjUnknown
653 .. autoclass:: pyderasn.ObjNotReady
654 .. autoclass:: pyderasn.InvalidValueType
655 .. autoclass:: pyderasn.BoundsError
658 from codecs import getdecoder
659 from codecs import getencoder
660 from collections import namedtuple
661 from collections import OrderedDict
662 from copy import copy
663 from datetime import datetime
664 from datetime import timedelta
665 from math import ceil
666 from os import environ
667 from string import ascii_letters
668 from string import digits
669 from unicodedata import category as unicat
671 from six import add_metaclass
672 from six import binary_type
673 from six import byte2int
674 from six import indexbytes
675 from six import int2byte
676 from six import integer_types
677 from six import iterbytes
678 from six import iteritems
679 from six import itervalues
681 from six import string_types
682 from six import text_type
683 from six import unichr as six_unichr
684 from six.moves import xrange as six_xrange
688 from termcolor import colored
689 except ImportError: # pragma: no cover
690 def colored(what, *args, **kwargs):
736 "TagClassApplication",
740 "TagFormConstructed",
751 TagClassUniversal = 0
752 TagClassApplication = 1 << 6
753 TagClassContext = 1 << 7
754 TagClassPrivate = 1 << 6 | 1 << 7
756 TagFormConstructed = 1 << 5
759 TagClassApplication: "APPLICATION ",
760 TagClassPrivate: "PRIVATE ",
761 TagClassUniversal: "UNIV ",
765 LENINDEF = b"\x80" # length indefinite mark
766 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
767 NAMEDTUPLE_KWARGS = {} if PY2 else {"module": __name__}
768 SET01 = frozenset(("0", "1"))
774 if (value[0] in "+- ") or (value[-1] == " "):
775 raise ValueError("non-pure integer")
778 def fractions2float(fractions_raw):
779 pureint(fractions_raw)
780 return float("0." + fractions_raw)
783 ########################################################################
785 ########################################################################
787 class ASN1Error(ValueError):
791 class DecodeError(ASN1Error):
792 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
794 :param str msg: reason of decode failing
795 :param klass: optional exact DecodeError inherited class (like
796 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
797 :py:exc:`InvalidLength`)
798 :param decode_path: tuple of strings. It contains human
799 readable names of the fields through which
800 decoding process has passed
801 :param int offset: binary offset where failure happened
803 super(DecodeError, self).__init__()
806 self.decode_path = decode_path
812 "" if self.klass is None else self.klass.__name__,
814 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
815 if len(self.decode_path) > 0 else ""
817 ("(at %d)" % self.offset) if self.offset > 0 else "",
823 return "%s(%s)" % (self.__class__.__name__, self)
826 class NotEnoughData(DecodeError):
830 class ExceedingData(ASN1Error):
831 def __init__(self, nbytes):
832 super(ExceedingData, self).__init__()
836 return "%d trailing bytes" % self.nbytes
839 return "%s(%s)" % (self.__class__.__name__, self)
842 class LenIndefForm(DecodeError):
846 class TagMismatch(DecodeError):
850 class InvalidLength(DecodeError):
854 class InvalidOID(DecodeError):
858 class ObjUnknown(ASN1Error):
859 def __init__(self, name):
860 super(ObjUnknown, self).__init__()
864 return "object is unknown: %s" % self.name
867 return "%s(%s)" % (self.__class__.__name__, self)
870 class ObjNotReady(ASN1Error):
871 def __init__(self, name):
872 super(ObjNotReady, self).__init__()
876 return "object is not ready: %s" % self.name
879 return "%s(%s)" % (self.__class__.__name__, self)
882 class InvalidValueType(ASN1Error):
883 def __init__(self, expected_types):
884 super(InvalidValueType, self).__init__()
885 self.expected_types = expected_types
888 return "invalid value type, expected: %s" % ", ".join(
889 [repr(t) for t in self.expected_types]
893 return "%s(%s)" % (self.__class__.__name__, self)
896 class BoundsError(ASN1Error):
897 def __init__(self, bound_min, value, bound_max):
898 super(BoundsError, self).__init__()
899 self.bound_min = bound_min
901 self.bound_max = bound_max
904 return "unsatisfied bounds: %s <= %s <= %s" % (
911 return "%s(%s)" % (self.__class__.__name__, self)
914 ########################################################################
916 ########################################################################
918 _hexdecoder = getdecoder("hex")
919 _hexencoder = getencoder("hex")
923 """Binary data to hexadecimal string convert
925 return _hexdecoder(data)[0]
929 """Hexadecimal string to binary data convert
931 return _hexencoder(data)[0].decode("ascii")
934 def int_bytes_len(num, byte_len=8):
937 return int(ceil(float(num.bit_length()) / byte_len))
940 def zero_ended_encode(num):
941 octets = bytearray(int_bytes_len(num, 7))
943 octets[i] = num & 0x7F
947 octets[i] = 0x80 | (num & 0x7F)
953 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
954 """Encode tag to binary form
956 :param int num: tag's number
957 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
958 :py:data:`pyderasn.TagClassContext`,
959 :py:data:`pyderasn.TagClassApplication`,
960 :py:data:`pyderasn.TagClassPrivate`)
961 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
962 :py:data:`pyderasn.TagFormConstructed`)
966 return int2byte(klass | form | num)
967 # [XX|X|11111][1.......][1.......] ... [0.......]
968 return int2byte(klass | form | 31) + zero_ended_encode(num)
972 """Decode tag from binary form
976 No validation is performed, assuming that it has already passed.
978 It returns tuple with three integers, as
979 :py:func:`pyderasn.tag_encode` accepts.
981 first_octet = byte2int(tag)
982 klass = first_octet & 0xC0
983 form = first_octet & 0x20
984 if first_octet & 0x1F < 0x1F:
985 return (klass, form, first_octet & 0x1F)
987 for octet in iterbytes(tag[1:]):
990 return (klass, form, num)
994 """Create CONTEXT PRIMITIVE tag
996 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1000 """Create CONTEXT CONSTRUCTED tag
1002 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1005 def tag_strip(data):
1006 """Take off tag from the data
1008 :returns: (encoded tag, tag length, remaining data)
1011 raise NotEnoughData("no data at all")
1012 if byte2int(data) & 0x1F < 31:
1013 return data[:1], 1, data[1:]
1018 raise DecodeError("unfinished tag")
1019 if indexbytes(data, i) & 0x80 == 0:
1022 return data[:i], i, data[i:]
1028 octets = bytearray(int_bytes_len(l) + 1)
1029 octets[0] = 0x80 | (len(octets) - 1)
1030 for i in six_xrange(len(octets) - 1, 0, -1):
1031 octets[i] = l & 0xFF
1033 return bytes(octets)
1036 def len_decode(data):
1039 :returns: (decoded length, length's length, remaining data)
1040 :raises LenIndefForm: if indefinite form encoding is met
1043 raise NotEnoughData("no data at all")
1044 first_octet = byte2int(data)
1045 if first_octet & 0x80 == 0:
1046 return first_octet, 1, data[1:]
1047 octets_num = first_octet & 0x7F
1048 if octets_num + 1 > len(data):
1049 raise NotEnoughData("encoded length is longer than data")
1051 raise LenIndefForm()
1052 if byte2int(data[1:]) == 0:
1053 raise DecodeError("leading zeros")
1055 for v in iterbytes(data[1:1 + octets_num]):
1058 raise DecodeError("long form instead of short one")
1059 return l, 1 + octets_num, data[1 + octets_num:]
1062 ########################################################################
1064 ########################################################################
1066 class AutoAddSlots(type):
1067 def __new__(cls, name, bases, _dict):
1068 _dict["__slots__"] = _dict.get("__slots__", ())
1069 return type.__new__(cls, name, bases, _dict)
1072 @add_metaclass(AutoAddSlots)
1074 """Common ASN.1 object class
1076 All ASN.1 types are inherited from it. It has metaclass that
1077 automatically adds ``__slots__`` to all inherited classes.
1101 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1102 self._expl = getattr(self, "expl", None) if expl is None else expl
1103 if self.tag != self.tag_default and self._expl is not None:
1104 raise ValueError("implicit and explicit tags can not be set simultaneously")
1105 if default is not None:
1107 self.optional = optional
1108 self.offset, self.llen, self.vlen = _decoded
1110 self.expl_lenindef = False
1111 self.lenindef = False
1112 self.ber_encoded = False
1115 def ready(self): # pragma: no cover
1116 """Is object ready to be encoded?
1118 raise NotImplementedError()
1120 def _assert_ready(self):
1122 raise ObjNotReady(self.__class__.__name__)
1126 """Is either object or any elements inside is BER encoded?
1128 return self.expl_lenindef or self.lenindef or self.ber_encoded
1132 """Is object decoded?
1134 return (self.llen + self.vlen) > 0
1136 def __getstate__(self): # pragma: no cover
1137 """Used for making safe to be mutable pickleable copies
1139 raise NotImplementedError()
1141 def __setstate__(self, state):
1142 if state.version != __version__:
1143 raise ValueError("data is pickled by different PyDERASN version")
1144 self.tag = self.tag_default
1148 self.optional = False
1152 self.expl_lenindef = False
1153 self.lenindef = False
1154 self.ber_encoded = False
1158 """See :ref:`decoding`
1160 return len(self.tag)
1164 """See :ref:`decoding`
1166 return self.tlen + self.llen + self.vlen
1168 def __str__(self): # pragma: no cover
1169 return self.__bytes__() if PY2 else self.__unicode__()
1171 def __ne__(self, their):
1172 return not(self == their)
1174 def __gt__(self, their): # pragma: no cover
1175 return not(self < their)
1177 def __le__(self, their): # pragma: no cover
1178 return (self == their) or (self < their)
1180 def __ge__(self, their): # pragma: no cover
1181 return (self == their) or (self > their)
1183 def _encode(self): # pragma: no cover
1184 raise NotImplementedError()
1186 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1187 raise NotImplementedError()
1190 """Encode the structure
1192 :returns: DER representation
1194 raw = self._encode()
1195 if self._expl is None:
1197 return b"".join((self._expl, len_encode(len(raw)), raw))
1199 def hexencode(self):
1200 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1202 return hexenc(self.encode())
1212 _ctx_immutable=True,
1216 :param data: either binary or memoryview
1217 :param int offset: initial data's offset
1218 :param bool leavemm: do we need to leave memoryview of remaining
1219 data as is, or convert it to bytes otherwise
1220 :param ctx: optional :ref:`context <ctx>` governing decoding process
1221 :param tag_only: decode only the tag, without length and contents
1222 (used only in Choice and Set structures, trying to
1223 determine if tag satisfies the scheme)
1224 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1226 :returns: (Obj, remaining data)
1228 .. seealso:: :ref:`decoding`
1232 elif _ctx_immutable:
1234 tlv = memoryview(data)
1235 if self._expl is None:
1236 result = self._decode(
1239 decode_path=decode_path,
1248 t, tlen, lv = tag_strip(tlv)
1249 except DecodeError as err:
1250 raise err.__class__(
1252 klass=self.__class__,
1253 decode_path=decode_path,
1258 klass=self.__class__,
1259 decode_path=decode_path,
1263 l, llen, v = len_decode(lv)
1264 except LenIndefForm as err:
1265 if not ctx.get("bered", False):
1266 raise err.__class__(
1268 klass=self.__class__,
1269 decode_path=decode_path,
1273 offset += tlen + llen
1274 result = self._decode(
1277 decode_path=decode_path,
1281 if tag_only: # pragma: no cover
1284 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1285 if eoc_expected.tobytes() != EOC:
1288 klass=self.__class__,
1289 decode_path=decode_path,
1293 obj.expl_lenindef = True
1294 except DecodeError as err:
1295 raise err.__class__(
1297 klass=self.__class__,
1298 decode_path=decode_path,
1303 raise NotEnoughData(
1304 "encoded length is longer than data",
1305 klass=self.__class__,
1306 decode_path=decode_path,
1309 result = self._decode(
1311 offset=offset + tlen + llen,
1312 decode_path=decode_path,
1316 if tag_only: # pragma: no cover
1319 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1321 "explicit tag out-of-bound, longer than data",
1322 klass=self.__class__,
1323 decode_path=decode_path,
1326 return obj, (tail if leavemm else tail.tobytes())
1328 def decod(self, data, offset=0, decode_path=(), ctx=None):
1329 """Decode the data, check that tail is empty
1331 :raises ExceedingData: if tail is not empty
1333 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1334 (decode without tail) that also checks that there is no
1337 obj, tail = self.decode(
1340 decode_path=decode_path,
1345 raise ExceedingData(len(tail))
1348 def hexdecode(self, data, *args, **kwargs):
1349 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1351 return self.decode(hexdec(data), *args, **kwargs)
1353 def hexdecod(self, data, *args, **kwargs):
1354 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1356 return self.decod(hexdec(data), *args, **kwargs)
1360 """See :ref:`decoding`
1362 return self._expl is not None
1366 """See :ref:`decoding`
1371 def expl_tlen(self):
1372 """See :ref:`decoding`
1374 return len(self._expl)
1377 def expl_llen(self):
1378 """See :ref:`decoding`
1380 if self.expl_lenindef:
1382 return len(len_encode(self.tlvlen))
1385 def expl_offset(self):
1386 """See :ref:`decoding`
1388 return self.offset - self.expl_tlen - self.expl_llen
1391 def expl_vlen(self):
1392 """See :ref:`decoding`
1397 def expl_tlvlen(self):
1398 """See :ref:`decoding`
1400 return self.expl_tlen + self.expl_llen + self.expl_vlen
1403 def fulloffset(self):
1404 """See :ref:`decoding`
1406 return self.expl_offset if self.expled else self.offset
1410 """See :ref:`decoding`
1412 return self.expl_tlvlen if self.expled else self.tlvlen
1414 def pps_lenindef(self, decode_path):
1415 if self.lenindef and not (
1416 getattr(self, "defined", None) is not None and
1417 self.defined[1].lenindef
1420 asn1_type_name="EOC",
1422 decode_path=decode_path,
1424 self.offset + self.tlvlen -
1425 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1433 if self.expl_lenindef:
1435 asn1_type_name="EOC",
1436 obj_name="EXPLICIT",
1437 decode_path=decode_path,
1438 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1447 class DecodePathDefBy(object):
1448 """DEFINED BY representation inside decode path
1450 __slots__ = ("defined_by",)
1452 def __init__(self, defined_by):
1453 self.defined_by = defined_by
1455 def __ne__(self, their):
1456 return not(self == their)
1458 def __eq__(self, their):
1459 if not isinstance(their, self.__class__):
1461 return self.defined_by == their.defined_by
1464 return "DEFINED BY " + str(self.defined_by)
1467 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1470 ########################################################################
1472 ########################################################################
1474 PP = namedtuple("PP", (
1497 ), **NAMEDTUPLE_KWARGS)
1502 asn1_type_name="unknown",
1519 expl_lenindef=False,
1550 def _colourize(what, colour, with_colours, attrs=("bold",)):
1551 return colored(what, colour, attrs=attrs) if with_colours else what
1554 def colonize_hex(hexed):
1555 """Separate hexadecimal string with colons
1557 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1566 with_decode_path=False,
1567 decode_path_len_decrease=0,
1574 " " if pp.expl_offset is None else
1575 ("-%d" % (pp.offset - pp.expl_offset))
1577 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1579 col = _colourize(col, "red", with_colours, ())
1580 col += _colourize("B", "red", with_colours) if pp.bered else " "
1582 col = "[%d,%d,%4d]%s" % (
1586 LENINDEF_PP_CHAR if pp.lenindef else " "
1588 col = _colourize(col, "green", with_colours, ())
1590 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1591 if decode_path_len > 0:
1592 cols.append(" ." * decode_path_len)
1593 ent = pp.decode_path[-1]
1594 if isinstance(ent, DecodePathDefBy):
1595 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1596 value = str(ent.defined_by)
1599 len(oid_maps) > 0 and
1600 ent.defined_by.asn1_type_name ==
1601 ObjectIdentifier.asn1_type_name
1603 for oid_map in oid_maps:
1604 oid_name = oid_map.get(value)
1605 if oid_name is not None:
1606 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1608 if oid_name is None:
1609 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1611 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1612 if pp.expl is not None:
1613 klass, _, num = pp.expl
1614 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1615 cols.append(_colourize(col, "blue", with_colours))
1616 if pp.impl is not None:
1617 klass, _, num = pp.impl
1618 col = "[%s%d]" % (TagClassReprs[klass], num)
1619 cols.append(_colourize(col, "blue", with_colours))
1620 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1621 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1623 cols.append(_colourize("BER", "red", with_colours))
1624 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1625 if pp.value is not None:
1627 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1629 len(oid_maps) > 0 and
1630 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1632 for oid_map in oid_maps:
1633 oid_name = oid_map.get(value)
1634 if oid_name is not None:
1635 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1637 if pp.asn1_type_name == Integer.asn1_type_name:
1638 hex_repr = hex(int(pp.obj._value))[2:].upper()
1639 if len(hex_repr) % 2 != 0:
1640 hex_repr = "0" + hex_repr
1641 cols.append(_colourize(
1642 "(%s)" % colonize_hex(hex_repr),
1647 if isinstance(pp.blob, binary_type):
1648 cols.append(hexenc(pp.blob))
1649 elif isinstance(pp.blob, tuple):
1650 cols.append(", ".join(pp.blob))
1652 cols.append(_colourize("OPTIONAL", "red", with_colours))
1654 cols.append(_colourize("DEFAULT", "red", with_colours))
1655 if with_decode_path:
1656 cols.append(_colourize(
1657 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1661 return " ".join(cols)
1664 def pp_console_blob(pp, decode_path_len_decrease=0):
1665 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1666 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1667 if decode_path_len > 0:
1668 cols.append(" ." * (decode_path_len + 1))
1669 if isinstance(pp.blob, binary_type):
1670 blob = hexenc(pp.blob).upper()
1671 for i in six_xrange(0, len(blob), 32):
1672 chunk = blob[i:i + 32]
1673 yield " ".join(cols + [colonize_hex(chunk)])
1674 elif isinstance(pp.blob, tuple):
1675 yield " ".join(cols + [", ".join(pp.blob)])
1683 with_decode_path=False,
1684 decode_path_only=(),
1686 """Pretty print object
1688 :param Obj obj: object you want to pretty print
1689 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1690 Its human readable form is printed when OID is met
1691 :param big_blobs: if large binary objects are met (like OctetString
1692 values), do we need to print them too, on separate
1694 :param with_colours: colourize output, if ``termcolor`` library
1696 :param with_decode_path: print decode path
1697 :param decode_path_only: print only that specified decode path
1699 def _pprint_pps(pps):
1701 if hasattr(pp, "_fields"):
1703 decode_path_only != () and
1705 str(p) for p in pp.decode_path[:len(decode_path_only)]
1706 ) != decode_path_only
1710 yield pp_console_row(
1715 with_colours=with_colours,
1716 with_decode_path=with_decode_path,
1717 decode_path_len_decrease=len(decode_path_only),
1719 for row in pp_console_blob(
1721 decode_path_len_decrease=len(decode_path_only),
1725 yield pp_console_row(
1730 with_colours=with_colours,
1731 with_decode_path=with_decode_path,
1732 decode_path_len_decrease=len(decode_path_only),
1735 for row in _pprint_pps(pp):
1737 return "\n".join(_pprint_pps(obj.pps()))
1740 ########################################################################
1741 # ASN.1 primitive types
1742 ########################################################################
1744 BooleanState = namedtuple("BooleanState", (
1757 ), **NAMEDTUPLE_KWARGS)
1761 """``BOOLEAN`` boolean type
1763 >>> b = Boolean(True)
1765 >>> b == Boolean(True)
1771 tag_default = tag_encode(1)
1772 asn1_type_name = "BOOLEAN"
1784 :param value: set the value. Either boolean type, or
1785 :py:class:`pyderasn.Boolean` object
1786 :param bytes impl: override default tag with ``IMPLICIT`` one
1787 :param bytes expl: override default tag with ``EXPLICIT`` one
1788 :param default: set default value. Type same as in ``value``
1789 :param bool optional: is object ``OPTIONAL`` in sequence
1791 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1792 self._value = None if value is None else self._value_sanitize(value)
1793 if default is not None:
1794 default = self._value_sanitize(default)
1795 self.default = self.__class__(
1801 self._value = default
1803 def _value_sanitize(self, value):
1804 if isinstance(value, bool):
1806 if issubclass(value.__class__, Boolean):
1808 raise InvalidValueType((self.__class__, bool))
1812 return self._value is not None
1814 def __getstate__(self):
1815 return BooleanState(
1830 def __setstate__(self, state):
1831 super(Boolean, self).__setstate__(state)
1832 self._value = state.value
1833 self.tag = state.tag
1834 self._expl = state.expl
1835 self.default = state.default
1836 self.optional = state.optional
1837 self.offset = state.offset
1838 self.llen = state.llen
1839 self.vlen = state.vlen
1840 self.expl_lenindef = state.expl_lenindef
1841 self.lenindef = state.lenindef
1842 self.ber_encoded = state.ber_encoded
1844 def __nonzero__(self):
1845 self._assert_ready()
1849 self._assert_ready()
1852 def __eq__(self, their):
1853 if isinstance(their, bool):
1854 return self._value == their
1855 if not issubclass(their.__class__, Boolean):
1858 self._value == their._value and
1859 self.tag == their.tag and
1860 self._expl == their._expl
1871 return self.__class__(
1873 impl=self.tag if impl is None else impl,
1874 expl=self._expl if expl is None else expl,
1875 default=self.default if default is None else default,
1876 optional=self.optional if optional is None else optional,
1880 self._assert_ready()
1884 (b"\xFF" if self._value else b"\x00"),
1887 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1889 t, _, lv = tag_strip(tlv)
1890 except DecodeError as err:
1891 raise err.__class__(
1893 klass=self.__class__,
1894 decode_path=decode_path,
1899 klass=self.__class__,
1900 decode_path=decode_path,
1906 l, _, v = len_decode(lv)
1907 except DecodeError as err:
1908 raise err.__class__(
1910 klass=self.__class__,
1911 decode_path=decode_path,
1915 raise InvalidLength(
1916 "Boolean's length must be equal to 1",
1917 klass=self.__class__,
1918 decode_path=decode_path,
1922 raise NotEnoughData(
1923 "encoded length is longer than data",
1924 klass=self.__class__,
1925 decode_path=decode_path,
1928 first_octet = byte2int(v)
1930 if first_octet == 0:
1932 elif first_octet == 0xFF:
1934 elif ctx.get("bered", False):
1939 "unacceptable Boolean value",
1940 klass=self.__class__,
1941 decode_path=decode_path,
1944 obj = self.__class__(
1948 default=self.default,
1949 optional=self.optional,
1950 _decoded=(offset, 1, 1),
1952 obj.ber_encoded = ber_encoded
1956 return pp_console_row(next(self.pps()))
1958 def pps(self, decode_path=()):
1961 asn1_type_name=self.asn1_type_name,
1962 obj_name=self.__class__.__name__,
1963 decode_path=decode_path,
1964 value=str(self._value) if self.ready else None,
1965 optional=self.optional,
1966 default=self == self.default,
1967 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1968 expl=None if self._expl is None else tag_decode(self._expl),
1973 expl_offset=self.expl_offset if self.expled else None,
1974 expl_tlen=self.expl_tlen if self.expled else None,
1975 expl_llen=self.expl_llen if self.expled else None,
1976 expl_vlen=self.expl_vlen if self.expled else None,
1977 expl_lenindef=self.expl_lenindef,
1978 ber_encoded=self.ber_encoded,
1981 for pp in self.pps_lenindef(decode_path):
1985 IntegerState = namedtuple("IntegerState", (
2001 ), **NAMEDTUPLE_KWARGS)
2005 """``INTEGER`` integer type
2007 >>> b = Integer(-123)
2009 >>> b == Integer(-123)
2014 >>> Integer(2, bounds=(1, 3))
2016 >>> Integer(5, bounds=(1, 3))
2017 Traceback (most recent call last):
2018 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2022 class Version(Integer):
2029 >>> v = Version("v1")
2036 {'v3': 2, 'v1': 0, 'v2': 1}
2038 __slots__ = ("specs", "_bound_min", "_bound_max")
2039 tag_default = tag_encode(2)
2040 asn1_type_name = "INTEGER"
2054 :param value: set the value. Either integer type, named value
2055 (if ``schema`` is specified in the class), or
2056 :py:class:`pyderasn.Integer` object
2057 :param bounds: set ``(MIN, MAX)`` value constraint.
2058 (-inf, +inf) by default
2059 :param bytes impl: override default tag with ``IMPLICIT`` one
2060 :param bytes expl: override default tag with ``EXPLICIT`` one
2061 :param default: set default value. Type same as in ``value``
2062 :param bool optional: is object ``OPTIONAL`` in sequence
2064 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2066 specs = getattr(self, "schema", {}) if _specs is None else _specs
2067 self.specs = specs if isinstance(specs, dict) else dict(specs)
2068 self._bound_min, self._bound_max = getattr(
2071 (float("-inf"), float("+inf")),
2072 ) if bounds is None else bounds
2073 if value is not None:
2074 self._value = self._value_sanitize(value)
2075 if default is not None:
2076 default = self._value_sanitize(default)
2077 self.default = self.__class__(
2083 if self._value is None:
2084 self._value = default
2086 def _value_sanitize(self, value):
2087 if isinstance(value, integer_types):
2089 elif issubclass(value.__class__, Integer):
2090 value = value._value
2091 elif isinstance(value, str):
2092 value = self.specs.get(value)
2094 raise ObjUnknown("integer value: %s" % value)
2096 raise InvalidValueType((self.__class__, int, str))
2097 if not self._bound_min <= value <= self._bound_max:
2098 raise BoundsError(self._bound_min, value, self._bound_max)
2103 return self._value is not None
2105 def __getstate__(self):
2106 return IntegerState(
2124 def __setstate__(self, state):
2125 super(Integer, self).__setstate__(state)
2126 self.specs = state.specs
2127 self._value = state.value
2128 self._bound_min = state.bound_min
2129 self._bound_max = state.bound_max
2130 self.tag = state.tag
2131 self._expl = state.expl
2132 self.default = state.default
2133 self.optional = state.optional
2134 self.offset = state.offset
2135 self.llen = state.llen
2136 self.vlen = state.vlen
2137 self.expl_lenindef = state.expl_lenindef
2138 self.lenindef = state.lenindef
2139 self.ber_encoded = state.ber_encoded
2142 self._assert_ready()
2143 return int(self._value)
2146 self._assert_ready()
2149 bytes(self._expl or b"") +
2150 str(self._value).encode("ascii"),
2153 def __eq__(self, their):
2154 if isinstance(their, integer_types):
2155 return self._value == their
2156 if not issubclass(their.__class__, Integer):
2159 self._value == their._value and
2160 self.tag == their.tag and
2161 self._expl == their._expl
2164 def __lt__(self, their):
2165 return self._value < their._value
2169 for name, value in iteritems(self.specs):
2170 if value == self._value:
2183 return self.__class__(
2186 (self._bound_min, self._bound_max)
2187 if bounds is None else bounds
2189 impl=self.tag if impl is None else impl,
2190 expl=self._expl if expl is None else expl,
2191 default=self.default if default is None else default,
2192 optional=self.optional if optional is None else optional,
2197 self._assert_ready()
2201 octets = bytearray([0])
2205 octets = bytearray()
2207 octets.append((value & 0xFF) ^ 0xFF)
2209 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2212 octets = bytearray()
2214 octets.append(value & 0xFF)
2216 if octets[-1] & 0x80 > 0:
2219 octets = bytes(octets)
2221 bytes_len = ceil(value.bit_length() / 8) or 1
2224 octets = value.to_bytes(
2229 except OverflowError:
2233 return b"".join((self.tag, len_encode(len(octets)), octets))
2235 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2237 t, _, lv = tag_strip(tlv)
2238 except DecodeError as err:
2239 raise err.__class__(
2241 klass=self.__class__,
2242 decode_path=decode_path,
2247 klass=self.__class__,
2248 decode_path=decode_path,
2254 l, llen, v = len_decode(lv)
2255 except DecodeError as err:
2256 raise err.__class__(
2258 klass=self.__class__,
2259 decode_path=decode_path,
2263 raise NotEnoughData(
2264 "encoded length is longer than data",
2265 klass=self.__class__,
2266 decode_path=decode_path,
2270 raise NotEnoughData(
2272 klass=self.__class__,
2273 decode_path=decode_path,
2276 v, tail = v[:l], v[l:]
2277 first_octet = byte2int(v)
2279 second_octet = byte2int(v[1:])
2281 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2282 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2285 "non normalized integer",
2286 klass=self.__class__,
2287 decode_path=decode_path,
2292 if first_octet & 0x80 > 0:
2293 octets = bytearray()
2294 for octet in bytearray(v):
2295 octets.append(octet ^ 0xFF)
2296 for octet in octets:
2297 value = (value << 8) | octet
2301 for octet in bytearray(v):
2302 value = (value << 8) | octet
2304 value = int.from_bytes(v, byteorder="big", signed=True)
2306 obj = self.__class__(
2308 bounds=(self._bound_min, self._bound_max),
2311 default=self.default,
2312 optional=self.optional,
2314 _decoded=(offset, llen, l),
2316 except BoundsError as err:
2319 klass=self.__class__,
2320 decode_path=decode_path,
2326 return pp_console_row(next(self.pps()))
2328 def pps(self, decode_path=()):
2331 asn1_type_name=self.asn1_type_name,
2332 obj_name=self.__class__.__name__,
2333 decode_path=decode_path,
2334 value=(self.named or str(self._value)) if self.ready else None,
2335 optional=self.optional,
2336 default=self == self.default,
2337 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2338 expl=None if self._expl is None else tag_decode(self._expl),
2343 expl_offset=self.expl_offset if self.expled else None,
2344 expl_tlen=self.expl_tlen if self.expled else None,
2345 expl_llen=self.expl_llen if self.expled else None,
2346 expl_vlen=self.expl_vlen if self.expled else None,
2347 expl_lenindef=self.expl_lenindef,
2350 for pp in self.pps_lenindef(decode_path):
2354 BitStringState = namedtuple("BitStringState", (
2370 ), **NAMEDTUPLE_KWARGS)
2373 class BitString(Obj):
2374 """``BIT STRING`` bit string type
2376 >>> BitString(b"hello world")
2377 BIT STRING 88 bits 68656c6c6f20776f726c64
2380 >>> b == b"hello world"
2385 >>> BitString("'0A3B5F291CD'H")
2386 BIT STRING 44 bits 0a3b5f291cd0
2387 >>> b = BitString("'010110000000'B")
2388 BIT STRING 12 bits 5800
2391 >>> b[0], b[1], b[2], b[3]
2392 (False, True, False, True)
2396 [False, True, False, True, True, False, False, False, False, False, False, False]
2400 class KeyUsage(BitString):
2402 ("digitalSignature", 0),
2403 ("nonRepudiation", 1),
2404 ("keyEncipherment", 2),
2407 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2408 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2410 ['nonRepudiation', 'keyEncipherment']
2412 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2416 Pay attention that BIT STRING can be encoded both in primitive
2417 and constructed forms. Decoder always checks constructed form tag
2418 additionally to specified primitive one. If BER decoding is
2419 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2420 of DER restrictions.
2422 __slots__ = ("tag_constructed", "specs", "defined")
2423 tag_default = tag_encode(3)
2424 asn1_type_name = "BIT STRING"
2437 :param value: set the value. Either binary type, tuple of named
2438 values (if ``schema`` is specified in the class),
2439 string in ``'XXX...'B`` form, or
2440 :py:class:`pyderasn.BitString` object
2441 :param bytes impl: override default tag with ``IMPLICIT`` one
2442 :param bytes expl: override default tag with ``EXPLICIT`` one
2443 :param default: set default value. Type same as in ``value``
2444 :param bool optional: is object ``OPTIONAL`` in sequence
2446 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2447 specs = getattr(self, "schema", {}) if _specs is None else _specs
2448 self.specs = specs if isinstance(specs, dict) else dict(specs)
2449 self._value = None if value is None else self._value_sanitize(value)
2450 if default is not None:
2451 default = self._value_sanitize(default)
2452 self.default = self.__class__(
2458 self._value = default
2460 tag_klass, _, tag_num = tag_decode(self.tag)
2461 self.tag_constructed = tag_encode(
2463 form=TagFormConstructed,
2467 def _bits2octets(self, bits):
2468 if len(self.specs) > 0:
2469 bits = bits.rstrip("0")
2471 bits += "0" * ((8 - (bit_len % 8)) % 8)
2472 octets = bytearray(len(bits) // 8)
2473 for i in six_xrange(len(octets)):
2474 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2475 return bit_len, bytes(octets)
2477 def _value_sanitize(self, value):
2478 if isinstance(value, (string_types, binary_type)):
2480 isinstance(value, string_types) and
2481 value.startswith("'")
2483 if value.endswith("'B"):
2485 if not frozenset(value) <= SET01:
2486 raise ValueError("B's coding contains unacceptable chars")
2487 return self._bits2octets(value)
2488 if value.endswith("'H"):
2492 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2494 if isinstance(value, binary_type):
2495 return (len(value) * 8, value)
2496 raise InvalidValueType((self.__class__, string_types, binary_type))
2497 if isinstance(value, tuple):
2500 isinstance(value[0], integer_types) and
2501 isinstance(value[1], binary_type)
2506 bit = self.specs.get(name)
2508 raise ObjUnknown("BitString value: %s" % name)
2511 return self._bits2octets("")
2512 bits = frozenset(bits)
2513 return self._bits2octets("".join(
2514 ("1" if bit in bits else "0")
2515 for bit in six_xrange(max(bits) + 1)
2517 if issubclass(value.__class__, BitString):
2519 raise InvalidValueType((self.__class__, binary_type, string_types))
2523 return self._value is not None
2525 def __getstate__(self):
2526 return BitStringState(
2540 self.tag_constructed,
2544 def __setstate__(self, state):
2545 super(BitString, self).__setstate__(state)
2546 self.specs = state.specs
2547 self._value = state.value
2548 self.tag = state.tag
2549 self._expl = state.expl
2550 self.default = state.default
2551 self.optional = state.optional
2552 self.offset = state.offset
2553 self.llen = state.llen
2554 self.vlen = state.vlen
2555 self.expl_lenindef = state.expl_lenindef
2556 self.lenindef = state.lenindef
2557 self.ber_encoded = state.ber_encoded
2558 self.tag_constructed = state.tag_constructed
2559 self.defined = state.defined
2562 self._assert_ready()
2563 for i in six_xrange(self._value[0]):
2568 self._assert_ready()
2569 return self._value[0]
2571 def __bytes__(self):
2572 self._assert_ready()
2573 return self._value[1]
2575 def __eq__(self, their):
2576 if isinstance(their, bytes):
2577 return self._value[1] == their
2578 if not issubclass(their.__class__, BitString):
2581 self._value == their._value and
2582 self.tag == their.tag and
2583 self._expl == their._expl
2588 return [name for name, bit in iteritems(self.specs) if self[bit]]
2598 return self.__class__(
2600 impl=self.tag if impl is None else impl,
2601 expl=self._expl if expl is None else expl,
2602 default=self.default if default is None else default,
2603 optional=self.optional if optional is None else optional,
2607 def __getitem__(self, key):
2608 if isinstance(key, int):
2609 bit_len, octets = self._value
2613 byte2int(memoryview(octets)[key // 8:]) >>
2616 if isinstance(key, string_types):
2617 value = self.specs.get(key)
2619 raise ObjUnknown("BitString value: %s" % key)
2621 raise InvalidValueType((int, str))
2624 self._assert_ready()
2625 bit_len, octets = self._value
2628 len_encode(len(octets) + 1),
2629 int2byte((8 - bit_len % 8) % 8),
2633 def _decode_chunk(self, lv, offset, decode_path):
2635 l, llen, v = len_decode(lv)
2636 except DecodeError as err:
2637 raise err.__class__(
2639 klass=self.__class__,
2640 decode_path=decode_path,
2644 raise NotEnoughData(
2645 "encoded length is longer than data",
2646 klass=self.__class__,
2647 decode_path=decode_path,
2651 raise NotEnoughData(
2653 klass=self.__class__,
2654 decode_path=decode_path,
2657 pad_size = byte2int(v)
2658 if l == 1 and pad_size != 0:
2660 "invalid empty value",
2661 klass=self.__class__,
2662 decode_path=decode_path,
2668 klass=self.__class__,
2669 decode_path=decode_path,
2672 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2675 klass=self.__class__,
2676 decode_path=decode_path,
2679 v, tail = v[:l], v[l:]
2680 obj = self.__class__(
2681 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2684 default=self.default,
2685 optional=self.optional,
2687 _decoded=(offset, llen, l),
2691 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2693 t, tlen, lv = tag_strip(tlv)
2694 except DecodeError as err:
2695 raise err.__class__(
2697 klass=self.__class__,
2698 decode_path=decode_path,
2702 if tag_only: # pragma: no cover
2704 return self._decode_chunk(lv, offset, decode_path)
2705 if t == self.tag_constructed:
2706 if not ctx.get("bered", False):
2708 "unallowed BER constructed encoding",
2709 klass=self.__class__,
2710 decode_path=decode_path,
2713 if tag_only: # pragma: no cover
2717 l, llen, v = len_decode(lv)
2718 except LenIndefForm:
2719 llen, l, v = 1, 0, lv[1:]
2721 except DecodeError as err:
2722 raise err.__class__(
2724 klass=self.__class__,
2725 decode_path=decode_path,
2729 raise NotEnoughData(
2730 "encoded length is longer than data",
2731 klass=self.__class__,
2732 decode_path=decode_path,
2735 if not lenindef and l == 0:
2736 raise NotEnoughData(
2738 klass=self.__class__,
2739 decode_path=decode_path,
2743 sub_offset = offset + tlen + llen
2747 if v[:EOC_LEN].tobytes() == EOC:
2754 "chunk out of bounds",
2755 klass=self.__class__,
2756 decode_path=decode_path + (str(len(chunks) - 1),),
2757 offset=chunks[-1].offset,
2759 sub_decode_path = decode_path + (str(len(chunks)),)
2761 chunk, v_tail = BitString().decode(
2764 decode_path=sub_decode_path,
2767 _ctx_immutable=False,
2771 "expected BitString encoded chunk",
2772 klass=self.__class__,
2773 decode_path=sub_decode_path,
2776 chunks.append(chunk)
2777 sub_offset += chunk.tlvlen
2778 vlen += chunk.tlvlen
2780 if len(chunks) == 0:
2783 klass=self.__class__,
2784 decode_path=decode_path,
2789 for chunk_i, chunk in enumerate(chunks[:-1]):
2790 if chunk.bit_len % 8 != 0:
2792 "BitString chunk is not multiple of 8 bits",
2793 klass=self.__class__,
2794 decode_path=decode_path + (str(chunk_i),),
2795 offset=chunk.offset,
2797 values.append(bytes(chunk))
2798 bit_len += chunk.bit_len
2799 chunk_last = chunks[-1]
2800 values.append(bytes(chunk_last))
2801 bit_len += chunk_last.bit_len
2802 obj = self.__class__(
2803 value=(bit_len, b"".join(values)),
2806 default=self.default,
2807 optional=self.optional,
2809 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2811 obj.lenindef = lenindef
2812 obj.ber_encoded = True
2813 return obj, (v[EOC_LEN:] if lenindef else v)
2815 klass=self.__class__,
2816 decode_path=decode_path,
2821 return pp_console_row(next(self.pps()))
2823 def pps(self, decode_path=()):
2827 bit_len, blob = self._value
2828 value = "%d bits" % bit_len
2829 if len(self.specs) > 0:
2830 blob = tuple(self.named)
2833 asn1_type_name=self.asn1_type_name,
2834 obj_name=self.__class__.__name__,
2835 decode_path=decode_path,
2838 optional=self.optional,
2839 default=self == self.default,
2840 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2841 expl=None if self._expl is None else tag_decode(self._expl),
2846 expl_offset=self.expl_offset if self.expled else None,
2847 expl_tlen=self.expl_tlen if self.expled else None,
2848 expl_llen=self.expl_llen if self.expled else None,
2849 expl_vlen=self.expl_vlen if self.expled else None,
2850 expl_lenindef=self.expl_lenindef,
2851 lenindef=self.lenindef,
2852 ber_encoded=self.ber_encoded,
2855 defined_by, defined = self.defined or (None, None)
2856 if defined_by is not None:
2858 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2860 for pp in self.pps_lenindef(decode_path):
2864 OctetStringState = namedtuple("OctetStringState", (
2881 ), **NAMEDTUPLE_KWARGS)
2884 class OctetString(Obj):
2885 """``OCTET STRING`` binary string type
2887 >>> s = OctetString(b"hello world")
2888 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2889 >>> s == OctetString(b"hello world")
2894 >>> OctetString(b"hello", bounds=(4, 4))
2895 Traceback (most recent call last):
2896 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2897 >>> OctetString(b"hell", bounds=(4, 4))
2898 OCTET STRING 4 bytes 68656c6c
2902 Pay attention that OCTET STRING can be encoded both in primitive
2903 and constructed forms. Decoder always checks constructed form tag
2904 additionally to specified primitive one. If BER decoding is
2905 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2906 of DER restrictions.
2908 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2909 tag_default = tag_encode(4)
2910 asn1_type_name = "OCTET STRING"
2924 :param value: set the value. Either binary type, or
2925 :py:class:`pyderasn.OctetString` object
2926 :param bounds: set ``(MIN, MAX)`` value size constraint.
2927 (-inf, +inf) by default
2928 :param bytes impl: override default tag with ``IMPLICIT`` one
2929 :param bytes expl: override default tag with ``EXPLICIT`` one
2930 :param default: set default value. Type same as in ``value``
2931 :param bool optional: is object ``OPTIONAL`` in sequence
2933 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2935 self._bound_min, self._bound_max = getattr(
2939 ) if bounds is None else bounds
2940 if value is not None:
2941 self._value = self._value_sanitize(value)
2942 if default is not None:
2943 default = self._value_sanitize(default)
2944 self.default = self.__class__(
2949 if self._value is None:
2950 self._value = default
2952 tag_klass, _, tag_num = tag_decode(self.tag)
2953 self.tag_constructed = tag_encode(
2955 form=TagFormConstructed,
2959 def _value_sanitize(self, value):
2960 if isinstance(value, binary_type):
2962 elif issubclass(value.__class__, OctetString):
2963 value = value._value
2965 raise InvalidValueType((self.__class__, bytes))
2966 if not self._bound_min <= len(value) <= self._bound_max:
2967 raise BoundsError(self._bound_min, len(value), self._bound_max)
2972 return self._value is not None
2974 def __getstate__(self):
2975 return OctetStringState(
2990 self.tag_constructed,
2994 def __setstate__(self, state):
2995 super(OctetString, self).__setstate__(state)
2996 self._value = state.value
2997 self._bound_min = state.bound_min
2998 self._bound_max = state.bound_max
2999 self.tag = state.tag
3000 self._expl = state.expl
3001 self.default = state.default
3002 self.optional = state.optional
3003 self.offset = state.offset
3004 self.llen = state.llen
3005 self.vlen = state.vlen
3006 self.expl_lenindef = state.expl_lenindef
3007 self.lenindef = state.lenindef
3008 self.ber_encoded = state.ber_encoded
3009 self.tag_constructed = state.tag_constructed
3010 self.defined = state.defined
3012 def __bytes__(self):
3013 self._assert_ready()
3016 def __eq__(self, their):
3017 if isinstance(their, binary_type):
3018 return self._value == their
3019 if not issubclass(their.__class__, OctetString):
3022 self._value == their._value and
3023 self.tag == their.tag and
3024 self._expl == their._expl
3027 def __lt__(self, their):
3028 return self._value < their._value
3039 return self.__class__(
3042 (self._bound_min, self._bound_max)
3043 if bounds is None else bounds
3045 impl=self.tag if impl is None else impl,
3046 expl=self._expl if expl is None else expl,
3047 default=self.default if default is None else default,
3048 optional=self.optional if optional is None else optional,
3052 self._assert_ready()
3055 len_encode(len(self._value)),
3059 def _decode_chunk(self, lv, offset, decode_path, ctx):
3061 l, llen, v = len_decode(lv)
3062 except DecodeError as err:
3063 raise err.__class__(
3065 klass=self.__class__,
3066 decode_path=decode_path,
3070 raise NotEnoughData(
3071 "encoded length is longer than data",
3072 klass=self.__class__,
3073 decode_path=decode_path,
3076 v, tail = v[:l], v[l:]
3078 obj = self.__class__(
3080 bounds=(self._bound_min, self._bound_max),
3083 default=self.default,
3084 optional=self.optional,
3085 _decoded=(offset, llen, l),
3088 except DecodeError as err:
3091 klass=self.__class__,
3092 decode_path=decode_path,
3095 except BoundsError as err:
3098 klass=self.__class__,
3099 decode_path=decode_path,
3104 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3106 t, tlen, lv = tag_strip(tlv)
3107 except DecodeError as err:
3108 raise err.__class__(
3110 klass=self.__class__,
3111 decode_path=decode_path,
3117 return self._decode_chunk(lv, offset, decode_path, ctx)
3118 if t == self.tag_constructed:
3119 if not ctx.get("bered", False):
3121 "unallowed BER constructed encoding",
3122 klass=self.__class__,
3123 decode_path=decode_path,
3130 l, llen, v = len_decode(lv)
3131 except LenIndefForm:
3132 llen, l, v = 1, 0, lv[1:]
3134 except DecodeError as err:
3135 raise err.__class__(
3137 klass=self.__class__,
3138 decode_path=decode_path,
3142 raise NotEnoughData(
3143 "encoded length is longer than data",
3144 klass=self.__class__,
3145 decode_path=decode_path,
3149 sub_offset = offset + tlen + llen
3153 if v[:EOC_LEN].tobytes() == EOC:
3160 "chunk out of bounds",
3161 klass=self.__class__,
3162 decode_path=decode_path + (str(len(chunks) - 1),),
3163 offset=chunks[-1].offset,
3165 sub_decode_path = decode_path + (str(len(chunks)),)
3167 chunk, v_tail = OctetString().decode(
3170 decode_path=sub_decode_path,
3173 _ctx_immutable=False,
3177 "expected OctetString encoded chunk",
3178 klass=self.__class__,
3179 decode_path=sub_decode_path,
3182 chunks.append(chunk)
3183 sub_offset += chunk.tlvlen
3184 vlen += chunk.tlvlen
3187 obj = self.__class__(
3188 value=b"".join(bytes(chunk) for chunk in chunks),
3189 bounds=(self._bound_min, self._bound_max),
3192 default=self.default,
3193 optional=self.optional,
3194 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3197 except DecodeError as err:
3200 klass=self.__class__,
3201 decode_path=decode_path,
3204 except BoundsError as err:
3207 klass=self.__class__,
3208 decode_path=decode_path,
3211 obj.lenindef = lenindef
3212 obj.ber_encoded = True
3213 return obj, (v[EOC_LEN:] if lenindef else v)
3215 klass=self.__class__,
3216 decode_path=decode_path,
3221 return pp_console_row(next(self.pps()))
3223 def pps(self, decode_path=()):
3226 asn1_type_name=self.asn1_type_name,
3227 obj_name=self.__class__.__name__,
3228 decode_path=decode_path,
3229 value=("%d bytes" % len(self._value)) if self.ready else None,
3230 blob=self._value if self.ready else None,
3231 optional=self.optional,
3232 default=self == self.default,
3233 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3234 expl=None if self._expl is None else tag_decode(self._expl),
3239 expl_offset=self.expl_offset if self.expled else None,
3240 expl_tlen=self.expl_tlen if self.expled else None,
3241 expl_llen=self.expl_llen if self.expled else None,
3242 expl_vlen=self.expl_vlen if self.expled else None,
3243 expl_lenindef=self.expl_lenindef,
3244 lenindef=self.lenindef,
3245 ber_encoded=self.ber_encoded,
3248 defined_by, defined = self.defined or (None, None)
3249 if defined_by is not None:
3251 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3253 for pp in self.pps_lenindef(decode_path):
3257 NullState = namedtuple("NullState", (
3269 ), **NAMEDTUPLE_KWARGS)
3273 """``NULL`` null object
3281 tag_default = tag_encode(5)
3282 asn1_type_name = "NULL"
3286 value=None, # unused, but Sequence passes it
3293 :param bytes impl: override default tag with ``IMPLICIT`` one
3294 :param bytes expl: override default tag with ``EXPLICIT`` one
3295 :param bool optional: is object ``OPTIONAL`` in sequence
3297 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3304 def __getstate__(self):
3319 def __setstate__(self, state):
3320 super(Null, self).__setstate__(state)
3321 self.tag = state.tag
3322 self._expl = state.expl
3323 self.default = state.default
3324 self.optional = state.optional
3325 self.offset = state.offset
3326 self.llen = state.llen
3327 self.vlen = state.vlen
3328 self.expl_lenindef = state.expl_lenindef
3329 self.lenindef = state.lenindef
3330 self.ber_encoded = state.ber_encoded
3332 def __eq__(self, their):
3333 if not issubclass(their.__class__, Null):
3336 self.tag == their.tag and
3337 self._expl == their._expl
3347 return self.__class__(
3348 impl=self.tag if impl is None else impl,
3349 expl=self._expl if expl is None else expl,
3350 optional=self.optional if optional is None else optional,
3354 return self.tag + len_encode(0)
3356 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3358 t, _, lv = tag_strip(tlv)
3359 except DecodeError as err:
3360 raise err.__class__(
3362 klass=self.__class__,
3363 decode_path=decode_path,
3368 klass=self.__class__,
3369 decode_path=decode_path,
3372 if tag_only: # pragma: no cover
3375 l, _, v = len_decode(lv)
3376 except DecodeError as err:
3377 raise err.__class__(
3379 klass=self.__class__,
3380 decode_path=decode_path,
3384 raise InvalidLength(
3385 "Null must have zero length",
3386 klass=self.__class__,
3387 decode_path=decode_path,
3390 obj = self.__class__(
3393 optional=self.optional,
3394 _decoded=(offset, 1, 0),
3399 return pp_console_row(next(self.pps()))
3401 def pps(self, decode_path=()):
3404 asn1_type_name=self.asn1_type_name,
3405 obj_name=self.__class__.__name__,
3406 decode_path=decode_path,
3407 optional=self.optional,
3408 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3409 expl=None if self._expl is None else tag_decode(self._expl),
3414 expl_offset=self.expl_offset if self.expled else None,
3415 expl_tlen=self.expl_tlen if self.expled else None,
3416 expl_llen=self.expl_llen if self.expled else None,
3417 expl_vlen=self.expl_vlen if self.expled else None,
3418 expl_lenindef=self.expl_lenindef,
3421 for pp in self.pps_lenindef(decode_path):
3425 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3439 ), **NAMEDTUPLE_KWARGS)
3442 class ObjectIdentifier(Obj):
3443 """``OBJECT IDENTIFIER`` OID type
3445 >>> oid = ObjectIdentifier((1, 2, 3))
3446 OBJECT IDENTIFIER 1.2.3
3447 >>> oid == ObjectIdentifier("1.2.3")
3453 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3454 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3456 >>> str(ObjectIdentifier((3, 1)))
3457 Traceback (most recent call last):
3458 pyderasn.InvalidOID: unacceptable first arc value
3460 __slots__ = ("defines",)
3461 tag_default = tag_encode(6)
3462 asn1_type_name = "OBJECT IDENTIFIER"
3475 :param value: set the value. Either tuples of integers,
3476 string of "."-concatenated integers, or
3477 :py:class:`pyderasn.ObjectIdentifier` object
3478 :param defines: sequence of tuples. Each tuple has two elements.
3479 First one is relative to current one decode
3480 path, aiming to the field defined by that OID.
3481 Read about relative path in
3482 :py:func:`pyderasn.abs_decode_path`. Second
3483 tuple element is ``{OID: pyderasn.Obj()}``
3484 dictionary, mapping between current OID value
3485 and structure applied to defined field.
3486 :ref:`Read about DEFINED BY <definedby>`
3487 :param bytes impl: override default tag with ``IMPLICIT`` one
3488 :param bytes expl: override default tag with ``EXPLICIT`` one
3489 :param default: set default value. Type same as in ``value``
3490 :param bool optional: is object ``OPTIONAL`` in sequence
3492 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3494 if value is not None:
3495 self._value = self._value_sanitize(value)
3496 if default is not None:
3497 default = self._value_sanitize(default)
3498 self.default = self.__class__(
3503 if self._value is None:
3504 self._value = default
3505 self.defines = defines
3507 def __add__(self, their):
3508 if isinstance(their, self.__class__):
3509 return self.__class__(self._value + their._value)
3510 if isinstance(their, tuple):
3511 return self.__class__(self._value + their)
3512 raise InvalidValueType((self.__class__, tuple))
3514 def _value_sanitize(self, value):
3515 if issubclass(value.__class__, ObjectIdentifier):
3517 if isinstance(value, string_types):
3519 value = tuple(pureint(arc) for arc in value.split("."))
3521 raise InvalidOID("unacceptable arcs values")
3522 if isinstance(value, tuple):
3524 raise InvalidOID("less than 2 arcs")
3525 first_arc = value[0]
3526 if first_arc in (0, 1):
3527 if not (0 <= value[1] <= 39):
3528 raise InvalidOID("second arc is too wide")
3529 elif first_arc == 2:
3532 raise InvalidOID("unacceptable first arc value")
3533 if not all(arc >= 0 for arc in value):
3534 raise InvalidOID("negative arc value")
3536 raise InvalidValueType((self.__class__, str, tuple))
3540 return self._value is not None
3542 def __getstate__(self):
3543 return ObjectIdentifierState(
3559 def __setstate__(self, state):
3560 super(ObjectIdentifier, self).__setstate__(state)
3561 self._value = state.value
3562 self.tag = state.tag
3563 self._expl = state.expl
3564 self.default = state.default
3565 self.optional = state.optional
3566 self.offset = state.offset
3567 self.llen = state.llen
3568 self.vlen = state.vlen
3569 self.expl_lenindef = state.expl_lenindef
3570 self.lenindef = state.lenindef
3571 self.ber_encoded = state.ber_encoded
3572 self.defines = state.defines
3575 self._assert_ready()
3576 return iter(self._value)
3579 return ".".join(str(arc) for arc in self._value or ())
3582 self._assert_ready()
3585 bytes(self._expl or b"") +
3586 str(self._value).encode("ascii"),
3589 def __eq__(self, their):
3590 if isinstance(their, tuple):
3591 return self._value == their
3592 if not issubclass(their.__class__, ObjectIdentifier):
3595 self.tag == their.tag and
3596 self._expl == their._expl and
3597 self._value == their._value
3600 def __lt__(self, their):
3601 return self._value < their._value
3612 return self.__class__(
3614 defines=self.defines if defines is None else defines,
3615 impl=self.tag if impl is None else impl,
3616 expl=self._expl if expl is None else expl,
3617 default=self.default if default is None else default,
3618 optional=self.optional if optional is None else optional,
3622 self._assert_ready()
3624 first_value = value[1]
3625 first_arc = value[0]
3628 elif first_arc == 1:
3630 elif first_arc == 2:
3632 else: # pragma: no cover
3633 raise RuntimeError("invalid arc is stored")
3634 octets = [zero_ended_encode(first_value)]
3635 for arc in value[2:]:
3636 octets.append(zero_ended_encode(arc))
3637 v = b"".join(octets)
3638 return b"".join((self.tag, len_encode(len(v)), v))
3640 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3642 t, _, lv = tag_strip(tlv)
3643 except DecodeError as err:
3644 raise err.__class__(
3646 klass=self.__class__,
3647 decode_path=decode_path,
3652 klass=self.__class__,
3653 decode_path=decode_path,
3656 if tag_only: # pragma: no cover
3659 l, llen, v = len_decode(lv)
3660 except DecodeError as err:
3661 raise err.__class__(
3663 klass=self.__class__,
3664 decode_path=decode_path,
3668 raise NotEnoughData(
3669 "encoded length is longer than data",
3670 klass=self.__class__,
3671 decode_path=decode_path,
3675 raise NotEnoughData(
3677 klass=self.__class__,
3678 decode_path=decode_path,
3681 v, tail = v[:l], v[l:]
3688 octet = indexbytes(v, i)
3689 if i == 0 and octet == 0x80:
3690 if ctx.get("bered", False):
3693 raise DecodeError("non normalized arc encoding")
3694 arc = (arc << 7) | (octet & 0x7F)
3695 if octet & 0x80 == 0:
3703 klass=self.__class__,
3704 decode_path=decode_path,
3708 second_arc = arcs[0]
3709 if 0 <= second_arc <= 39:
3711 elif 40 <= second_arc <= 79:
3717 obj = self.__class__(
3718 value=tuple([first_arc, second_arc] + arcs[1:]),
3721 default=self.default,
3722 optional=self.optional,
3723 _decoded=(offset, llen, l),
3726 obj.ber_encoded = True
3730 return pp_console_row(next(self.pps()))
3732 def pps(self, decode_path=()):
3735 asn1_type_name=self.asn1_type_name,
3736 obj_name=self.__class__.__name__,
3737 decode_path=decode_path,
3738 value=str(self) if self.ready else None,
3739 optional=self.optional,
3740 default=self == self.default,
3741 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3742 expl=None if self._expl is None else tag_decode(self._expl),
3747 expl_offset=self.expl_offset if self.expled else None,
3748 expl_tlen=self.expl_tlen if self.expled else None,
3749 expl_llen=self.expl_llen if self.expled else None,
3750 expl_vlen=self.expl_vlen if self.expled else None,
3751 expl_lenindef=self.expl_lenindef,
3752 ber_encoded=self.ber_encoded,
3755 for pp in self.pps_lenindef(decode_path):
3759 class Enumerated(Integer):
3760 """``ENUMERATED`` integer type
3762 This type is identical to :py:class:`pyderasn.Integer`, but requires
3763 schema to be specified and does not accept values missing from it.
3766 tag_default = tag_encode(10)
3767 asn1_type_name = "ENUMERATED"
3778 bounds=None, # dummy argument, workability for Integer.decode
3780 super(Enumerated, self).__init__(
3781 value, bounds, impl, expl, default, optional, _specs, _decoded,
3783 if len(self.specs) == 0:
3784 raise ValueError("schema must be specified")
3786 def _value_sanitize(self, value):
3787 if isinstance(value, self.__class__):
3788 value = value._value
3789 elif isinstance(value, integer_types):
3790 for _value in itervalues(self.specs):
3795 "unknown integer value: %s" % value,
3796 klass=self.__class__,
3798 elif isinstance(value, string_types):
3799 value = self.specs.get(value)
3801 raise ObjUnknown("integer value: %s" % value)
3803 raise InvalidValueType((self.__class__, int, str))
3815 return self.__class__(
3817 impl=self.tag if impl is None else impl,
3818 expl=self._expl if expl is None else expl,
3819 default=self.default if default is None else default,
3820 optional=self.optional if optional is None else optional,
3825 def escape_control_unicode(c):
3826 if unicat(c)[0] == "C":
3827 c = repr(c).lstrip("u").strip("'")
3831 class CommonString(OctetString):
3832 """Common class for all strings
3834 Everything resembles :py:class:`pyderasn.OctetString`, except
3835 ability to deal with unicode text strings.
3837 >>> hexenc("привет мир".encode("utf-8"))
3838 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3839 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3841 >>> s = UTF8String("привет мир")
3842 UTF8String UTF8String привет мир
3844 'привет мир'
3845 >>> hexenc(bytes(s))
3846 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3848 >>> PrintableString("привет мир")
3849 Traceback (most recent call last):
3850 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3852 >>> BMPString("ада", bounds=(2, 2))
3853 Traceback (most recent call last):
3854 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3855 >>> s = BMPString("ад", bounds=(2, 2))
3858 >>> hexenc(bytes(s))
3866 * - :py:class:`pyderasn.UTF8String`
3868 * - :py:class:`pyderasn.NumericString`
3870 * - :py:class:`pyderasn.PrintableString`
3872 * - :py:class:`pyderasn.TeletexString`
3874 * - :py:class:`pyderasn.T61String`
3876 * - :py:class:`pyderasn.VideotexString`
3878 * - :py:class:`pyderasn.IA5String`
3880 * - :py:class:`pyderasn.GraphicString`
3882 * - :py:class:`pyderasn.VisibleString`
3884 * - :py:class:`pyderasn.ISO646String`
3886 * - :py:class:`pyderasn.GeneralString`
3888 * - :py:class:`pyderasn.UniversalString`
3890 * - :py:class:`pyderasn.BMPString`
3895 def _value_sanitize(self, value):
3897 value_decoded = None
3898 if isinstance(value, self.__class__):
3899 value_raw = value._value
3900 elif isinstance(value, text_type):
3901 value_decoded = value
3902 elif isinstance(value, binary_type):
3905 raise InvalidValueType((self.__class__, text_type, binary_type))
3908 value_decoded.encode(self.encoding)
3909 if value_raw is None else value_raw
3912 value_raw.decode(self.encoding)
3913 if value_decoded is None else value_decoded
3915 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3916 raise DecodeError(str(err))
3917 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3925 def __eq__(self, their):
3926 if isinstance(their, binary_type):
3927 return self._value == their
3928 if isinstance(their, text_type):
3929 return self._value == their.encode(self.encoding)
3930 if not isinstance(their, self.__class__):
3933 self._value == their._value and
3934 self.tag == their.tag and
3935 self._expl == their._expl
3938 def __unicode__(self):
3940 return self._value.decode(self.encoding)
3941 return text_type(self._value)
3944 return pp_console_row(next(self.pps(no_unicode=PY2)))
3946 def pps(self, decode_path=(), no_unicode=False):
3950 hexenc(bytes(self)) if no_unicode else
3951 "".join(escape_control_unicode(c) for c in self.__unicode__())
3955 asn1_type_name=self.asn1_type_name,
3956 obj_name=self.__class__.__name__,
3957 decode_path=decode_path,
3959 optional=self.optional,
3960 default=self == self.default,
3961 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3962 expl=None if self._expl is None else tag_decode(self._expl),
3967 expl_offset=self.expl_offset if self.expled else None,
3968 expl_tlen=self.expl_tlen if self.expled else None,
3969 expl_llen=self.expl_llen if self.expled else None,
3970 expl_vlen=self.expl_vlen if self.expled else None,
3971 expl_lenindef=self.expl_lenindef,
3972 ber_encoded=self.ber_encoded,
3975 for pp in self.pps_lenindef(decode_path):
3979 class UTF8String(CommonString):
3981 tag_default = tag_encode(12)
3983 asn1_type_name = "UTF8String"
3986 class AllowableCharsMixin(object):
3988 def allowable_chars(self):
3990 return self._allowable_chars
3991 return frozenset(six_unichr(c) for c in self._allowable_chars)
3994 class NumericString(AllowableCharsMixin, CommonString):
3997 Its value is properly sanitized: only ASCII digits with spaces can
4000 >>> NumericString().allowable_chars
4001 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
4004 tag_default = tag_encode(18)
4006 asn1_type_name = "NumericString"
4007 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4009 def _value_sanitize(self, value):
4010 value = super(NumericString, self)._value_sanitize(value)
4011 if not frozenset(value) <= self._allowable_chars:
4012 raise DecodeError("non-numeric value")
4016 PrintableStringState = namedtuple(
4017 "PrintableStringState",
4018 OctetStringState._fields + ("allowable_chars",),
4023 class PrintableString(AllowableCharsMixin, CommonString):
4026 Its value is properly sanitized: see X.680 41.4 table 10.
4028 >>> PrintableString().allowable_chars
4029 frozenset([' ', "'", ..., 'z'])
4030 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4031 PrintableString PrintableString foo*bar
4032 >>> obj.allow_asterisk, obj.allow_ampersand
4036 tag_default = tag_encode(19)
4038 asn1_type_name = "PrintableString"
4039 _allowable_chars = frozenset(
4040 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4042 _asterisk = frozenset("*".encode("ascii"))
4043 _ampersand = frozenset("&".encode("ascii"))
4055 allow_asterisk=False,
4056 allow_ampersand=False,
4059 :param allow_asterisk: allow asterisk character
4060 :param allow_ampersand: allow ampersand character
4063 self._allowable_chars |= self._asterisk
4065 self._allowable_chars |= self._ampersand
4066 super(PrintableString, self).__init__(
4067 value, bounds, impl, expl, default, optional, _decoded, ctx,
4071 def allow_asterisk(self):
4072 """Is asterisk character allowed?
4074 return self._asterisk <= self._allowable_chars
4077 def allow_ampersand(self):
4078 """Is ampersand character allowed?
4080 return self._ampersand <= self._allowable_chars
4082 def _value_sanitize(self, value):
4083 value = super(PrintableString, self)._value_sanitize(value)
4084 if not frozenset(value) <= self._allowable_chars:
4085 raise DecodeError("non-printable value")
4088 def __getstate__(self):
4089 return PrintableStringState(
4090 *super(PrintableString, self).__getstate__(),
4091 **{"allowable_chars": self._allowable_chars}
4094 def __setstate__(self, state):
4095 super(PrintableString, self).__setstate__(state)
4096 self._allowable_chars = state.allowable_chars
4107 return self.__class__(
4110 (self._bound_min, self._bound_max)
4111 if bounds is None else bounds
4113 impl=self.tag if impl is None else impl,
4114 expl=self._expl if expl is None else expl,
4115 default=self.default if default is None else default,
4116 optional=self.optional if optional is None else optional,
4117 allow_asterisk=self.allow_asterisk,
4118 allow_ampersand=self.allow_ampersand,
4122 class TeletexString(CommonString):
4124 tag_default = tag_encode(20)
4126 asn1_type_name = "TeletexString"
4129 class T61String(TeletexString):
4131 asn1_type_name = "T61String"
4134 class VideotexString(CommonString):
4136 tag_default = tag_encode(21)
4137 encoding = "iso-8859-1"
4138 asn1_type_name = "VideotexString"
4141 class IA5String(CommonString):
4143 tag_default = tag_encode(22)
4145 asn1_type_name = "IA5"
4148 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4149 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4150 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4153 class VisibleString(CommonString):
4155 tag_default = tag_encode(26)
4157 asn1_type_name = "VisibleString"
4160 UTCTimeState = namedtuple(
4162 OctetStringState._fields + ("ber_raw",),
4167 class UTCTime(VisibleString):
4168 """``UTCTime`` datetime type
4170 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4171 UTCTime UTCTime 2017-09-30T22:07:50
4177 datetime.datetime(2017, 9, 30, 22, 7, 50)
4178 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4179 datetime.datetime(1957, 9, 30, 22, 7, 50)
4183 Pay attention that UTCTime can not hold full year, so all years
4184 having < 50 years are treated as 20xx, 19xx otherwise, according
4185 to X.509 recommendation.
4189 No strict validation of UTC offsets are made, but very crude:
4191 * minutes are not exceeding 60
4192 * offset value is not exceeding 14 hours
4194 __slots__ = ("_ber_raw",)
4195 tag_default = tag_encode(23)
4197 asn1_type_name = "UTCTime"
4207 bounds=None, # dummy argument, workability for OctetString.decode
4211 :param value: set the value. Either datetime type, or
4212 :py:class:`pyderasn.UTCTime` object
4213 :param bytes impl: override default tag with ``IMPLICIT`` one
4214 :param bytes expl: override default tag with ``EXPLICIT`` one
4215 :param default: set default value. Type same as in ``value``
4216 :param bool optional: is object ``OPTIONAL`` in sequence
4218 super(UTCTime, self).__init__(
4219 None, None, impl, expl, None, optional, _decoded, ctx,
4222 self._ber_raw = None
4223 if value is not None:
4224 self._value, self._ber_raw = self._value_sanitize(value, ctx)
4225 self.ber_encoded = self._ber_raw is not None
4226 if default is not None:
4227 default, _ = self._value_sanitize(default)
4228 self.default = self.__class__(
4233 if self._value is None:
4234 self._value = default
4236 self.optional = optional
4238 def _strptime_bered(self, value):
4239 year = pureint(value[:2])
4240 year += 2000 if year < 50 else 1900
4243 pureint(value[2:4]), # %m
4244 pureint(value[4:6]), # %d
4245 pureint(value[6:8]), # %H
4246 pureint(value[8:10]), # %M
4250 raise ValueError("no timezone")
4252 if value[-1] == "Z":
4256 raise ValueError("invalid UTC offset")
4257 if value[-5] == "-":
4259 elif value[-5] == "+":
4262 raise ValueError("invalid UTC offset")
4263 offset = 60 * pureint(value[-2:])
4265 raise ValueError("invalid UTC offset minutes")
4266 offset += 3600 * pureint(value[-4:-2])
4267 if offset > 14 * 3600:
4268 raise ValueError("too big UTC offset")
4272 return offset, decoded
4274 raise ValueError("invalid UTC offset seconds")
4275 seconds = pureint(value)
4277 raise ValueError("invalid seconds value")
4278 decoded += timedelta(seconds=seconds)
4279 return offset, decoded
4281 def _strptime(self, value):
4282 # datetime.strptime's format: %y%m%d%H%M%SZ
4283 if len(value) != LEN_YYMMDDHHMMSSZ:
4284 raise ValueError("invalid UTCTime length")
4285 if value[-1] != "Z":
4286 raise ValueError("non UTC timezone")
4287 year = pureint(value[:2])
4288 year += 2000 if year < 50 else 1900
4291 pureint(value[2:4]), # %m
4292 pureint(value[4:6]), # %d
4293 pureint(value[6:8]), # %H
4294 pureint(value[8:10]), # %M
4295 pureint(value[10:12]), # %S
4298 def _dt_sanitize(self, value):
4299 if value.year < 1950 or value.year > 2049:
4300 raise ValueError("UTCTime can hold only 1950-2049 years")
4301 return value.replace(microsecond=0)
4303 def _value_sanitize(self, value, ctx=None):
4304 if isinstance(value, binary_type):
4306 value_decoded = value.decode("ascii")
4307 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4308 raise DecodeError("invalid UTCTime encoding: %r" % err)
4311 return self._strptime(value_decoded), None
4312 except (TypeError, ValueError) as _err:
4314 if (ctx is not None) and ctx.get("bered", False):
4316 offset, _value = self._strptime_bered(value_decoded)
4317 _value = _value - timedelta(seconds=offset)
4318 return self._dt_sanitize(_value), value_decoded
4319 except (TypeError, ValueError, OverflowError) as _err:
4322 "invalid %s format: %r" % (self.asn1_type_name, err),
4323 klass=self.__class__,
4325 if isinstance(value, self.__class__):
4326 return value._value, None
4327 if isinstance(value, datetime):
4328 return self._dt_sanitize(value), None
4329 raise InvalidValueType((self.__class__, datetime))
4331 def _pp_value(self):
4333 value = self._value.isoformat()
4334 if self.ber_encoded:
4335 value += " (%s)" % self._ber_raw
4338 def __unicode__(self):
4340 value = self._value.isoformat()
4341 if self.ber_encoded:
4342 value += " (%s)" % self._ber_raw
4344 return text_type(self._pp_value())
4346 def __getstate__(self):
4347 return UTCTimeState(
4348 *super(UTCTime, self).__getstate__(),
4349 **{"ber_raw": self._ber_raw}
4352 def __setstate__(self, state):
4353 super(UTCTime, self).__setstate__(state)
4354 self._ber_raw = state.ber_raw
4356 def __bytes__(self):
4357 self._assert_ready()
4358 return self._encode_time()
4360 def __eq__(self, their):
4361 if isinstance(their, binary_type):
4362 return self._encode_time() == their
4363 if isinstance(their, datetime):
4364 return self.todatetime() == their
4365 if not isinstance(their, self.__class__):
4368 self._value == their._value and
4369 self.tag == their.tag and
4370 self._expl == their._expl
4373 def _encode_time(self):
4374 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4377 self._assert_ready()
4378 value = self._encode_time()
4379 return b"".join((self.tag, len_encode(len(value)), value))
4381 def todatetime(self):
4385 return pp_console_row(next(self.pps()))
4387 def pps(self, decode_path=()):
4390 asn1_type_name=self.asn1_type_name,
4391 obj_name=self.__class__.__name__,
4392 decode_path=decode_path,
4393 value=self._pp_value(),
4394 optional=self.optional,
4395 default=self == self.default,
4396 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4397 expl=None if self._expl is None else tag_decode(self._expl),
4402 expl_offset=self.expl_offset if self.expled else None,
4403 expl_tlen=self.expl_tlen if self.expled else None,
4404 expl_llen=self.expl_llen if self.expled else None,
4405 expl_vlen=self.expl_vlen if self.expled else None,
4406 expl_lenindef=self.expl_lenindef,
4407 ber_encoded=self.ber_encoded,
4410 for pp in self.pps_lenindef(decode_path):
4414 class GeneralizedTime(UTCTime):
4415 """``GeneralizedTime`` datetime type
4417 This type is similar to :py:class:`pyderasn.UTCTime`.
4419 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4420 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4422 '20170930220750.000123Z'
4423 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4424 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4428 Only microsecond fractions are supported in DER encoding.
4429 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4430 higher precision values.
4434 BER encoded data can loss information (accuracy) during decoding
4435 because of float transformations.
4439 Local times (without explicit timezone specification) are treated
4440 as UTC one, no transformations are made.
4444 Zero year is unsupported.
4447 tag_default = tag_encode(24)
4448 asn1_type_name = "GeneralizedTime"
4450 def _dt_sanitize(self, value):
4453 def _strptime_bered(self, value):
4454 if len(value) < 4 + 3 * 2:
4455 raise ValueError("invalid GeneralizedTime")
4457 pureint(value[:4]), # %Y
4458 pureint(value[4:6]), # %m
4459 pureint(value[6:8]), # %d
4460 pureint(value[8:10]), # %H
4465 return offset, decoded
4466 if value[-1] == "Z":
4469 for char, sign in (("-", -1), ("+", 1)):
4470 idx = value.rfind(char)
4473 offset_raw = value[idx + 1:].replace(":", "")
4474 if len(offset_raw) not in (2, 4):
4475 raise ValueError("invalid UTC offset")
4477 offset = 60 * pureint(offset_raw[2:] or "0")
4479 raise ValueError("invalid UTC offset minutes")
4480 offset += 3600 * pureint(offset_raw[:2])
4481 if offset > 14 * 3600:
4482 raise ValueError("too big UTC offset")
4486 return offset, decoded
4487 if value[0] in DECIMAL_SIGNS:
4489 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4492 raise ValueError("stripped minutes")
4493 decoded += timedelta(seconds=60 * pureint(value[:2]))
4496 return offset, decoded
4497 if value[0] in DECIMAL_SIGNS:
4499 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4502 raise ValueError("stripped seconds")
4503 decoded += timedelta(seconds=pureint(value[:2]))
4506 return offset, decoded
4507 if value[0] not in DECIMAL_SIGNS:
4508 raise ValueError("invalid format after seconds")
4510 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4513 def _strptime(self, value):
4515 if l == LEN_YYYYMMDDHHMMSSZ:
4516 # datetime.strptime's format: %Y%m%d%H%M%SZ
4517 if value[-1] != "Z":
4518 raise ValueError("non UTC timezone")
4520 pureint(value[:4]), # %Y
4521 pureint(value[4:6]), # %m
4522 pureint(value[6:8]), # %d
4523 pureint(value[8:10]), # %H
4524 pureint(value[10:12]), # %M
4525 pureint(value[12:14]), # %S
4527 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4528 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4529 if value[-1] != "Z":
4530 raise ValueError("non UTC timezone")
4531 if value[14] != ".":
4532 raise ValueError("no fractions separator")
4535 raise ValueError("trailing zero")
4538 raise ValueError("only microsecond fractions are supported")
4539 us = pureint(us + ("0" * (6 - us_len)))
4541 pureint(value[:4]), # %Y
4542 pureint(value[4:6]), # %m
4543 pureint(value[6:8]), # %d
4544 pureint(value[8:10]), # %H
4545 pureint(value[10:12]), # %M
4546 pureint(value[12:14]), # %S
4550 raise ValueError("invalid GeneralizedTime length")
4552 def _encode_time(self):
4554 encoded = value.strftime("%Y%m%d%H%M%S")
4555 if value.microsecond > 0:
4556 encoded += (".%06d" % value.microsecond).rstrip("0")
4557 return (encoded + "Z").encode("ascii")
4560 class GraphicString(CommonString):
4562 tag_default = tag_encode(25)
4563 encoding = "iso-8859-1"
4564 asn1_type_name = "GraphicString"
4567 class ISO646String(VisibleString):
4569 asn1_type_name = "ISO646String"
4572 class GeneralString(CommonString):
4574 tag_default = tag_encode(27)
4575 encoding = "iso-8859-1"
4576 asn1_type_name = "GeneralString"
4579 class UniversalString(CommonString):
4581 tag_default = tag_encode(28)
4582 encoding = "utf-32-be"
4583 asn1_type_name = "UniversalString"
4586 class BMPString(CommonString):
4588 tag_default = tag_encode(30)
4589 encoding = "utf-16-be"
4590 asn1_type_name = "BMPString"
4593 ChoiceState = namedtuple("ChoiceState", (
4607 ), **NAMEDTUPLE_KWARGS)
4611 """``CHOICE`` special type
4615 class GeneralName(Choice):
4617 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4618 ("dNSName", IA5String(impl=tag_ctxp(2))),
4621 >>> gn = GeneralName()
4623 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4624 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4625 >>> gn["dNSName"] = IA5String("bar.baz")
4626 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4627 >>> gn["rfc822Name"]
4630 [2] IA5String IA5 bar.baz
4633 >>> gn.value == gn["dNSName"]
4636 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4638 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4639 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4641 __slots__ = ("specs",)
4643 asn1_type_name = "CHOICE"
4656 :param value: set the value. Either ``(choice, value)`` tuple, or
4657 :py:class:`pyderasn.Choice` object
4658 :param bytes impl: can not be set, do **not** use it
4659 :param bytes expl: override default tag with ``EXPLICIT`` one
4660 :param default: set default value. Type same as in ``value``
4661 :param bool optional: is object ``OPTIONAL`` in sequence
4663 if impl is not None:
4664 raise ValueError("no implicit tag allowed for CHOICE")
4665 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4667 schema = getattr(self, "schema", ())
4668 if len(schema) == 0:
4669 raise ValueError("schema must be specified")
4671 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4674 if value is not None:
4675 self._value = self._value_sanitize(value)
4676 if default is not None:
4677 default_value = self._value_sanitize(default)
4678 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4679 default_obj.specs = self.specs
4680 default_obj._value = default_value
4681 self.default = default_obj
4683 self._value = copy(default_obj._value)
4685 def _value_sanitize(self, value):
4686 if isinstance(value, tuple) and len(value) == 2:
4688 spec = self.specs.get(choice)
4690 raise ObjUnknown(choice)
4691 if not isinstance(obj, spec.__class__):
4692 raise InvalidValueType((spec,))
4693 return (choice, spec(obj))
4694 if isinstance(value, self.__class__):
4696 raise InvalidValueType((self.__class__, tuple))
4700 return self._value is not None and self._value[1].ready
4704 return self.expl_lenindef or (
4705 (self._value is not None) and
4706 self._value[1].bered
4709 def __getstate__(self):
4726 def __setstate__(self, state):
4727 super(Choice, self).__setstate__(state)
4728 self.specs = state.specs
4729 self._value = state.value
4730 self._expl = state.expl
4731 self.default = state.default
4732 self.optional = state.optional
4733 self.offset = state.offset
4734 self.llen = state.llen
4735 self.vlen = state.vlen
4736 self.expl_lenindef = state.expl_lenindef
4737 self.lenindef = state.lenindef
4738 self.ber_encoded = state.ber_encoded
4740 def __eq__(self, their):
4741 if isinstance(their, tuple) and len(their) == 2:
4742 return self._value == their
4743 if not isinstance(their, self.__class__):
4746 self.specs == their.specs and
4747 self._value == their._value
4757 return self.__class__(
4760 expl=self._expl if expl is None else expl,
4761 default=self.default if default is None else default,
4762 optional=self.optional if optional is None else optional,
4767 self._assert_ready()
4768 return self._value[0]
4772 self._assert_ready()
4773 return self._value[1]
4775 def __getitem__(self, key):
4776 if key not in self.specs:
4777 raise ObjUnknown(key)
4778 if self._value is None:
4780 choice, value = self._value
4785 def __setitem__(self, key, value):
4786 spec = self.specs.get(key)
4788 raise ObjUnknown(key)
4789 if not isinstance(value, spec.__class__):
4790 raise InvalidValueType((spec.__class__,))
4791 self._value = (key, spec(value))
4799 return self._value[1].decoded if self.ready else False
4802 self._assert_ready()
4803 return self._value[1].encode()
4805 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4806 for choice, spec in iteritems(self.specs):
4807 sub_decode_path = decode_path + (choice,)
4813 decode_path=sub_decode_path,
4816 _ctx_immutable=False,
4823 klass=self.__class__,
4824 decode_path=decode_path,
4827 if tag_only: # pragma: no cover
4829 value, tail = spec.decode(
4833 decode_path=sub_decode_path,
4835 _ctx_immutable=False,
4837 obj = self.__class__(
4840 default=self.default,
4841 optional=self.optional,
4842 _decoded=(offset, 0, value.fulllen),
4844 obj._value = (choice, value)
4848 value = pp_console_row(next(self.pps()))
4850 value = "%s[%r]" % (value, self.value)
4853 def pps(self, decode_path=()):
4856 asn1_type_name=self.asn1_type_name,
4857 obj_name=self.__class__.__name__,
4858 decode_path=decode_path,
4859 value=self.choice if self.ready else None,
4860 optional=self.optional,
4861 default=self == self.default,
4862 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4863 expl=None if self._expl is None else tag_decode(self._expl),
4868 expl_lenindef=self.expl_lenindef,
4872 yield self.value.pps(decode_path=decode_path + (self.choice,))
4873 for pp in self.pps_lenindef(decode_path):
4877 class PrimitiveTypes(Choice):
4878 """Predefined ``CHOICE`` for all generic primitive types
4880 It could be useful for general decoding of some unspecified values:
4882 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4883 OCTET STRING 3 bytes 666f6f
4884 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4888 schema = tuple((klass.__name__, klass()) for klass in (
4912 AnyState = namedtuple("AnyState", (
4925 ), **NAMEDTUPLE_KWARGS)
4929 """``ANY`` special type
4931 >>> Any(Integer(-123))
4933 >>> a = Any(OctetString(b"hello world").encode())
4934 ANY 040b68656c6c6f20776f726c64
4935 >>> hexenc(bytes(a))
4936 b'0x040x0bhello world'
4938 __slots__ = ("defined",)
4939 tag_default = tag_encode(0)
4940 asn1_type_name = "ANY"
4950 :param value: set the value. Either any kind of pyderasn's
4951 **ready** object, or bytes. Pay attention that
4952 **no** validation is performed is raw binary value
4954 :param bytes expl: override default tag with ``EXPLICIT`` one
4955 :param bool optional: is object ``OPTIONAL`` in sequence
4957 super(Any, self).__init__(None, expl, None, optional, _decoded)
4958 self._value = None if value is None else self._value_sanitize(value)
4961 def _value_sanitize(self, value):
4962 if isinstance(value, binary_type):
4964 if isinstance(value, self.__class__):
4966 if isinstance(value, Obj):
4967 return value.encode()
4968 raise InvalidValueType((self.__class__, Obj, binary_type))
4972 return self._value is not None
4976 if self.expl_lenindef or self.lenindef:
4978 if self.defined is None:
4980 return self.defined[1].bered
4982 def __getstate__(self):
4998 def __setstate__(self, state):
4999 super(Any, self).__setstate__(state)
5000 self._value = state.value
5001 self.tag = state.tag
5002 self._expl = state.expl
5003 self.optional = state.optional
5004 self.offset = state.offset
5005 self.llen = state.llen
5006 self.vlen = state.vlen
5007 self.expl_lenindef = state.expl_lenindef
5008 self.lenindef = state.lenindef
5009 self.ber_encoded = state.ber_encoded
5010 self.defined = state.defined
5012 def __eq__(self, their):
5013 if isinstance(their, binary_type):
5014 return self._value == their
5015 if issubclass(their.__class__, Any):
5016 return self._value == their._value
5025 return self.__class__(
5027 expl=self._expl if expl is None else expl,
5028 optional=self.optional if optional is None else optional,
5031 def __bytes__(self):
5032 self._assert_ready()
5040 self._assert_ready()
5043 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5045 t, tlen, lv = tag_strip(tlv)
5046 except DecodeError as err:
5047 raise err.__class__(
5049 klass=self.__class__,
5050 decode_path=decode_path,
5054 l, llen, v = len_decode(lv)
5055 except LenIndefForm as err:
5056 if not ctx.get("bered", False):
5057 raise err.__class__(
5059 klass=self.__class__,
5060 decode_path=decode_path,
5063 llen, vlen, v = 1, 0, lv[1:]
5064 sub_offset = offset + tlen + llen
5066 while v[:EOC_LEN].tobytes() != EOC:
5067 chunk, v = Any().decode(
5070 decode_path=decode_path + (str(chunk_i),),
5073 _ctx_immutable=False,
5075 vlen += chunk.tlvlen
5076 sub_offset += chunk.tlvlen
5078 tlvlen = tlen + llen + vlen + EOC_LEN
5079 obj = self.__class__(
5080 value=tlv[:tlvlen].tobytes(),
5082 optional=self.optional,
5083 _decoded=(offset, 0, tlvlen),
5086 obj.tag = t.tobytes()
5087 return obj, v[EOC_LEN:]
5088 except DecodeError as err:
5089 raise err.__class__(
5091 klass=self.__class__,
5092 decode_path=decode_path,
5096 raise NotEnoughData(
5097 "encoded length is longer than data",
5098 klass=self.__class__,
5099 decode_path=decode_path,
5102 tlvlen = tlen + llen + l
5103 v, tail = tlv[:tlvlen], v[l:]
5104 obj = self.__class__(
5107 optional=self.optional,
5108 _decoded=(offset, 0, tlvlen),
5110 obj.tag = t.tobytes()
5114 return pp_console_row(next(self.pps()))
5116 def pps(self, decode_path=()):
5119 asn1_type_name=self.asn1_type_name,
5120 obj_name=self.__class__.__name__,
5121 decode_path=decode_path,
5122 blob=self._value if self.ready else None,
5123 optional=self.optional,
5124 default=self == self.default,
5125 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5126 expl=None if self._expl is None else tag_decode(self._expl),
5131 expl_offset=self.expl_offset if self.expled else None,
5132 expl_tlen=self.expl_tlen if self.expled else None,
5133 expl_llen=self.expl_llen if self.expled else None,
5134 expl_vlen=self.expl_vlen if self.expled else None,
5135 expl_lenindef=self.expl_lenindef,
5136 lenindef=self.lenindef,
5139 defined_by, defined = self.defined or (None, None)
5140 if defined_by is not None:
5142 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5144 for pp in self.pps_lenindef(decode_path):
5148 ########################################################################
5149 # ASN.1 constructed types
5150 ########################################################################
5152 def get_def_by_path(defines_by_path, sub_decode_path):
5153 """Get define by decode path
5155 for path, define in defines_by_path:
5156 if len(path) != len(sub_decode_path):
5158 for p1, p2 in zip(path, sub_decode_path):
5159 if (p1 != any) and (p1 != p2):
5165 def abs_decode_path(decode_path, rel_path):
5166 """Create an absolute decode path from current and relative ones
5168 :param decode_path: current decode path, starting point. Tuple of strings
5169 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5170 If first tuple's element is "/", then treat it as
5171 an absolute path, ignoring ``decode_path`` as
5172 starting point. Also this tuple can contain ".."
5173 elements, stripping the leading element from
5176 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5177 ("foo", "bar", "baz", "whatever")
5178 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5180 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5183 if rel_path[0] == "/":
5185 if rel_path[0] == "..":
5186 return abs_decode_path(decode_path[:-1], rel_path[1:])
5187 return decode_path + rel_path
5190 SequenceState = namedtuple("SequenceState", (
5204 ), **NAMEDTUPLE_KWARGS)
5207 class Sequence(Obj):
5208 """``SEQUENCE`` structure type
5210 You have to make specification of sequence::
5212 class Extension(Sequence):
5214 ("extnID", ObjectIdentifier()),
5215 ("critical", Boolean(default=False)),
5216 ("extnValue", OctetString()),
5219 Then, you can work with it as with dictionary.
5221 >>> ext = Extension()
5222 >>> Extension().specs
5224 ('extnID', OBJECT IDENTIFIER),
5225 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5226 ('extnValue', OCTET STRING),
5228 >>> ext["extnID"] = "1.2.3"
5229 Traceback (most recent call last):
5230 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5231 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5233 You can determine if sequence is ready to be encoded:
5238 Traceback (most recent call last):
5239 pyderasn.ObjNotReady: object is not ready: extnValue
5240 >>> ext["extnValue"] = OctetString(b"foobar")
5244 Value you want to assign, must have the same **type** as in
5245 corresponding specification, but it can have different tags,
5246 optional/default attributes -- they will be taken from specification
5249 class TBSCertificate(Sequence):
5251 ("version", Version(expl=tag_ctxc(0), default="v1")),
5254 >>> tbs = TBSCertificate()
5255 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5257 Assign ``None`` to remove value from sequence.
5259 You can set values in Sequence during its initialization:
5261 >>> AlgorithmIdentifier((
5262 ("algorithm", ObjectIdentifier("1.2.3")),
5263 ("parameters", Any(Null()))
5265 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5267 You can determine if value exists/set in the sequence and take its value:
5269 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5272 OBJECT IDENTIFIER 1.2.3
5274 But pay attention that if value has default, then it won't be (not
5275 in) in the sequence (because ``DEFAULT`` must not be encoded in
5276 DER), but you can read its value:
5278 >>> "critical" in ext, ext["critical"]
5279 (False, BOOLEAN False)
5280 >>> ext["critical"] = Boolean(True)
5281 >>> "critical" in ext, ext["critical"]
5282 (True, BOOLEAN True)
5284 All defaulted values are always optional.
5286 .. _allow_default_values_ctx:
5288 DER prohibits default value encoding and will raise an error if
5289 default value is unexpectedly met during decode.
5290 If :ref:`bered <bered_ctx>` context option is set, then no error
5291 will be raised, but ``bered`` attribute set. You can disable strict
5292 defaulted values existence validation by setting
5293 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5295 Two sequences are equal if they have equal specification (schema),
5296 implicit/explicit tagging and the same values.
5298 __slots__ = ("specs",)
5299 tag_default = tag_encode(form=TagFormConstructed, num=16)
5300 asn1_type_name = "SEQUENCE"
5312 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5314 schema = getattr(self, "schema", ())
5316 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5319 if value is not None:
5320 if issubclass(value.__class__, Sequence):
5321 self._value = value._value
5322 elif hasattr(value, "__iter__"):
5323 for seq_key, seq_value in value:
5324 self[seq_key] = seq_value
5326 raise InvalidValueType((Sequence,))
5327 if default is not None:
5328 if not issubclass(default.__class__, Sequence):
5329 raise InvalidValueType((Sequence,))
5330 default_value = default._value
5331 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5332 default_obj.specs = self.specs
5333 default_obj._value = default_value
5334 self.default = default_obj
5336 self._value = copy(default_obj._value)
5340 for name, spec in iteritems(self.specs):
5341 value = self._value.get(name)
5352 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5354 return any(value.bered for value in itervalues(self._value))
5356 def __getstate__(self):
5357 return SequenceState(
5360 {k: copy(v) for k, v in iteritems(self._value)},
5373 def __setstate__(self, state):
5374 super(Sequence, self).__setstate__(state)
5375 self.specs = state.specs
5376 self._value = state.value
5377 self.tag = state.tag
5378 self._expl = state.expl
5379 self.default = state.default
5380 self.optional = state.optional
5381 self.offset = state.offset
5382 self.llen = state.llen
5383 self.vlen = state.vlen
5384 self.expl_lenindef = state.expl_lenindef
5385 self.lenindef = state.lenindef
5386 self.ber_encoded = state.ber_encoded
5388 def __eq__(self, their):
5389 if not isinstance(their, self.__class__):
5392 self.specs == their.specs and
5393 self.tag == their.tag and
5394 self._expl == their._expl and
5395 self._value == their._value
5406 return self.__class__(
5409 impl=self.tag if impl is None else impl,
5410 expl=self._expl if expl is None else expl,
5411 default=self.default if default is None else default,
5412 optional=self.optional if optional is None else optional,
5415 def __contains__(self, key):
5416 return key in self._value
5418 def __setitem__(self, key, value):
5419 spec = self.specs.get(key)
5421 raise ObjUnknown(key)
5423 self._value.pop(key, None)
5425 if not isinstance(value, spec.__class__):
5426 raise InvalidValueType((spec.__class__,))
5427 value = spec(value=value)
5428 if spec.default is not None and value == spec.default:
5429 self._value.pop(key, None)
5431 self._value[key] = value
5433 def __getitem__(self, key):
5434 value = self._value.get(key)
5435 if value is not None:
5437 spec = self.specs.get(key)
5439 raise ObjUnknown(key)
5440 if spec.default is not None:
5444 def _encoded_values(self):
5446 for name, spec in iteritems(self.specs):
5447 value = self._value.get(name)
5451 raise ObjNotReady(name)
5452 raws.append(value.encode())
5456 v = b"".join(self._encoded_values())
5457 return b"".join((self.tag, len_encode(len(v)), v))
5459 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5461 t, tlen, lv = tag_strip(tlv)
5462 except DecodeError as err:
5463 raise err.__class__(
5465 klass=self.__class__,
5466 decode_path=decode_path,
5471 klass=self.__class__,
5472 decode_path=decode_path,
5475 if tag_only: # pragma: no cover
5478 ctx_bered = ctx.get("bered", False)
5480 l, llen, v = len_decode(lv)
5481 except LenIndefForm as err:
5483 raise err.__class__(
5485 klass=self.__class__,
5486 decode_path=decode_path,
5489 l, llen, v = 0, 1, lv[1:]
5491 except DecodeError as err:
5492 raise err.__class__(
5494 klass=self.__class__,
5495 decode_path=decode_path,
5499 raise NotEnoughData(
5500 "encoded length is longer than data",
5501 klass=self.__class__,
5502 decode_path=decode_path,
5506 v, tail = v[:l], v[l:]
5508 sub_offset = offset + tlen + llen
5511 ctx_allow_default_values = ctx.get("allow_default_values", False)
5512 for name, spec in iteritems(self.specs):
5513 if spec.optional and (
5514 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5518 sub_decode_path = decode_path + (name,)
5520 value, v_tail = spec.decode(
5524 decode_path=sub_decode_path,
5526 _ctx_immutable=False,
5528 except TagMismatch as err:
5529 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5533 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5534 if defined is not None:
5535 defined_by, defined_spec = defined
5536 if issubclass(value.__class__, SequenceOf):
5537 for i, _value in enumerate(value):
5538 sub_sub_decode_path = sub_decode_path + (
5540 DecodePathDefBy(defined_by),
5542 defined_value, defined_tail = defined_spec.decode(
5543 memoryview(bytes(_value)),
5545 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5546 if value.expled else (value.tlen + value.llen)
5549 decode_path=sub_sub_decode_path,
5551 _ctx_immutable=False,
5553 if len(defined_tail) > 0:
5556 klass=self.__class__,
5557 decode_path=sub_sub_decode_path,
5560 _value.defined = (defined_by, defined_value)
5562 defined_value, defined_tail = defined_spec.decode(
5563 memoryview(bytes(value)),
5565 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5566 if value.expled else (value.tlen + value.llen)
5569 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5571 _ctx_immutable=False,
5573 if len(defined_tail) > 0:
5576 klass=self.__class__,
5577 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5580 value.defined = (defined_by, defined_value)
5582 value_len = value.fulllen
5584 sub_offset += value_len
5586 if spec.default is not None and value == spec.default:
5587 if ctx_bered or ctx_allow_default_values:
5591 "DEFAULT value met",
5592 klass=self.__class__,
5593 decode_path=sub_decode_path,
5596 values[name] = value
5598 spec_defines = getattr(spec, "defines", ())
5599 if len(spec_defines) == 0:
5600 defines_by_path = ctx.get("defines_by_path", ())
5601 if len(defines_by_path) > 0:
5602 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5603 if spec_defines is not None and len(spec_defines) > 0:
5604 for rel_path, schema in spec_defines:
5605 defined = schema.get(value, None)
5606 if defined is not None:
5607 ctx.setdefault("_defines", []).append((
5608 abs_decode_path(sub_decode_path[:-1], rel_path),
5612 if v[:EOC_LEN].tobytes() != EOC:
5615 klass=self.__class__,
5616 decode_path=decode_path,
5624 klass=self.__class__,
5625 decode_path=decode_path,
5628 obj = self.__class__(
5632 default=self.default,
5633 optional=self.optional,
5634 _decoded=(offset, llen, vlen),
5637 obj.lenindef = lenindef
5638 obj.ber_encoded = ber_encoded
5642 value = pp_console_row(next(self.pps()))
5644 for name in self.specs:
5645 _value = self._value.get(name)
5648 cols.append("%s: %s" % (name, repr(_value)))
5649 return "%s[%s]" % (value, "; ".join(cols))
5651 def pps(self, decode_path=()):
5654 asn1_type_name=self.asn1_type_name,
5655 obj_name=self.__class__.__name__,
5656 decode_path=decode_path,
5657 optional=self.optional,
5658 default=self == self.default,
5659 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5660 expl=None if self._expl is None else tag_decode(self._expl),
5665 expl_offset=self.expl_offset if self.expled else None,
5666 expl_tlen=self.expl_tlen if self.expled else None,
5667 expl_llen=self.expl_llen if self.expled else None,
5668 expl_vlen=self.expl_vlen if self.expled else None,
5669 expl_lenindef=self.expl_lenindef,
5670 lenindef=self.lenindef,
5671 ber_encoded=self.ber_encoded,
5674 for name in self.specs:
5675 value = self._value.get(name)
5678 yield value.pps(decode_path=decode_path + (name,))
5679 for pp in self.pps_lenindef(decode_path):
5683 class Set(Sequence):
5684 """``SET`` structure type
5686 Its usage is identical to :py:class:`pyderasn.Sequence`.
5688 .. _allow_unordered_set_ctx:
5690 DER prohibits unordered values encoding and will raise an error
5691 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5692 then no error will occure. Also you can disable strict values
5693 ordering check by setting ``"allow_unordered_set": True``
5694 :ref:`context <ctx>` option.
5697 tag_default = tag_encode(form=TagFormConstructed, num=17)
5698 asn1_type_name = "SET"
5701 raws = self._encoded_values()
5704 return b"".join((self.tag, len_encode(len(v)), v))
5706 def _specs_items(self):
5707 return iteritems(self.specs)
5709 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5711 t, tlen, lv = tag_strip(tlv)
5712 except DecodeError as err:
5713 raise err.__class__(
5715 klass=self.__class__,
5716 decode_path=decode_path,
5721 klass=self.__class__,
5722 decode_path=decode_path,
5728 ctx_bered = ctx.get("bered", False)
5730 l, llen, v = len_decode(lv)
5731 except LenIndefForm as err:
5733 raise err.__class__(
5735 klass=self.__class__,
5736 decode_path=decode_path,
5739 l, llen, v = 0, 1, lv[1:]
5741 except DecodeError as err:
5742 raise err.__class__(
5744 klass=self.__class__,
5745 decode_path=decode_path,
5749 raise NotEnoughData(
5750 "encoded length is longer than data",
5751 klass=self.__class__,
5755 v, tail = v[:l], v[l:]
5757 sub_offset = offset + tlen + llen
5760 ctx_allow_default_values = ctx.get("allow_default_values", False)
5761 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5762 value_prev = memoryview(v[:0])
5765 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5767 for name, spec in self._specs_items():
5768 sub_decode_path = decode_path + (name,)
5774 decode_path=sub_decode_path,
5777 _ctx_immutable=False,
5784 klass=self.__class__,
5785 decode_path=decode_path,
5788 value, v_tail = spec.decode(
5792 decode_path=sub_decode_path,
5794 _ctx_immutable=False,
5796 value_len = value.fulllen
5797 if value_prev.tobytes() > v[:value_len].tobytes():
5798 if ctx_bered or ctx_allow_unordered_set:
5802 "unordered " + self.asn1_type_name,
5803 klass=self.__class__,
5804 decode_path=sub_decode_path,
5807 if spec.default is None or value != spec.default:
5809 elif ctx_bered or ctx_allow_default_values:
5813 "DEFAULT value met",
5814 klass=self.__class__,
5815 decode_path=sub_decode_path,
5818 values[name] = value
5819 value_prev = v[:value_len]
5820 sub_offset += value_len
5823 obj = self.__class__(
5827 default=self.default,
5828 optional=self.optional,
5829 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5832 if v[:EOC_LEN].tobytes() != EOC:
5835 klass=self.__class__,
5836 decode_path=decode_path,
5844 "not all values are ready",
5845 klass=self.__class__,
5846 decode_path=decode_path,
5849 obj.ber_encoded = ber_encoded
5853 SequenceOfState = namedtuple("SequenceOfState", (
5869 ), **NAMEDTUPLE_KWARGS)
5872 class SequenceOf(Obj):
5873 """``SEQUENCE OF`` sequence type
5875 For that kind of type you must specify the object it will carry on
5876 (bounds are for example here, not required)::
5878 class Ints(SequenceOf):
5883 >>> ints.append(Integer(123))
5884 >>> ints.append(Integer(234))
5886 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5887 >>> [int(i) for i in ints]
5889 >>> ints.append(Integer(345))
5890 Traceback (most recent call last):
5891 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5894 >>> ints[1] = Integer(345)
5896 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5898 Also you can initialize sequence with preinitialized values:
5900 >>> ints = Ints([Integer(123), Integer(234)])
5902 __slots__ = ("spec", "_bound_min", "_bound_max")
5903 tag_default = tag_encode(form=TagFormConstructed, num=16)
5904 asn1_type_name = "SEQUENCE OF"
5917 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5919 schema = getattr(self, "schema", None)
5921 raise ValueError("schema must be specified")
5923 self._bound_min, self._bound_max = getattr(
5927 ) if bounds is None else bounds
5929 if value is not None:
5930 self._value = self._value_sanitize(value)
5931 if default is not None:
5932 default_value = self._value_sanitize(default)
5933 default_obj = self.__class__(
5938 default_obj._value = default_value
5939 self.default = default_obj
5941 self._value = copy(default_obj._value)
5943 def _value_sanitize(self, value):
5944 if issubclass(value.__class__, SequenceOf):
5945 value = value._value
5946 elif hasattr(value, "__iter__"):
5949 raise InvalidValueType((self.__class__, iter))
5950 if not self._bound_min <= len(value) <= self._bound_max:
5951 raise BoundsError(self._bound_min, len(value), self._bound_max)
5953 if not isinstance(v, self.spec.__class__):
5954 raise InvalidValueType((self.spec.__class__,))
5959 return all(v.ready for v in self._value)
5963 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5965 return any(v.bered for v in self._value)
5967 def __getstate__(self):
5968 return SequenceOfState(
5971 [copy(v) for v in self._value],
5986 def __setstate__(self, state):
5987 super(SequenceOf, self).__setstate__(state)
5988 self.spec = state.spec
5989 self._value = state.value
5990 self._bound_min = state.bound_min
5991 self._bound_max = state.bound_max
5992 self.tag = state.tag
5993 self._expl = state.expl
5994 self.default = state.default
5995 self.optional = state.optional
5996 self.offset = state.offset
5997 self.llen = state.llen
5998 self.vlen = state.vlen
5999 self.expl_lenindef = state.expl_lenindef
6000 self.lenindef = state.lenindef
6001 self.ber_encoded = state.ber_encoded
6003 def __eq__(self, their):
6004 if isinstance(their, self.__class__):
6006 self.spec == their.spec and
6007 self.tag == their.tag and
6008 self._expl == their._expl and
6009 self._value == their._value
6011 if hasattr(their, "__iter__"):
6012 return self._value == list(their)
6024 return self.__class__(
6028 (self._bound_min, self._bound_max)
6029 if bounds is None else bounds
6031 impl=self.tag if impl is None else impl,
6032 expl=self._expl if expl is None else expl,
6033 default=self.default if default is None else default,
6034 optional=self.optional if optional is None else optional,
6037 def __contains__(self, key):
6038 return key in self._value
6040 def append(self, value):
6041 if not isinstance(value, self.spec.__class__):
6042 raise InvalidValueType((self.spec.__class__,))
6043 if len(self._value) + 1 > self._bound_max:
6046 len(self._value) + 1,
6049 self._value.append(value)
6052 self._assert_ready()
6053 return iter(self._value)
6056 self._assert_ready()
6057 return len(self._value)
6059 def __setitem__(self, key, value):
6060 if not isinstance(value, self.spec.__class__):
6061 raise InvalidValueType((self.spec.__class__,))
6062 self._value[key] = self.spec(value=value)
6064 def __getitem__(self, key):
6065 return self._value[key]
6067 def _encoded_values(self):
6068 return [v.encode() for v in self._value]
6071 v = b"".join(self._encoded_values())
6072 return b"".join((self.tag, len_encode(len(v)), v))
6074 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6076 t, tlen, lv = tag_strip(tlv)
6077 except DecodeError as err:
6078 raise err.__class__(
6080 klass=self.__class__,
6081 decode_path=decode_path,
6086 klass=self.__class__,
6087 decode_path=decode_path,
6093 ctx_bered = ctx.get("bered", False)
6095 l, llen, v = len_decode(lv)
6096 except LenIndefForm as err:
6098 raise err.__class__(
6100 klass=self.__class__,
6101 decode_path=decode_path,
6104 l, llen, v = 0, 1, lv[1:]
6106 except DecodeError as err:
6107 raise err.__class__(
6109 klass=self.__class__,
6110 decode_path=decode_path,
6114 raise NotEnoughData(
6115 "encoded length is longer than data",
6116 klass=self.__class__,
6117 decode_path=decode_path,
6121 v, tail = v[:l], v[l:]
6123 sub_offset = offset + tlen + llen
6125 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6126 value_prev = memoryview(v[:0])
6130 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6132 sub_decode_path = decode_path + (str(len(_value)),)
6133 value, v_tail = spec.decode(
6137 decode_path=sub_decode_path,
6139 _ctx_immutable=False,
6141 value_len = value.fulllen
6143 if value_prev.tobytes() > v[:value_len].tobytes():
6144 if ctx_bered or ctx_allow_unordered_set:
6148 "unordered " + self.asn1_type_name,
6149 klass=self.__class__,
6150 decode_path=sub_decode_path,
6153 value_prev = v[:value_len]
6154 _value.append(value)
6155 sub_offset += value_len
6159 obj = self.__class__(
6162 bounds=(self._bound_min, self._bound_max),
6165 default=self.default,
6166 optional=self.optional,
6167 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6169 except BoundsError as err:
6172 klass=self.__class__,
6173 decode_path=decode_path,
6177 if v[:EOC_LEN].tobytes() != EOC:
6180 klass=self.__class__,
6181 decode_path=decode_path,
6186 obj.ber_encoded = ber_encoded
6191 pp_console_row(next(self.pps())),
6192 ", ".join(repr(v) for v in self._value),
6195 def pps(self, decode_path=()):
6198 asn1_type_name=self.asn1_type_name,
6199 obj_name=self.__class__.__name__,
6200 decode_path=decode_path,
6201 optional=self.optional,
6202 default=self == self.default,
6203 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6204 expl=None if self._expl is None else tag_decode(self._expl),
6209 expl_offset=self.expl_offset if self.expled else None,
6210 expl_tlen=self.expl_tlen if self.expled else None,
6211 expl_llen=self.expl_llen if self.expled else None,
6212 expl_vlen=self.expl_vlen if self.expled else None,
6213 expl_lenindef=self.expl_lenindef,
6214 lenindef=self.lenindef,
6215 ber_encoded=self.ber_encoded,
6218 for i, value in enumerate(self._value):
6219 yield value.pps(decode_path=decode_path + (str(i),))
6220 for pp in self.pps_lenindef(decode_path):
6224 class SetOf(SequenceOf):
6225 """``SET OF`` sequence type
6227 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6230 tag_default = tag_encode(form=TagFormConstructed, num=17)
6231 asn1_type_name = "SET OF"
6234 raws = self._encoded_values()
6237 return b"".join((self.tag, len_encode(len(v)), v))
6239 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6240 return super(SetOf, self)._decode(
6246 ordering_check=True,
6250 def obj_by_path(pypath): # pragma: no cover
6251 """Import object specified as string Python path
6253 Modules must be separated from classes/functions with ``:``.
6255 >>> obj_by_path("foo.bar:Baz")
6256 <class 'foo.bar.Baz'>
6257 >>> obj_by_path("foo.bar:Baz.boo")
6258 <classmethod 'foo.bar.Baz.boo'>
6260 mod, objs = pypath.rsplit(":", 1)
6261 from importlib import import_module
6262 obj = import_module(mod)
6263 for obj_name in objs.split("."):
6264 obj = getattr(obj, obj_name)
6268 def generic_decoder(): # pragma: no cover
6269 # All of this below is a big hack with self references
6270 choice = PrimitiveTypes()
6271 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6272 choice.specs["SetOf"] = SetOf(schema=choice)
6273 for i in six_xrange(31):
6274 choice.specs["SequenceOf%d" % i] = SequenceOf(
6278 choice.specs["Any"] = Any()
6280 # Class name equals to type name, to omit it from output
6281 class SEQUENCEOF(SequenceOf):
6289 with_decode_path=False,
6290 decode_path_only=(),
6292 def _pprint_pps(pps):
6294 if hasattr(pp, "_fields"):
6296 decode_path_only != () and
6297 pp.decode_path[:len(decode_path_only)] != decode_path_only
6300 if pp.asn1_type_name == Choice.asn1_type_name:
6302 pp_kwargs = pp._asdict()
6303 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6304 pp = _pp(**pp_kwargs)
6305 yield pp_console_row(
6310 with_colours=with_colours,
6311 with_decode_path=with_decode_path,
6312 decode_path_len_decrease=len(decode_path_only),
6314 for row in pp_console_blob(
6316 decode_path_len_decrease=len(decode_path_only),
6320 for row in _pprint_pps(pp):
6322 return "\n".join(_pprint_pps(obj.pps()))
6323 return SEQUENCEOF(), pprint_any
6326 def main(): # pragma: no cover
6328 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6329 parser.add_argument(
6333 help="Skip that number of bytes from the beginning",
6335 parser.add_argument(
6337 help="Python paths to dictionary with OIDs, comma separated",
6339 parser.add_argument(
6341 help="Python path to schema definition to use",
6343 parser.add_argument(
6344 "--defines-by-path",
6345 help="Python path to decoder's defines_by_path",
6347 parser.add_argument(
6349 action="store_true",
6350 help="Disallow BER encoding",
6352 parser.add_argument(
6353 "--print-decode-path",
6354 action="store_true",
6355 help="Print decode paths",
6357 parser.add_argument(
6358 "--decode-path-only",
6359 help="Print only specified decode path",
6361 parser.add_argument(
6363 action="store_true",
6364 help="Allow explicit tag out-of-bound",
6366 parser.add_argument(
6368 type=argparse.FileType("rb"),
6369 help="Path to DER file you want to decode",
6371 args = parser.parse_args()
6372 args.DERFile.seek(args.skip)
6373 der = memoryview(args.DERFile.read())
6374 args.DERFile.close()
6376 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6377 if args.oids else ()
6380 schema = obj_by_path(args.schema)
6381 from functools import partial
6382 pprinter = partial(pprint, big_blobs=True)
6384 schema, pprinter = generic_decoder()
6386 "bered": not args.nobered,
6387 "allow_expl_oob": args.allow_expl_oob,
6389 if args.defines_by_path is not None:
6390 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6391 obj, tail = schema().decode(der, ctx=ctx)
6395 with_colours=environ.get("NO_COLOR") is None,
6396 with_decode_path=args.print_decode_path,
6398 () if args.decode_path_only is None else
6399 tuple(args.decode_path_only.split(":"))
6403 print("\nTrailing data: %s" % hexenc(tail))
6406 if __name__ == "__main__":