3 # cython: language_level=3
4 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
5 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, version 3 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Python ASN.1 DER/BER codec with abstract structures
20 This library allows you to marshal various structures in ASN.1 DER
21 format, unmarshal them in BER/CER/DER ones.
25 >>> Integer().decod(raw) == i
28 There are primitive types, holding single values
29 (:py:class:`pyderasn.BitString`,
30 :py:class:`pyderasn.Boolean`,
31 :py:class:`pyderasn.Enumerated`,
32 :py:class:`pyderasn.GeneralizedTime`,
33 :py:class:`pyderasn.Integer`,
34 :py:class:`pyderasn.Null`,
35 :py:class:`pyderasn.ObjectIdentifier`,
36 :py:class:`pyderasn.OctetString`,
37 :py:class:`pyderasn.UTCTime`,
38 :py:class:`various strings <pyderasn.CommonString>`
39 (:py:class:`pyderasn.BMPString`,
40 :py:class:`pyderasn.GeneralString`,
41 :py:class:`pyderasn.GraphicString`,
42 :py:class:`pyderasn.IA5String`,
43 :py:class:`pyderasn.ISO646String`,
44 :py:class:`pyderasn.NumericString`,
45 :py:class:`pyderasn.PrintableString`,
46 :py:class:`pyderasn.T61String`,
47 :py:class:`pyderasn.TeletexString`,
48 :py:class:`pyderasn.UniversalString`,
49 :py:class:`pyderasn.UTF8String`,
50 :py:class:`pyderasn.VideotexString`,
51 :py:class:`pyderasn.VisibleString`)),
52 constructed types, holding multiple primitive types
53 (:py:class:`pyderasn.Sequence`,
54 :py:class:`pyderasn.SequenceOf`,
55 :py:class:`pyderasn.Set`,
56 :py:class:`pyderasn.SetOf`),
57 and special types like
58 :py:class:`pyderasn.Any` and
59 :py:class:`pyderasn.Choice`.
67 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
68 the default tag used during coding process. You can override it with
69 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
70 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
71 argument or ``expl`` class attribute). Both arguments take raw binary
72 string, containing that tag. You can **not** set implicit and explicit
75 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
76 functions, allowing you to easily create ``CONTEXT``
77 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
78 number. Pay attention that explicit tags always have *constructed* tag
79 (``tag_ctxc``), but implicit tags for primitive types are primitive
84 >>> Integer(impl=tag_ctxp(1))
86 >>> Integer(expl=tag_ctxc(2))
89 Implicit tag is not explicitly shown.
91 Two objects of the same type, but with different implicit/explicit tags
94 You can get object's effective tag (either default or implicited) through
95 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
98 >>> tag_decode(tag_ctxc(123))
100 >>> klass, form, num = tag_decode(tag_ctxc(123))
101 >>> klass == TagClassContext
103 >>> form == TagFormConstructed
106 To determine if object has explicit tag, use ``expled`` boolean property
107 and ``expl_tag`` property, returning explicit tag's value.
112 Many objects in sequences could be ``OPTIONAL`` and could have
113 ``DEFAULT`` value. You can specify that object's property using
114 corresponding keyword arguments.
116 >>> Integer(optional=True, default=123)
117 INTEGER 123 OPTIONAL DEFAULT
119 Those specifications do not play any role in primitive value encoding,
120 but are taken into account when dealing with sequences holding them. For
121 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
124 class Version(Integer):
130 class TBSCertificate(Sequence):
132 ("version", Version(expl=tag_ctxc(0), default="v1")),
135 When default argument is used and value is not specified, then it equals
143 Some objects give ability to set value size constraints. This is either
144 possible integer value, or allowed length of various strings and
145 sequences. Constraints are set in the following way::
150 And values satisfaction is checked as: ``MIN <= X <= MAX``.
152 For simplicity you can also set bounds the following way::
154 bounded_x = X(bounds=(MIN, MAX))
156 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
162 All objects have ``ready`` boolean property, that tells if object is
163 ready to be encoded. If that kind of action is performed on unready
164 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
166 All objects are friendly to ``copy.copy()`` and copied objects can be
169 Also all objects can be safely ``pickle``-d, but pay attention that
170 pickling among different PyDERASN versions is prohibited.
177 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
178 ``offset`` optional argument could be used to set initial object's
179 offset in the binary data, for convenience. It returns decoded object
180 and remaining unmarshalled data (tail). Internally all work is done on
181 ``memoryview(data)``, and you can leave returning tail as a memoryview,
182 by specifying ``leavemm=True`` argument.
184 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
185 immediately checks and raises if there is non-empty tail.
187 When object is decoded, ``decoded`` property is true and you can safely
188 use following properties:
190 * ``offset`` -- position including initial offset where object's tag starts
191 * ``tlen`` -- length of object's tag
192 * ``llen`` -- length of object's length value
193 * ``vlen`` -- length of object's value
194 * ``tlvlen`` -- length of the whole object
196 Pay attention that those values do **not** include anything related to
197 explicit tag. If you want to know information about it, then use:
199 * ``expled`` -- to know if explicit tag is set
200 * ``expl_offset`` (it is lesser than ``offset``)
203 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
204 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
206 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
209 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
216 You can specify so called context keyword argument during
217 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
218 various options governing decoding process.
220 Currently available context options:
222 * :ref:`allow_default_values <allow_default_values_ctx>`
223 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
224 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
225 * :ref:`bered <bered_ctx>`
226 * :ref:`defines_by_path <defines_by_path_ctx>`
233 All objects have ``pps()`` method, that is a generator of
234 :py:class:`pyderasn.PP` namedtuple, holding various raw information
235 about the object. If ``pps`` is called on sequences, then all underlying
236 ``PP`` will be yielded.
238 You can use :py:func:`pyderasn.pp_console_row` function, converting
239 those ``PP`` to human readable string. Actually exactly it is used for
240 all object ``repr``. But it is easy to write custom formatters.
242 >>> from pyderasn import pprint
243 >>> encoded = Integer(-12345).encode()
244 >>> obj, tail = Integer().decode(encoded)
245 >>> print(pprint(obj))
246 0 [1,1, 2] INTEGER -12345
250 Example certificate::
252 >>> print(pprint(crt))
253 0 [1,3,1604] Certificate SEQUENCE
254 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
255 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
256 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
257 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
258 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
259 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
261 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
262 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
263 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
264 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
265 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
266 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
267 . . . . . . . 13:02:45:53
269 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
270 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
271 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
273 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
274 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
275 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
280 Let's parse that output, human::
282 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
283 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
284 0 1 2 3 4 5 6 7 8 9 10 11
288 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
294 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
300 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
305 Offset of the object, where its DER/BER encoding begins.
306 Pay attention that it does **not** include explicit tag.
308 If explicit tag exists, then this is its length (tag + encoded length).
310 Length of object's tag. For example CHOICE does not have its own tag,
313 Length of encoded length.
315 Length of encoded value.
317 Visual indentation to show the depth of object in the hierarchy.
319 Object's name inside SEQUENCE/CHOICE.
321 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
322 here. "IMPLICIT" is omitted.
324 Object's class name, if set. Omitted if it is just an ordinary simple
325 value (like with ``algorithm`` in example above).
329 Object's value, if set. Can consist of multiple words (like OCTET/BIT
330 STRINGs above). We see ``v3`` value in Version, because it is named.
331 ``rdnSequence`` is the choice of CHOICE type.
333 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
334 default one, specified in the schema.
336 Shows does object contains any kind of BER encoded data (possibly
337 Sequence holding BER-encoded underlying value).
339 Only applicable to BER encoded data. Indefinite length encoding mark.
341 Only applicable to BER encoded data. If object has BER-specific
342 encoding, then ``BER`` will be shown. It does not depend on indefinite
343 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
344 (and its derivatives), ``SET``, ``SET OF``, ``UTCTime``, ``GeneralizedTime``
353 ASN.1 structures often have ANY and OCTET STRING fields, that are
354 DEFINED BY some previously met ObjectIdentifier. This library provides
355 ability to specify mapping between some OID and field that must be
356 decoded with specific specification.
363 :py:class:`pyderasn.ObjectIdentifier` field inside
364 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
365 necessary for decoding structures. For example, CMS (:rfc:`5652`)
368 class ContentInfo(Sequence):
370 ("contentType", ContentType(defines=((("content",), {
371 id_digestedData: DigestedData(),
372 id_signedData: SignedData(),
374 ("content", Any(expl=tag_ctxc(0))),
377 ``contentType`` field tells that it defines that ``content`` must be
378 decoded with ``SignedData`` specification, if ``contentType`` equals to
379 ``id-signedData``. The same applies to ``DigestedData``. If
380 ``contentType`` contains unknown OID, then no automatic decoding is
383 You can specify multiple fields, that will be autodecoded -- that is why
384 ``defines`` kwarg is a sequence. You can specify defined field
385 relatively or absolutely to current decode path. For example ``defines``
386 for AlgorithmIdentifier of X.509's
387 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
391 id_ecPublicKey: ECParameters(),
392 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
394 (("..", "subjectPublicKey"), {
395 id_rsaEncryption: RSAPublicKey(),
396 id_GostR3410_2001: OctetString(),
400 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
401 autodecode its parameters inside SPKI's algorithm and its public key
404 Following types can be automatically decoded (DEFINED BY):
406 * :py:class:`pyderasn.Any`
407 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
408 * :py:class:`pyderasn.OctetString`
409 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
410 ``Any``/``BitString``/``OctetString``-s
412 When any of those fields is automatically decoded, then ``.defined``
413 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
414 was defined, ``value`` contains corresponding decoded value. For example
415 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
417 .. _defines_by_path_ctx:
419 defines_by_path context option
420 ______________________________
422 Sometimes you either can not or do not want to explicitly set *defines*
423 in the scheme. You can dynamically apply those definitions when calling
424 ``.decode()`` method.
426 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
427 value must be sequence of following tuples::
429 (decode_path, defines)
431 where ``decode_path`` is a tuple holding so-called decode path to the
432 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
433 ``defines``, holding exactly the same value as accepted in its
434 :ref:`keyword argument <defines>`.
436 For example, again for CMS, you want to automatically decode
437 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
438 structures it may hold. Also, automatically decode ``controlSequence``
441 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
444 ((("content",), {id_signedData: SignedData()}),),
449 DecodePathDefBy(id_signedData),
454 id_cct_PKIData: PKIData(),
455 id_cct_PKIResponse: PKIResponse(),
461 DecodePathDefBy(id_signedData),
464 DecodePathDefBy(id_cct_PKIResponse),
470 id_cmc_recipientNonce: RecipientNonce(),
471 id_cmc_senderNonce: SenderNonce(),
472 id_cmc_statusInfoV2: CMCStatusInfoV2(),
473 id_cmc_transactionId: TransactionId(),
478 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
479 First function is useful for path construction when some automatic
480 decoding is already done. ``any`` means literally any value it meet --
481 useful for SEQUENCE/SET OF-s.
488 By default PyDERASN accepts only DER encoded data. It always encodes to
489 DER. But you can optionally enable BER decoding with setting ``bered``
490 :ref:`context <ctx>` argument to True. Indefinite lengths and
491 constructed primitive types should be parsed successfully.
493 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
494 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
495 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``,
496 ``UTCTime``, ``GeneralizedTime`` can contain it.
497 * If object has an indefinite length encoding, then its ``lenindef``
498 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
499 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
501 * If object has an indefinite length encoded explicit tag, then
502 ``expl_lenindef`` is set to True.
503 * If object has either any of BER-related encoding (explicit tag
504 indefinite length, object's indefinite length, BER-encoding) or any
505 underlying component has that kind of encoding, then ``bered``
506 attribute is set to True. For example SignedData CMS can have
507 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
508 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
510 EOC (end-of-contents) token's length is taken in advance in object's
513 .. _allow_expl_oob_ctx:
515 Allow explicit tag out-of-bound
516 -------------------------------
518 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
519 one value, more than one object. If you set ``allow_expl_oob`` context
520 option to True, then no error will be raised and that invalid encoding
521 will be silently further processed. But pay attention that offsets and
522 lengths will be invalid in that case.
526 This option should be used only for skipping some decode errors, just
527 to see the decoded structure somehow.
531 .. autoclass:: pyderasn.Obj
539 .. autoclass:: pyderasn.Boolean
544 .. autoclass:: pyderasn.Integer
549 .. autoclass:: pyderasn.BitString
554 .. autoclass:: pyderasn.OctetString
559 .. autoclass:: pyderasn.Null
564 .. autoclass:: pyderasn.ObjectIdentifier
569 .. autoclass:: pyderasn.Enumerated
573 .. autoclass:: pyderasn.CommonString
577 .. autoclass:: pyderasn.NumericString
581 .. autoclass:: pyderasn.PrintableString
586 .. autoclass:: pyderasn.UTCTime
587 :members: __init__, todatetime
591 .. autoclass:: pyderasn.GeneralizedTime
598 .. autoclass:: pyderasn.Choice
603 .. autoclass:: PrimitiveTypes
607 .. autoclass:: pyderasn.Any
615 .. autoclass:: pyderasn.Sequence
620 .. autoclass:: pyderasn.Set
625 .. autoclass:: pyderasn.SequenceOf
630 .. autoclass:: pyderasn.SetOf
636 .. autofunction:: pyderasn.abs_decode_path
637 .. autofunction:: pyderasn.colonize_hex
638 .. autofunction:: pyderasn.hexenc
639 .. autofunction:: pyderasn.hexdec
640 .. autofunction:: pyderasn.tag_encode
641 .. autofunction:: pyderasn.tag_decode
642 .. autofunction:: pyderasn.tag_ctxp
643 .. autofunction:: pyderasn.tag_ctxc
644 .. autoclass:: pyderasn.DecodeError
646 .. autoclass:: pyderasn.NotEnoughData
647 .. autoclass:: pyderasn.ExceedingData
648 .. autoclass:: pyderasn.LenIndefForm
649 .. autoclass:: pyderasn.TagMismatch
650 .. autoclass:: pyderasn.InvalidLength
651 .. autoclass:: pyderasn.InvalidOID
652 .. autoclass:: pyderasn.ObjUnknown
653 .. autoclass:: pyderasn.ObjNotReady
654 .. autoclass:: pyderasn.InvalidValueType
655 .. autoclass:: pyderasn.BoundsError
658 from codecs import getdecoder
659 from codecs import getencoder
660 from collections import namedtuple
661 from collections import OrderedDict
662 from copy import copy
663 from datetime import datetime
664 from datetime import timedelta
665 from math import ceil
666 from os import environ
667 from string import ascii_letters
668 from string import digits
669 from unicodedata import category as unicat
671 from six import add_metaclass
672 from six import binary_type
673 from six import byte2int
674 from six import indexbytes
675 from six import int2byte
676 from six import integer_types
677 from six import iterbytes
678 from six import iteritems
679 from six import itervalues
681 from six import string_types
682 from six import text_type
683 from six import unichr as six_unichr
684 from six.moves import xrange as six_xrange
688 from termcolor import colored
689 except ImportError: # pragma: no cover
690 def colored(what, *args, **kwargs):
736 "TagClassApplication",
740 "TagFormConstructed",
751 TagClassUniversal = 0
752 TagClassApplication = 1 << 6
753 TagClassContext = 1 << 7
754 TagClassPrivate = 1 << 6 | 1 << 7
756 TagFormConstructed = 1 << 5
759 TagClassApplication: "APPLICATION ",
760 TagClassPrivate: "PRIVATE ",
761 TagClassUniversal: "UNIV ",
765 LENINDEF = b"\x80" # length indefinite mark
766 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
767 NAMEDTUPLE_KWARGS = {} if PY2 else {"module": __name__}
768 SET01 = frozenset("01")
769 DECIMALS = frozenset(digits)
774 if not set(value) <= DECIMALS:
775 raise ValueError("non-pure integer")
778 def fractions2float(fractions_raw):
779 pureint(fractions_raw)
780 return float("0." + fractions_raw)
783 ########################################################################
785 ########################################################################
787 class ASN1Error(ValueError):
791 class DecodeError(ASN1Error):
792 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
794 :param str msg: reason of decode failing
795 :param klass: optional exact DecodeError inherited class (like
796 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
797 :py:exc:`InvalidLength`)
798 :param decode_path: tuple of strings. It contains human
799 readable names of the fields through which
800 decoding process has passed
801 :param int offset: binary offset where failure happened
803 super(DecodeError, self).__init__()
806 self.decode_path = decode_path
812 "" if self.klass is None else self.klass.__name__,
814 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
815 if len(self.decode_path) > 0 else ""
817 ("(at %d)" % self.offset) if self.offset > 0 else "",
823 return "%s(%s)" % (self.__class__.__name__, self)
826 class NotEnoughData(DecodeError):
830 class ExceedingData(ASN1Error):
831 def __init__(self, nbytes):
832 super(ExceedingData, self).__init__()
836 return "%d trailing bytes" % self.nbytes
839 return "%s(%s)" % (self.__class__.__name__, self)
842 class LenIndefForm(DecodeError):
846 class TagMismatch(DecodeError):
850 class InvalidLength(DecodeError):
854 class InvalidOID(DecodeError):
858 class ObjUnknown(ASN1Error):
859 def __init__(self, name):
860 super(ObjUnknown, self).__init__()
864 return "object is unknown: %s" % self.name
867 return "%s(%s)" % (self.__class__.__name__, self)
870 class ObjNotReady(ASN1Error):
871 def __init__(self, name):
872 super(ObjNotReady, self).__init__()
876 return "object is not ready: %s" % self.name
879 return "%s(%s)" % (self.__class__.__name__, self)
882 class InvalidValueType(ASN1Error):
883 def __init__(self, expected_types):
884 super(InvalidValueType, self).__init__()
885 self.expected_types = expected_types
888 return "invalid value type, expected: %s" % ", ".join(
889 [repr(t) for t in self.expected_types]
893 return "%s(%s)" % (self.__class__.__name__, self)
896 class BoundsError(ASN1Error):
897 def __init__(self, bound_min, value, bound_max):
898 super(BoundsError, self).__init__()
899 self.bound_min = bound_min
901 self.bound_max = bound_max
904 return "unsatisfied bounds: %s <= %s <= %s" % (
911 return "%s(%s)" % (self.__class__.__name__, self)
914 ########################################################################
916 ########################################################################
918 _hexdecoder = getdecoder("hex")
919 _hexencoder = getencoder("hex")
923 """Binary data to hexadecimal string convert
925 return _hexdecoder(data)[0]
929 """Hexadecimal string to binary data convert
931 return _hexencoder(data)[0].decode("ascii")
934 def int_bytes_len(num, byte_len=8):
937 return int(ceil(float(num.bit_length()) / byte_len))
940 def zero_ended_encode(num):
941 octets = bytearray(int_bytes_len(num, 7))
943 octets[i] = num & 0x7F
947 octets[i] = 0x80 | (num & 0x7F)
953 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
954 """Encode tag to binary form
956 :param int num: tag's number
957 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
958 :py:data:`pyderasn.TagClassContext`,
959 :py:data:`pyderasn.TagClassApplication`,
960 :py:data:`pyderasn.TagClassPrivate`)
961 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
962 :py:data:`pyderasn.TagFormConstructed`)
966 return int2byte(klass | form | num)
967 # [XX|X|11111][1.......][1.......] ... [0.......]
968 return int2byte(klass | form | 31) + zero_ended_encode(num)
972 """Decode tag from binary form
976 No validation is performed, assuming that it has already passed.
978 It returns tuple with three integers, as
979 :py:func:`pyderasn.tag_encode` accepts.
981 first_octet = byte2int(tag)
982 klass = first_octet & 0xC0
983 form = first_octet & 0x20
984 if first_octet & 0x1F < 0x1F:
985 return (klass, form, first_octet & 0x1F)
987 for octet in iterbytes(tag[1:]):
990 return (klass, form, num)
994 """Create CONTEXT PRIMITIVE tag
996 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
1000 """Create CONTEXT CONSTRUCTED tag
1002 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
1005 def tag_strip(data):
1006 """Take off tag from the data
1008 :returns: (encoded tag, tag length, remaining data)
1011 raise NotEnoughData("no data at all")
1012 if byte2int(data) & 0x1F < 31:
1013 return data[:1], 1, data[1:]
1018 raise DecodeError("unfinished tag")
1019 if indexbytes(data, i) & 0x80 == 0:
1022 return data[:i], i, data[i:]
1028 octets = bytearray(int_bytes_len(l) + 1)
1029 octets[0] = 0x80 | (len(octets) - 1)
1030 for i in six_xrange(len(octets) - 1, 0, -1):
1031 octets[i] = l & 0xFF
1033 return bytes(octets)
1036 def len_decode(data):
1039 :returns: (decoded length, length's length, remaining data)
1040 :raises LenIndefForm: if indefinite form encoding is met
1043 raise NotEnoughData("no data at all")
1044 first_octet = byte2int(data)
1045 if first_octet & 0x80 == 0:
1046 return first_octet, 1, data[1:]
1047 octets_num = first_octet & 0x7F
1048 if octets_num + 1 > len(data):
1049 raise NotEnoughData("encoded length is longer than data")
1051 raise LenIndefForm()
1052 if byte2int(data[1:]) == 0:
1053 raise DecodeError("leading zeros")
1055 for v in iterbytes(data[1:1 + octets_num]):
1058 raise DecodeError("long form instead of short one")
1059 return l, 1 + octets_num, data[1 + octets_num:]
1062 ########################################################################
1064 ########################################################################
1066 class AutoAddSlots(type):
1067 def __new__(cls, name, bases, _dict):
1068 _dict["__slots__"] = _dict.get("__slots__", ())
1069 return type.__new__(cls, name, bases, _dict)
1072 @add_metaclass(AutoAddSlots)
1074 """Common ASN.1 object class
1076 All ASN.1 types are inherited from it. It has metaclass that
1077 automatically adds ``__slots__`` to all inherited classes.
1101 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1102 self._expl = getattr(self, "expl", None) if expl is None else expl
1103 if self.tag != self.tag_default and self._expl is not None:
1104 raise ValueError("implicit and explicit tags can not be set simultaneously")
1105 if default is not None:
1107 self.optional = optional
1108 self.offset, self.llen, self.vlen = _decoded
1110 self.expl_lenindef = False
1111 self.lenindef = False
1112 self.ber_encoded = False
1115 def ready(self): # pragma: no cover
1116 """Is object ready to be encoded?
1118 raise NotImplementedError()
1120 def _assert_ready(self):
1122 raise ObjNotReady(self.__class__.__name__)
1126 """Is either object or any elements inside is BER encoded?
1128 return self.expl_lenindef or self.lenindef or self.ber_encoded
1132 """Is object decoded?
1134 return (self.llen + self.vlen) > 0
1136 def __getstate__(self): # pragma: no cover
1137 """Used for making safe to be mutable pickleable copies
1139 raise NotImplementedError()
1141 def __setstate__(self, state):
1142 if state.version != __version__:
1143 raise ValueError("data is pickled by different PyDERASN version")
1144 self.tag = self.tag_default
1148 self.optional = False
1152 self.expl_lenindef = False
1153 self.lenindef = False
1154 self.ber_encoded = False
1158 """See :ref:`decoding`
1160 return len(self.tag)
1164 """See :ref:`decoding`
1166 return self.tlen + self.llen + self.vlen
1168 def __str__(self): # pragma: no cover
1169 return self.__bytes__() if PY2 else self.__unicode__()
1171 def __ne__(self, their):
1172 return not(self == their)
1174 def __gt__(self, their): # pragma: no cover
1175 return not(self < their)
1177 def __le__(self, their): # pragma: no cover
1178 return (self == their) or (self < their)
1180 def __ge__(self, their): # pragma: no cover
1181 return (self == their) or (self > their)
1183 def _encode(self): # pragma: no cover
1184 raise NotImplementedError()
1186 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1187 raise NotImplementedError()
1190 """Encode the structure
1192 :returns: DER representation
1194 raw = self._encode()
1195 if self._expl is None:
1197 return b"".join((self._expl, len_encode(len(raw)), raw))
1199 def hexencode(self):
1200 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1202 return hexenc(self.encode())
1212 _ctx_immutable=True,
1216 :param data: either binary or memoryview
1217 :param int offset: initial data's offset
1218 :param bool leavemm: do we need to leave memoryview of remaining
1219 data as is, or convert it to bytes otherwise
1220 :param ctx: optional :ref:`context <ctx>` governing decoding process
1221 :param tag_only: decode only the tag, without length and contents
1222 (used only in Choice and Set structures, trying to
1223 determine if tag satisfies the scheme)
1224 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1226 :returns: (Obj, remaining data)
1228 .. seealso:: :ref:`decoding`
1232 elif _ctx_immutable:
1234 tlv = memoryview(data)
1235 if self._expl is None:
1236 result = self._decode(
1239 decode_path=decode_path,
1248 t, tlen, lv = tag_strip(tlv)
1249 except DecodeError as err:
1250 raise err.__class__(
1252 klass=self.__class__,
1253 decode_path=decode_path,
1258 klass=self.__class__,
1259 decode_path=decode_path,
1263 l, llen, v = len_decode(lv)
1264 except LenIndefForm as err:
1265 if not ctx.get("bered", False):
1266 raise err.__class__(
1268 klass=self.__class__,
1269 decode_path=decode_path,
1273 offset += tlen + llen
1274 result = self._decode(
1277 decode_path=decode_path,
1281 if tag_only: # pragma: no cover
1284 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1285 if eoc_expected.tobytes() != EOC:
1288 klass=self.__class__,
1289 decode_path=decode_path,
1293 obj.expl_lenindef = True
1294 except DecodeError as err:
1295 raise err.__class__(
1297 klass=self.__class__,
1298 decode_path=decode_path,
1303 raise NotEnoughData(
1304 "encoded length is longer than data",
1305 klass=self.__class__,
1306 decode_path=decode_path,
1309 result = self._decode(
1311 offset=offset + tlen + llen,
1312 decode_path=decode_path,
1316 if tag_only: # pragma: no cover
1319 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1321 "explicit tag out-of-bound, longer than data",
1322 klass=self.__class__,
1323 decode_path=decode_path,
1326 return obj, (tail if leavemm else tail.tobytes())
1328 def decod(self, data, offset=0, decode_path=(), ctx=None):
1329 """Decode the data, check that tail is empty
1331 :raises ExceedingData: if tail is not empty
1333 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1334 (decode without tail) that also checks that there is no
1337 obj, tail = self.decode(
1340 decode_path=decode_path,
1345 raise ExceedingData(len(tail))
1348 def hexdecode(self, data, *args, **kwargs):
1349 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1351 return self.decode(hexdec(data), *args, **kwargs)
1353 def hexdecod(self, data, *args, **kwargs):
1354 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1356 return self.decod(hexdec(data), *args, **kwargs)
1360 """See :ref:`decoding`
1362 return self._expl is not None
1366 """See :ref:`decoding`
1371 def expl_tlen(self):
1372 """See :ref:`decoding`
1374 return len(self._expl)
1377 def expl_llen(self):
1378 """See :ref:`decoding`
1380 if self.expl_lenindef:
1382 return len(len_encode(self.tlvlen))
1385 def expl_offset(self):
1386 """See :ref:`decoding`
1388 return self.offset - self.expl_tlen - self.expl_llen
1391 def expl_vlen(self):
1392 """See :ref:`decoding`
1397 def expl_tlvlen(self):
1398 """See :ref:`decoding`
1400 return self.expl_tlen + self.expl_llen + self.expl_vlen
1403 def fulloffset(self):
1404 """See :ref:`decoding`
1406 return self.expl_offset if self.expled else self.offset
1410 """See :ref:`decoding`
1412 return self.expl_tlvlen if self.expled else self.tlvlen
1414 def pps_lenindef(self, decode_path):
1415 if self.lenindef and not (
1416 getattr(self, "defined", None) is not None and
1417 self.defined[1].lenindef
1420 asn1_type_name="EOC",
1422 decode_path=decode_path,
1424 self.offset + self.tlvlen -
1425 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1433 if self.expl_lenindef:
1435 asn1_type_name="EOC",
1436 obj_name="EXPLICIT",
1437 decode_path=decode_path,
1438 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1447 class DecodePathDefBy(object):
1448 """DEFINED BY representation inside decode path
1450 __slots__ = ("defined_by",)
1452 def __init__(self, defined_by):
1453 self.defined_by = defined_by
1455 def __ne__(self, their):
1456 return not(self == their)
1458 def __eq__(self, their):
1459 if not isinstance(their, self.__class__):
1461 return self.defined_by == their.defined_by
1464 return "DEFINED BY " + str(self.defined_by)
1467 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1470 ########################################################################
1472 ########################################################################
1474 PP = namedtuple("PP", (
1497 ), **NAMEDTUPLE_KWARGS)
1502 asn1_type_name="unknown",
1519 expl_lenindef=False,
1550 def _colourize(what, colour, with_colours, attrs=("bold",)):
1551 return colored(what, colour, attrs=attrs) if with_colours else what
1554 def colonize_hex(hexed):
1555 """Separate hexadecimal string with colons
1557 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1566 with_decode_path=False,
1567 decode_path_len_decrease=0,
1574 " " if pp.expl_offset is None else
1575 ("-%d" % (pp.offset - pp.expl_offset))
1577 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1579 col = _colourize(col, "red", with_colours, ())
1580 col += _colourize("B", "red", with_colours) if pp.bered else " "
1582 col = "[%d,%d,%4d]%s" % (
1586 LENINDEF_PP_CHAR if pp.lenindef else " "
1588 col = _colourize(col, "green", with_colours, ())
1590 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1591 if decode_path_len > 0:
1592 cols.append(" ." * decode_path_len)
1593 ent = pp.decode_path[-1]
1594 if isinstance(ent, DecodePathDefBy):
1595 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1596 value = str(ent.defined_by)
1599 len(oid_maps) > 0 and
1600 ent.defined_by.asn1_type_name ==
1601 ObjectIdentifier.asn1_type_name
1603 for oid_map in oid_maps:
1604 oid_name = oid_map.get(value)
1605 if oid_name is not None:
1606 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1608 if oid_name is None:
1609 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1611 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1612 if pp.expl is not None:
1613 klass, _, num = pp.expl
1614 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1615 cols.append(_colourize(col, "blue", with_colours))
1616 if pp.impl is not None:
1617 klass, _, num = pp.impl
1618 col = "[%s%d]" % (TagClassReprs[klass], num)
1619 cols.append(_colourize(col, "blue", with_colours))
1620 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1621 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1623 cols.append(_colourize("BER", "red", with_colours))
1624 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1625 if pp.value is not None:
1627 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1629 len(oid_maps) > 0 and
1630 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1632 for oid_map in oid_maps:
1633 oid_name = oid_map.get(value)
1634 if oid_name is not None:
1635 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1637 if pp.asn1_type_name == Integer.asn1_type_name:
1638 hex_repr = hex(int(pp.obj._value))[2:].upper()
1639 if len(hex_repr) % 2 != 0:
1640 hex_repr = "0" + hex_repr
1641 cols.append(_colourize(
1642 "(%s)" % colonize_hex(hex_repr),
1647 if pp.blob.__class__ == binary_type:
1648 cols.append(hexenc(pp.blob))
1649 elif pp.blob.__class__ == tuple:
1650 cols.append(", ".join(pp.blob))
1652 cols.append(_colourize("OPTIONAL", "red", with_colours))
1654 cols.append(_colourize("DEFAULT", "red", with_colours))
1655 if with_decode_path:
1656 cols.append(_colourize(
1657 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1661 return " ".join(cols)
1664 def pp_console_blob(pp, decode_path_len_decrease=0):
1665 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1666 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1667 if decode_path_len > 0:
1668 cols.append(" ." * (decode_path_len + 1))
1669 if pp.blob.__class__ == binary_type:
1670 blob = hexenc(pp.blob).upper()
1671 for i in six_xrange(0, len(blob), 32):
1672 chunk = blob[i:i + 32]
1673 yield " ".join(cols + [colonize_hex(chunk)])
1674 elif pp.blob.__class__ == tuple:
1675 yield " ".join(cols + [", ".join(pp.blob)])
1683 with_decode_path=False,
1684 decode_path_only=(),
1686 """Pretty print object
1688 :param Obj obj: object you want to pretty print
1689 :param oid_maps: list of ``str(OID) <-> human readable string`` dictionary.
1690 Its human readable form is printed when OID is met
1691 :param big_blobs: if large binary objects are met (like OctetString
1692 values), do we need to print them too, on separate
1694 :param with_colours: colourize output, if ``termcolor`` library
1696 :param with_decode_path: print decode path
1697 :param decode_path_only: print only that specified decode path
1699 def _pprint_pps(pps):
1701 if hasattr(pp, "_fields"):
1703 decode_path_only != () and
1705 str(p) for p in pp.decode_path[:len(decode_path_only)]
1706 ) != decode_path_only
1710 yield pp_console_row(
1715 with_colours=with_colours,
1716 with_decode_path=with_decode_path,
1717 decode_path_len_decrease=len(decode_path_only),
1719 for row in pp_console_blob(
1721 decode_path_len_decrease=len(decode_path_only),
1725 yield pp_console_row(
1730 with_colours=with_colours,
1731 with_decode_path=with_decode_path,
1732 decode_path_len_decrease=len(decode_path_only),
1735 for row in _pprint_pps(pp):
1737 return "\n".join(_pprint_pps(obj.pps()))
1740 ########################################################################
1741 # ASN.1 primitive types
1742 ########################################################################
1744 BooleanState = namedtuple("BooleanState", (
1757 ), **NAMEDTUPLE_KWARGS)
1761 """``BOOLEAN`` boolean type
1763 >>> b = Boolean(True)
1765 >>> b == Boolean(True)
1771 tag_default = tag_encode(1)
1772 asn1_type_name = "BOOLEAN"
1784 :param value: set the value. Either boolean type, or
1785 :py:class:`pyderasn.Boolean` object
1786 :param bytes impl: override default tag with ``IMPLICIT`` one
1787 :param bytes expl: override default tag with ``EXPLICIT`` one
1788 :param default: set default value. Type same as in ``value``
1789 :param bool optional: is object ``OPTIONAL`` in sequence
1791 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1792 self._value = None if value is None else self._value_sanitize(value)
1793 if default is not None:
1794 default = self._value_sanitize(default)
1795 self.default = self.__class__(
1801 self._value = default
1803 def _value_sanitize(self, value):
1804 if value.__class__ == bool:
1806 if issubclass(value.__class__, Boolean):
1808 raise InvalidValueType((self.__class__, bool))
1812 return self._value is not None
1814 def __getstate__(self):
1815 return BooleanState(
1830 def __setstate__(self, state):
1831 super(Boolean, self).__setstate__(state)
1832 self._value = state.value
1833 self.tag = state.tag
1834 self._expl = state.expl
1835 self.default = state.default
1836 self.optional = state.optional
1837 self.offset = state.offset
1838 self.llen = state.llen
1839 self.vlen = state.vlen
1840 self.expl_lenindef = state.expl_lenindef
1841 self.lenindef = state.lenindef
1842 self.ber_encoded = state.ber_encoded
1844 def __nonzero__(self):
1845 self._assert_ready()
1849 self._assert_ready()
1852 def __eq__(self, their):
1853 if their.__class__ == bool:
1854 return self._value == their
1855 if not issubclass(their.__class__, Boolean):
1858 self._value == their._value and
1859 self.tag == their.tag and
1860 self._expl == their._expl
1871 return self.__class__(
1873 impl=self.tag if impl is None else impl,
1874 expl=self._expl if expl is None else expl,
1875 default=self.default if default is None else default,
1876 optional=self.optional if optional is None else optional,
1880 self._assert_ready()
1884 (b"\xFF" if self._value else b"\x00"),
1887 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1889 t, _, lv = tag_strip(tlv)
1890 except DecodeError as err:
1891 raise err.__class__(
1893 klass=self.__class__,
1894 decode_path=decode_path,
1899 klass=self.__class__,
1900 decode_path=decode_path,
1906 l, _, v = len_decode(lv)
1907 except DecodeError as err:
1908 raise err.__class__(
1910 klass=self.__class__,
1911 decode_path=decode_path,
1915 raise InvalidLength(
1916 "Boolean's length must be equal to 1",
1917 klass=self.__class__,
1918 decode_path=decode_path,
1922 raise NotEnoughData(
1923 "encoded length is longer than data",
1924 klass=self.__class__,
1925 decode_path=decode_path,
1928 first_octet = byte2int(v)
1930 if first_octet == 0:
1932 elif first_octet == 0xFF:
1934 elif ctx.get("bered", False):
1939 "unacceptable Boolean value",
1940 klass=self.__class__,
1941 decode_path=decode_path,
1944 obj = self.__class__(
1948 default=self.default,
1949 optional=self.optional,
1950 _decoded=(offset, 1, 1),
1952 obj.ber_encoded = ber_encoded
1956 return pp_console_row(next(self.pps()))
1958 def pps(self, decode_path=()):
1961 asn1_type_name=self.asn1_type_name,
1962 obj_name=self.__class__.__name__,
1963 decode_path=decode_path,
1964 value=str(self._value) if self.ready else None,
1965 optional=self.optional,
1966 default=self == self.default,
1967 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1968 expl=None if self._expl is None else tag_decode(self._expl),
1973 expl_offset=self.expl_offset if self.expled else None,
1974 expl_tlen=self.expl_tlen if self.expled else None,
1975 expl_llen=self.expl_llen if self.expled else None,
1976 expl_vlen=self.expl_vlen if self.expled else None,
1977 expl_lenindef=self.expl_lenindef,
1978 ber_encoded=self.ber_encoded,
1981 for pp in self.pps_lenindef(decode_path):
1985 IntegerState = namedtuple("IntegerState", (
2001 ), **NAMEDTUPLE_KWARGS)
2005 """``INTEGER`` integer type
2007 >>> b = Integer(-123)
2009 >>> b == Integer(-123)
2014 >>> Integer(2, bounds=(1, 3))
2016 >>> Integer(5, bounds=(1, 3))
2017 Traceback (most recent call last):
2018 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2022 class Version(Integer):
2029 >>> v = Version("v1")
2036 {'v3': 2, 'v1': 0, 'v2': 1}
2038 __slots__ = ("specs", "_bound_min", "_bound_max")
2039 tag_default = tag_encode(2)
2040 asn1_type_name = "INTEGER"
2054 :param value: set the value. Either integer type, named value
2055 (if ``schema`` is specified in the class), or
2056 :py:class:`pyderasn.Integer` object
2057 :param bounds: set ``(MIN, MAX)`` value constraint.
2058 (-inf, +inf) by default
2059 :param bytes impl: override default tag with ``IMPLICIT`` one
2060 :param bytes expl: override default tag with ``EXPLICIT`` one
2061 :param default: set default value. Type same as in ``value``
2062 :param bool optional: is object ``OPTIONAL`` in sequence
2064 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2066 specs = getattr(self, "schema", {}) if _specs is None else _specs
2067 self.specs = specs if specs.__class__ == dict else dict(specs)
2068 self._bound_min, self._bound_max = getattr(
2071 (float("-inf"), float("+inf")),
2072 ) if bounds is None else bounds
2073 if value is not None:
2074 self._value = self._value_sanitize(value)
2075 if default is not None:
2076 default = self._value_sanitize(default)
2077 self.default = self.__class__(
2083 if self._value is None:
2084 self._value = default
2086 def _value_sanitize(self, value):
2087 if isinstance(value, integer_types):
2089 elif issubclass(value.__class__, Integer):
2090 value = value._value
2091 elif value.__class__ == str:
2092 value = self.specs.get(value)
2094 raise ObjUnknown("integer value: %s" % value)
2096 raise InvalidValueType((self.__class__, int, str))
2097 if not self._bound_min <= value <= self._bound_max:
2098 raise BoundsError(self._bound_min, value, self._bound_max)
2103 return self._value is not None
2105 def __getstate__(self):
2106 return IntegerState(
2124 def __setstate__(self, state):
2125 super(Integer, self).__setstate__(state)
2126 self.specs = state.specs
2127 self._value = state.value
2128 self._bound_min = state.bound_min
2129 self._bound_max = state.bound_max
2130 self.tag = state.tag
2131 self._expl = state.expl
2132 self.default = state.default
2133 self.optional = state.optional
2134 self.offset = state.offset
2135 self.llen = state.llen
2136 self.vlen = state.vlen
2137 self.expl_lenindef = state.expl_lenindef
2138 self.lenindef = state.lenindef
2139 self.ber_encoded = state.ber_encoded
2142 self._assert_ready()
2143 return int(self._value)
2146 self._assert_ready()
2149 bytes(self._expl or b"") +
2150 str(self._value).encode("ascii"),
2153 def __eq__(self, their):
2154 if isinstance(their, integer_types):
2155 return self._value == their
2156 if not issubclass(their.__class__, Integer):
2159 self._value == their._value and
2160 self.tag == their.tag and
2161 self._expl == their._expl
2164 def __lt__(self, their):
2165 return self._value < their._value
2169 for name, value in iteritems(self.specs):
2170 if value == self._value:
2183 return self.__class__(
2186 (self._bound_min, self._bound_max)
2187 if bounds is None else bounds
2189 impl=self.tag if impl is None else impl,
2190 expl=self._expl if expl is None else expl,
2191 default=self.default if default is None else default,
2192 optional=self.optional if optional is None else optional,
2197 self._assert_ready()
2201 octets = bytearray([0])
2205 octets = bytearray()
2207 octets.append((value & 0xFF) ^ 0xFF)
2209 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2212 octets = bytearray()
2214 octets.append(value & 0xFF)
2216 if octets[-1] & 0x80 > 0:
2219 octets = bytes(octets)
2221 bytes_len = ceil(value.bit_length() / 8) or 1
2224 octets = value.to_bytes(
2229 except OverflowError:
2233 return b"".join((self.tag, len_encode(len(octets)), octets))
2235 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2237 t, _, lv = tag_strip(tlv)
2238 except DecodeError as err:
2239 raise err.__class__(
2241 klass=self.__class__,
2242 decode_path=decode_path,
2247 klass=self.__class__,
2248 decode_path=decode_path,
2254 l, llen, v = len_decode(lv)
2255 except DecodeError as err:
2256 raise err.__class__(
2258 klass=self.__class__,
2259 decode_path=decode_path,
2263 raise NotEnoughData(
2264 "encoded length is longer than data",
2265 klass=self.__class__,
2266 decode_path=decode_path,
2270 raise NotEnoughData(
2272 klass=self.__class__,
2273 decode_path=decode_path,
2276 v, tail = v[:l], v[l:]
2277 first_octet = byte2int(v)
2279 second_octet = byte2int(v[1:])
2281 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2282 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2285 "non normalized integer",
2286 klass=self.__class__,
2287 decode_path=decode_path,
2292 if first_octet & 0x80 > 0:
2293 octets = bytearray()
2294 for octet in bytearray(v):
2295 octets.append(octet ^ 0xFF)
2296 for octet in octets:
2297 value = (value << 8) | octet
2301 for octet in bytearray(v):
2302 value = (value << 8) | octet
2304 value = int.from_bytes(v, byteorder="big", signed=True)
2306 obj = self.__class__(
2308 bounds=(self._bound_min, self._bound_max),
2311 default=self.default,
2312 optional=self.optional,
2314 _decoded=(offset, llen, l),
2316 except BoundsError as err:
2319 klass=self.__class__,
2320 decode_path=decode_path,
2326 return pp_console_row(next(self.pps()))
2328 def pps(self, decode_path=()):
2331 asn1_type_name=self.asn1_type_name,
2332 obj_name=self.__class__.__name__,
2333 decode_path=decode_path,
2334 value=(self.named or str(self._value)) if self.ready else None,
2335 optional=self.optional,
2336 default=self == self.default,
2337 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2338 expl=None if self._expl is None else tag_decode(self._expl),
2343 expl_offset=self.expl_offset if self.expled else None,
2344 expl_tlen=self.expl_tlen if self.expled else None,
2345 expl_llen=self.expl_llen if self.expled else None,
2346 expl_vlen=self.expl_vlen if self.expled else None,
2347 expl_lenindef=self.expl_lenindef,
2350 for pp in self.pps_lenindef(decode_path):
2354 BitStringState = namedtuple("BitStringState", (
2370 ), **NAMEDTUPLE_KWARGS)
2373 class BitString(Obj):
2374 """``BIT STRING`` bit string type
2376 >>> BitString(b"hello world")
2377 BIT STRING 88 bits 68656c6c6f20776f726c64
2380 >>> b == b"hello world"
2385 >>> BitString("'0A3B5F291CD'H")
2386 BIT STRING 44 bits 0a3b5f291cd0
2387 >>> b = BitString("'010110000000'B")
2388 BIT STRING 12 bits 5800
2391 >>> b[0], b[1], b[2], b[3]
2392 (False, True, False, True)
2396 [False, True, False, True, True, False, False, False, False, False, False, False]
2400 class KeyUsage(BitString):
2402 ("digitalSignature", 0),
2403 ("nonRepudiation", 1),
2404 ("keyEncipherment", 2),
2407 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2408 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2410 ['nonRepudiation', 'keyEncipherment']
2412 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2416 Pay attention that BIT STRING can be encoded both in primitive
2417 and constructed forms. Decoder always checks constructed form tag
2418 additionally to specified primitive one. If BER decoding is
2419 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2420 of DER restrictions.
2422 __slots__ = ("tag_constructed", "specs", "defined")
2423 tag_default = tag_encode(3)
2424 asn1_type_name = "BIT STRING"
2437 :param value: set the value. Either binary type, tuple of named
2438 values (if ``schema`` is specified in the class),
2439 string in ``'XXX...'B`` form, or
2440 :py:class:`pyderasn.BitString` object
2441 :param bytes impl: override default tag with ``IMPLICIT`` one
2442 :param bytes expl: override default tag with ``EXPLICIT`` one
2443 :param default: set default value. Type same as in ``value``
2444 :param bool optional: is object ``OPTIONAL`` in sequence
2446 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2447 specs = getattr(self, "schema", {}) if _specs is None else _specs
2448 self.specs = specs if specs.__class__ == dict else dict(specs)
2449 self._value = None if value is None else self._value_sanitize(value)
2450 if default is not None:
2451 default = self._value_sanitize(default)
2452 self.default = self.__class__(
2458 self._value = default
2460 tag_klass, _, tag_num = tag_decode(self.tag)
2461 self.tag_constructed = tag_encode(
2463 form=TagFormConstructed,
2467 def _bits2octets(self, bits):
2468 if len(self.specs) > 0:
2469 bits = bits.rstrip("0")
2471 bits += "0" * ((8 - (bit_len % 8)) % 8)
2472 octets = bytearray(len(bits) // 8)
2473 for i in six_xrange(len(octets)):
2474 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2475 return bit_len, bytes(octets)
2477 def _value_sanitize(self, value):
2478 if isinstance(value, (string_types, binary_type)):
2480 isinstance(value, string_types) and
2481 value.startswith("'")
2483 if value.endswith("'B"):
2485 if not frozenset(value) <= SET01:
2486 raise ValueError("B's coding contains unacceptable chars")
2487 return self._bits2octets(value)
2488 if value.endswith("'H"):
2492 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2494 if value.__class__ == binary_type:
2495 return (len(value) * 8, value)
2496 raise InvalidValueType((self.__class__, string_types, binary_type))
2497 if value.__class__ == tuple:
2500 isinstance(value[0], integer_types) and
2501 value[1].__class__ == binary_type
2506 bit = self.specs.get(name)
2508 raise ObjUnknown("BitString value: %s" % name)
2511 return self._bits2octets("")
2512 bits = frozenset(bits)
2513 return self._bits2octets("".join(
2514 ("1" if bit in bits else "0")
2515 for bit in six_xrange(max(bits) + 1)
2517 if issubclass(value.__class__, BitString):
2519 raise InvalidValueType((self.__class__, binary_type, string_types))
2523 return self._value is not None
2525 def __getstate__(self):
2526 return BitStringState(
2540 self.tag_constructed,
2544 def __setstate__(self, state):
2545 super(BitString, self).__setstate__(state)
2546 self.specs = state.specs
2547 self._value = state.value
2548 self.tag = state.tag
2549 self._expl = state.expl
2550 self.default = state.default
2551 self.optional = state.optional
2552 self.offset = state.offset
2553 self.llen = state.llen
2554 self.vlen = state.vlen
2555 self.expl_lenindef = state.expl_lenindef
2556 self.lenindef = state.lenindef
2557 self.ber_encoded = state.ber_encoded
2558 self.tag_constructed = state.tag_constructed
2559 self.defined = state.defined
2562 self._assert_ready()
2563 for i in six_xrange(self._value[0]):
2568 self._assert_ready()
2569 return self._value[0]
2571 def __bytes__(self):
2572 self._assert_ready()
2573 return self._value[1]
2575 def __eq__(self, their):
2576 if their.__class__ == bytes:
2577 return self._value[1] == their
2578 if not issubclass(their.__class__, BitString):
2581 self._value == their._value and
2582 self.tag == their.tag and
2583 self._expl == their._expl
2588 return [name for name, bit in iteritems(self.specs) if self[bit]]
2598 return self.__class__(
2600 impl=self.tag if impl is None else impl,
2601 expl=self._expl if expl is None else expl,
2602 default=self.default if default is None else default,
2603 optional=self.optional if optional is None else optional,
2607 def __getitem__(self, key):
2608 if key.__class__ == int:
2609 bit_len, octets = self._value
2613 byte2int(memoryview(octets)[key // 8:]) >>
2616 if isinstance(key, string_types):
2617 value = self.specs.get(key)
2619 raise ObjUnknown("BitString value: %s" % key)
2621 raise InvalidValueType((int, str))
2624 self._assert_ready()
2625 bit_len, octets = self._value
2628 len_encode(len(octets) + 1),
2629 int2byte((8 - bit_len % 8) % 8),
2633 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2635 t, tlen, lv = tag_strip(tlv)
2636 except DecodeError as err:
2637 raise err.__class__(
2639 klass=self.__class__,
2640 decode_path=decode_path,
2644 if tag_only: # pragma: no cover
2647 l, llen, v = len_decode(lv)
2648 except DecodeError as err:
2649 raise err.__class__(
2651 klass=self.__class__,
2652 decode_path=decode_path,
2656 raise NotEnoughData(
2657 "encoded length is longer than data",
2658 klass=self.__class__,
2659 decode_path=decode_path,
2663 raise NotEnoughData(
2665 klass=self.__class__,
2666 decode_path=decode_path,
2669 pad_size = byte2int(v)
2670 if l == 1 and pad_size != 0:
2672 "invalid empty value",
2673 klass=self.__class__,
2674 decode_path=decode_path,
2680 klass=self.__class__,
2681 decode_path=decode_path,
2684 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2687 klass=self.__class__,
2688 decode_path=decode_path,
2691 v, tail = v[:l], v[l:]
2692 obj = self.__class__(
2693 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2696 default=self.default,
2697 optional=self.optional,
2699 _decoded=(offset, llen, l),
2702 if t != self.tag_constructed:
2704 klass=self.__class__,
2705 decode_path=decode_path,
2708 if not ctx.get("bered", False):
2710 "unallowed BER constructed encoding",
2711 klass=self.__class__,
2712 decode_path=decode_path,
2715 if tag_only: # pragma: no cover
2719 l, llen, v = len_decode(lv)
2720 except LenIndefForm:
2721 llen, l, v = 1, 0, lv[1:]
2723 except DecodeError as err:
2724 raise err.__class__(
2726 klass=self.__class__,
2727 decode_path=decode_path,
2731 raise NotEnoughData(
2732 "encoded length is longer than data",
2733 klass=self.__class__,
2734 decode_path=decode_path,
2737 if not lenindef and l == 0:
2738 raise NotEnoughData(
2740 klass=self.__class__,
2741 decode_path=decode_path,
2745 sub_offset = offset + tlen + llen
2749 if v[:EOC_LEN].tobytes() == EOC:
2756 "chunk out of bounds",
2757 klass=self.__class__,
2758 decode_path=decode_path + (str(len(chunks) - 1),),
2759 offset=chunks[-1].offset,
2761 sub_decode_path = decode_path + (str(len(chunks)),)
2763 chunk, v_tail = BitString().decode(
2766 decode_path=sub_decode_path,
2769 _ctx_immutable=False,
2773 "expected BitString encoded chunk",
2774 klass=self.__class__,
2775 decode_path=sub_decode_path,
2778 chunks.append(chunk)
2779 sub_offset += chunk.tlvlen
2780 vlen += chunk.tlvlen
2782 if len(chunks) == 0:
2785 klass=self.__class__,
2786 decode_path=decode_path,
2791 for chunk_i, chunk in enumerate(chunks[:-1]):
2792 if chunk.bit_len % 8 != 0:
2794 "BitString chunk is not multiple of 8 bits",
2795 klass=self.__class__,
2796 decode_path=decode_path + (str(chunk_i),),
2797 offset=chunk.offset,
2799 values.append(bytes(chunk))
2800 bit_len += chunk.bit_len
2801 chunk_last = chunks[-1]
2802 values.append(bytes(chunk_last))
2803 bit_len += chunk_last.bit_len
2804 obj = self.__class__(
2805 value=(bit_len, b"".join(values)),
2808 default=self.default,
2809 optional=self.optional,
2811 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2813 obj.lenindef = lenindef
2814 obj.ber_encoded = True
2815 return obj, (v[EOC_LEN:] if lenindef else v)
2818 return pp_console_row(next(self.pps()))
2820 def pps(self, decode_path=()):
2824 bit_len, blob = self._value
2825 value = "%d bits" % bit_len
2826 if len(self.specs) > 0:
2827 blob = tuple(self.named)
2830 asn1_type_name=self.asn1_type_name,
2831 obj_name=self.__class__.__name__,
2832 decode_path=decode_path,
2835 optional=self.optional,
2836 default=self == self.default,
2837 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2838 expl=None if self._expl is None else tag_decode(self._expl),
2843 expl_offset=self.expl_offset if self.expled else None,
2844 expl_tlen=self.expl_tlen if self.expled else None,
2845 expl_llen=self.expl_llen if self.expled else None,
2846 expl_vlen=self.expl_vlen if self.expled else None,
2847 expl_lenindef=self.expl_lenindef,
2848 lenindef=self.lenindef,
2849 ber_encoded=self.ber_encoded,
2852 defined_by, defined = self.defined or (None, None)
2853 if defined_by is not None:
2855 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2857 for pp in self.pps_lenindef(decode_path):
2861 OctetStringState = namedtuple("OctetStringState", (
2878 ), **NAMEDTUPLE_KWARGS)
2881 class OctetString(Obj):
2882 """``OCTET STRING`` binary string type
2884 >>> s = OctetString(b"hello world")
2885 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2886 >>> s == OctetString(b"hello world")
2891 >>> OctetString(b"hello", bounds=(4, 4))
2892 Traceback (most recent call last):
2893 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2894 >>> OctetString(b"hell", bounds=(4, 4))
2895 OCTET STRING 4 bytes 68656c6c
2899 Pay attention that OCTET STRING can be encoded both in primitive
2900 and constructed forms. Decoder always checks constructed form tag
2901 additionally to specified primitive one. If BER decoding is
2902 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2903 of DER restrictions.
2905 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2906 tag_default = tag_encode(4)
2907 asn1_type_name = "OCTET STRING"
2921 :param value: set the value. Either binary type, or
2922 :py:class:`pyderasn.OctetString` object
2923 :param bounds: set ``(MIN, MAX)`` value size constraint.
2924 (-inf, +inf) by default
2925 :param bytes impl: override default tag with ``IMPLICIT`` one
2926 :param bytes expl: override default tag with ``EXPLICIT`` one
2927 :param default: set default value. Type same as in ``value``
2928 :param bool optional: is object ``OPTIONAL`` in sequence
2930 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2932 self._bound_min, self._bound_max = getattr(
2936 ) if bounds is None else bounds
2937 if value is not None:
2938 self._value = self._value_sanitize(value)
2939 if default is not None:
2940 default = self._value_sanitize(default)
2941 self.default = self.__class__(
2946 if self._value is None:
2947 self._value = default
2949 tag_klass, _, tag_num = tag_decode(self.tag)
2950 self.tag_constructed = tag_encode(
2952 form=TagFormConstructed,
2956 def _value_sanitize(self, value):
2957 if value.__class__ == binary_type:
2959 elif issubclass(value.__class__, OctetString):
2960 value = value._value
2962 raise InvalidValueType((self.__class__, bytes))
2963 if not self._bound_min <= len(value) <= self._bound_max:
2964 raise BoundsError(self._bound_min, len(value), self._bound_max)
2969 return self._value is not None
2971 def __getstate__(self):
2972 return OctetStringState(
2987 self.tag_constructed,
2991 def __setstate__(self, state):
2992 super(OctetString, self).__setstate__(state)
2993 self._value = state.value
2994 self._bound_min = state.bound_min
2995 self._bound_max = state.bound_max
2996 self.tag = state.tag
2997 self._expl = state.expl
2998 self.default = state.default
2999 self.optional = state.optional
3000 self.offset = state.offset
3001 self.llen = state.llen
3002 self.vlen = state.vlen
3003 self.expl_lenindef = state.expl_lenindef
3004 self.lenindef = state.lenindef
3005 self.ber_encoded = state.ber_encoded
3006 self.tag_constructed = state.tag_constructed
3007 self.defined = state.defined
3009 def __bytes__(self):
3010 self._assert_ready()
3013 def __eq__(self, their):
3014 if their.__class__ == binary_type:
3015 return self._value == their
3016 if not issubclass(their.__class__, OctetString):
3019 self._value == their._value and
3020 self.tag == their.tag and
3021 self._expl == their._expl
3024 def __lt__(self, their):
3025 return self._value < their._value
3036 return self.__class__(
3039 (self._bound_min, self._bound_max)
3040 if bounds is None else bounds
3042 impl=self.tag if impl is None else impl,
3043 expl=self._expl if expl is None else expl,
3044 default=self.default if default is None else default,
3045 optional=self.optional if optional is None else optional,
3049 self._assert_ready()
3052 len_encode(len(self._value)),
3056 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3058 t, tlen, lv = tag_strip(tlv)
3059 except DecodeError as err:
3060 raise err.__class__(
3062 klass=self.__class__,
3063 decode_path=decode_path,
3070 l, llen, v = len_decode(lv)
3071 except DecodeError as err:
3072 raise err.__class__(
3074 klass=self.__class__,
3075 decode_path=decode_path,
3079 raise NotEnoughData(
3080 "encoded length is longer than data",
3081 klass=self.__class__,
3082 decode_path=decode_path,
3085 v, tail = v[:l], v[l:]
3087 obj = self.__class__(
3089 bounds=(self._bound_min, self._bound_max),
3092 default=self.default,
3093 optional=self.optional,
3094 _decoded=(offset, llen, l),
3097 except DecodeError as err:
3100 klass=self.__class__,
3101 decode_path=decode_path,
3104 except BoundsError as err:
3107 klass=self.__class__,
3108 decode_path=decode_path,
3112 if t != self.tag_constructed:
3114 klass=self.__class__,
3115 decode_path=decode_path,
3118 if not ctx.get("bered", False):
3120 "unallowed BER constructed encoding",
3121 klass=self.__class__,
3122 decode_path=decode_path,
3129 l, llen, v = len_decode(lv)
3130 except LenIndefForm:
3131 llen, l, v = 1, 0, lv[1:]
3133 except DecodeError as err:
3134 raise err.__class__(
3136 klass=self.__class__,
3137 decode_path=decode_path,
3141 raise NotEnoughData(
3142 "encoded length is longer than data",
3143 klass=self.__class__,
3144 decode_path=decode_path,
3148 sub_offset = offset + tlen + llen
3152 if v[:EOC_LEN].tobytes() == EOC:
3159 "chunk out of bounds",
3160 klass=self.__class__,
3161 decode_path=decode_path + (str(len(chunks) - 1),),
3162 offset=chunks[-1].offset,
3164 sub_decode_path = decode_path + (str(len(chunks)),)
3166 chunk, v_tail = OctetString().decode(
3169 decode_path=sub_decode_path,
3172 _ctx_immutable=False,
3176 "expected OctetString encoded chunk",
3177 klass=self.__class__,
3178 decode_path=sub_decode_path,
3181 chunks.append(chunk)
3182 sub_offset += chunk.tlvlen
3183 vlen += chunk.tlvlen
3186 obj = self.__class__(
3187 value=b"".join(bytes(chunk) for chunk in chunks),
3188 bounds=(self._bound_min, self._bound_max),
3191 default=self.default,
3192 optional=self.optional,
3193 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3196 except DecodeError as err:
3199 klass=self.__class__,
3200 decode_path=decode_path,
3203 except BoundsError as err:
3206 klass=self.__class__,
3207 decode_path=decode_path,
3210 obj.lenindef = lenindef
3211 obj.ber_encoded = True
3212 return obj, (v[EOC_LEN:] if lenindef else v)
3215 return pp_console_row(next(self.pps()))
3217 def pps(self, decode_path=()):
3220 asn1_type_name=self.asn1_type_name,
3221 obj_name=self.__class__.__name__,
3222 decode_path=decode_path,
3223 value=("%d bytes" % len(self._value)) if self.ready else None,
3224 blob=self._value if self.ready else None,
3225 optional=self.optional,
3226 default=self == self.default,
3227 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3228 expl=None if self._expl is None else tag_decode(self._expl),
3233 expl_offset=self.expl_offset if self.expled else None,
3234 expl_tlen=self.expl_tlen if self.expled else None,
3235 expl_llen=self.expl_llen if self.expled else None,
3236 expl_vlen=self.expl_vlen if self.expled else None,
3237 expl_lenindef=self.expl_lenindef,
3238 lenindef=self.lenindef,
3239 ber_encoded=self.ber_encoded,
3242 defined_by, defined = self.defined or (None, None)
3243 if defined_by is not None:
3245 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3247 for pp in self.pps_lenindef(decode_path):
3251 NullState = namedtuple("NullState", (
3263 ), **NAMEDTUPLE_KWARGS)
3267 """``NULL`` null object
3275 tag_default = tag_encode(5)
3276 asn1_type_name = "NULL"
3280 value=None, # unused, but Sequence passes it
3287 :param bytes impl: override default tag with ``IMPLICIT`` one
3288 :param bytes expl: override default tag with ``EXPLICIT`` one
3289 :param bool optional: is object ``OPTIONAL`` in sequence
3291 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3298 def __getstate__(self):
3313 def __setstate__(self, state):
3314 super(Null, self).__setstate__(state)
3315 self.tag = state.tag
3316 self._expl = state.expl
3317 self.default = state.default
3318 self.optional = state.optional
3319 self.offset = state.offset
3320 self.llen = state.llen
3321 self.vlen = state.vlen
3322 self.expl_lenindef = state.expl_lenindef
3323 self.lenindef = state.lenindef
3324 self.ber_encoded = state.ber_encoded
3326 def __eq__(self, their):
3327 if not issubclass(their.__class__, Null):
3330 self.tag == their.tag and
3331 self._expl == their._expl
3341 return self.__class__(
3342 impl=self.tag if impl is None else impl,
3343 expl=self._expl if expl is None else expl,
3344 optional=self.optional if optional is None else optional,
3348 return self.tag + len_encode(0)
3350 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3352 t, _, lv = tag_strip(tlv)
3353 except DecodeError as err:
3354 raise err.__class__(
3356 klass=self.__class__,
3357 decode_path=decode_path,
3362 klass=self.__class__,
3363 decode_path=decode_path,
3366 if tag_only: # pragma: no cover
3369 l, _, v = len_decode(lv)
3370 except DecodeError as err:
3371 raise err.__class__(
3373 klass=self.__class__,
3374 decode_path=decode_path,
3378 raise InvalidLength(
3379 "Null must have zero length",
3380 klass=self.__class__,
3381 decode_path=decode_path,
3384 obj = self.__class__(
3387 optional=self.optional,
3388 _decoded=(offset, 1, 0),
3393 return pp_console_row(next(self.pps()))
3395 def pps(self, decode_path=()):
3398 asn1_type_name=self.asn1_type_name,
3399 obj_name=self.__class__.__name__,
3400 decode_path=decode_path,
3401 optional=self.optional,
3402 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3403 expl=None if self._expl is None else tag_decode(self._expl),
3408 expl_offset=self.expl_offset if self.expled else None,
3409 expl_tlen=self.expl_tlen if self.expled else None,
3410 expl_llen=self.expl_llen if self.expled else None,
3411 expl_vlen=self.expl_vlen if self.expled else None,
3412 expl_lenindef=self.expl_lenindef,
3415 for pp in self.pps_lenindef(decode_path):
3419 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3433 ), **NAMEDTUPLE_KWARGS)
3436 class ObjectIdentifier(Obj):
3437 """``OBJECT IDENTIFIER`` OID type
3439 >>> oid = ObjectIdentifier((1, 2, 3))
3440 OBJECT IDENTIFIER 1.2.3
3441 >>> oid == ObjectIdentifier("1.2.3")
3447 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3448 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3450 >>> str(ObjectIdentifier((3, 1)))
3451 Traceback (most recent call last):
3452 pyderasn.InvalidOID: unacceptable first arc value
3454 __slots__ = ("defines",)
3455 tag_default = tag_encode(6)
3456 asn1_type_name = "OBJECT IDENTIFIER"
3469 :param value: set the value. Either tuples of integers,
3470 string of "."-concatenated integers, or
3471 :py:class:`pyderasn.ObjectIdentifier` object
3472 :param defines: sequence of tuples. Each tuple has two elements.
3473 First one is relative to current one decode
3474 path, aiming to the field defined by that OID.
3475 Read about relative path in
3476 :py:func:`pyderasn.abs_decode_path`. Second
3477 tuple element is ``{OID: pyderasn.Obj()}``
3478 dictionary, mapping between current OID value
3479 and structure applied to defined field.
3480 :ref:`Read about DEFINED BY <definedby>`
3481 :param bytes impl: override default tag with ``IMPLICIT`` one
3482 :param bytes expl: override default tag with ``EXPLICIT`` one
3483 :param default: set default value. Type same as in ``value``
3484 :param bool optional: is object ``OPTIONAL`` in sequence
3486 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3488 if value is not None:
3489 self._value = self._value_sanitize(value)
3490 if default is not None:
3491 default = self._value_sanitize(default)
3492 self.default = self.__class__(
3497 if self._value is None:
3498 self._value = default
3499 self.defines = defines
3501 def __add__(self, their):
3502 if their.__class__ == tuple:
3503 return self.__class__(self._value + their)
3504 if isinstance(their, self.__class__):
3505 return self.__class__(self._value + their._value)
3506 raise InvalidValueType((self.__class__, tuple))
3508 def _value_sanitize(self, value):
3509 if issubclass(value.__class__, ObjectIdentifier):
3511 if isinstance(value, string_types):
3513 value = tuple(pureint(arc) for arc in value.split("."))
3515 raise InvalidOID("unacceptable arcs values")
3516 if value.__class__ == tuple:
3518 raise InvalidOID("less than 2 arcs")
3519 first_arc = value[0]
3520 if first_arc in (0, 1):
3521 if not (0 <= value[1] <= 39):
3522 raise InvalidOID("second arc is too wide")
3523 elif first_arc == 2:
3526 raise InvalidOID("unacceptable first arc value")
3527 if not all(arc >= 0 for arc in value):
3528 raise InvalidOID("negative arc value")
3530 raise InvalidValueType((self.__class__, str, tuple))
3534 return self._value is not None
3536 def __getstate__(self):
3537 return ObjectIdentifierState(
3553 def __setstate__(self, state):
3554 super(ObjectIdentifier, self).__setstate__(state)
3555 self._value = state.value
3556 self.tag = state.tag
3557 self._expl = state.expl
3558 self.default = state.default
3559 self.optional = state.optional
3560 self.offset = state.offset
3561 self.llen = state.llen
3562 self.vlen = state.vlen
3563 self.expl_lenindef = state.expl_lenindef
3564 self.lenindef = state.lenindef
3565 self.ber_encoded = state.ber_encoded
3566 self.defines = state.defines
3569 self._assert_ready()
3570 return iter(self._value)
3573 return ".".join(str(arc) for arc in self._value or ())
3576 self._assert_ready()
3579 bytes(self._expl or b"") +
3580 str(self._value).encode("ascii"),
3583 def __eq__(self, their):
3584 if their.__class__ == tuple:
3585 return self._value == their
3586 if not issubclass(their.__class__, ObjectIdentifier):
3589 self.tag == their.tag and
3590 self._expl == their._expl and
3591 self._value == their._value
3594 def __lt__(self, their):
3595 return self._value < their._value
3606 return self.__class__(
3608 defines=self.defines if defines is None else defines,
3609 impl=self.tag if impl is None else impl,
3610 expl=self._expl if expl is None else expl,
3611 default=self.default if default is None else default,
3612 optional=self.optional if optional is None else optional,
3616 self._assert_ready()
3618 first_value = value[1]
3619 first_arc = value[0]
3622 elif first_arc == 1:
3624 elif first_arc == 2:
3626 else: # pragma: no cover
3627 raise RuntimeError("invalid arc is stored")
3628 octets = [zero_ended_encode(first_value)]
3629 for arc in value[2:]:
3630 octets.append(zero_ended_encode(arc))
3631 v = b"".join(octets)
3632 return b"".join((self.tag, len_encode(len(v)), v))
3634 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3636 t, _, lv = tag_strip(tlv)
3637 except DecodeError as err:
3638 raise err.__class__(
3640 klass=self.__class__,
3641 decode_path=decode_path,
3646 klass=self.__class__,
3647 decode_path=decode_path,
3650 if tag_only: # pragma: no cover
3653 l, llen, v = len_decode(lv)
3654 except DecodeError as err:
3655 raise err.__class__(
3657 klass=self.__class__,
3658 decode_path=decode_path,
3662 raise NotEnoughData(
3663 "encoded length is longer than data",
3664 klass=self.__class__,
3665 decode_path=decode_path,
3669 raise NotEnoughData(
3671 klass=self.__class__,
3672 decode_path=decode_path,
3675 v, tail = v[:l], v[l:]
3682 octet = indexbytes(v, i)
3683 if i == 0 and octet == 0x80:
3684 if ctx.get("bered", False):
3687 raise DecodeError("non normalized arc encoding")
3688 arc = (arc << 7) | (octet & 0x7F)
3689 if octet & 0x80 == 0:
3697 klass=self.__class__,
3698 decode_path=decode_path,
3702 second_arc = arcs[0]
3703 if 0 <= second_arc <= 39:
3705 elif 40 <= second_arc <= 79:
3711 obj = self.__class__(
3712 value=tuple([first_arc, second_arc] + arcs[1:]),
3715 default=self.default,
3716 optional=self.optional,
3717 _decoded=(offset, llen, l),
3720 obj.ber_encoded = True
3724 return pp_console_row(next(self.pps()))
3726 def pps(self, decode_path=()):
3729 asn1_type_name=self.asn1_type_name,
3730 obj_name=self.__class__.__name__,
3731 decode_path=decode_path,
3732 value=str(self) if self.ready else None,
3733 optional=self.optional,
3734 default=self == self.default,
3735 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3736 expl=None if self._expl is None else tag_decode(self._expl),
3741 expl_offset=self.expl_offset if self.expled else None,
3742 expl_tlen=self.expl_tlen if self.expled else None,
3743 expl_llen=self.expl_llen if self.expled else None,
3744 expl_vlen=self.expl_vlen if self.expled else None,
3745 expl_lenindef=self.expl_lenindef,
3746 ber_encoded=self.ber_encoded,
3749 for pp in self.pps_lenindef(decode_path):
3753 class Enumerated(Integer):
3754 """``ENUMERATED`` integer type
3756 This type is identical to :py:class:`pyderasn.Integer`, but requires
3757 schema to be specified and does not accept values missing from it.
3760 tag_default = tag_encode(10)
3761 asn1_type_name = "ENUMERATED"
3772 bounds=None, # dummy argument, workability for Integer.decode
3774 super(Enumerated, self).__init__(
3775 value, bounds, impl, expl, default, optional, _specs, _decoded,
3777 if len(self.specs) == 0:
3778 raise ValueError("schema must be specified")
3780 def _value_sanitize(self, value):
3781 if isinstance(value, self.__class__):
3782 value = value._value
3783 elif isinstance(value, integer_types):
3784 for _value in itervalues(self.specs):
3789 "unknown integer value: %s" % value,
3790 klass=self.__class__,
3792 elif isinstance(value, string_types):
3793 value = self.specs.get(value)
3795 raise ObjUnknown("integer value: %s" % value)
3797 raise InvalidValueType((self.__class__, int, str))
3809 return self.__class__(
3811 impl=self.tag if impl is None else impl,
3812 expl=self._expl if expl is None else expl,
3813 default=self.default if default is None else default,
3814 optional=self.optional if optional is None else optional,
3819 def escape_control_unicode(c):
3820 if unicat(c)[0] == "C":
3821 c = repr(c).lstrip("u").strip("'")
3825 class CommonString(OctetString):
3826 """Common class for all strings
3828 Everything resembles :py:class:`pyderasn.OctetString`, except
3829 ability to deal with unicode text strings.
3831 >>> hexenc("привет мир".encode("utf-8"))
3832 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3833 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3835 >>> s = UTF8String("привет мир")
3836 UTF8String UTF8String привет мир
3838 'привет мир'
3839 >>> hexenc(bytes(s))
3840 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3842 >>> PrintableString("привет мир")
3843 Traceback (most recent call last):
3844 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3846 >>> BMPString("ада", bounds=(2, 2))
3847 Traceback (most recent call last):
3848 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3849 >>> s = BMPString("ад", bounds=(2, 2))
3852 >>> hexenc(bytes(s))
3860 * - :py:class:`pyderasn.UTF8String`
3862 * - :py:class:`pyderasn.NumericString`
3864 * - :py:class:`pyderasn.PrintableString`
3866 * - :py:class:`pyderasn.TeletexString`
3868 * - :py:class:`pyderasn.T61String`
3870 * - :py:class:`pyderasn.VideotexString`
3872 * - :py:class:`pyderasn.IA5String`
3874 * - :py:class:`pyderasn.GraphicString`
3876 * - :py:class:`pyderasn.VisibleString`
3878 * - :py:class:`pyderasn.ISO646String`
3880 * - :py:class:`pyderasn.GeneralString`
3882 * - :py:class:`pyderasn.UniversalString`
3884 * - :py:class:`pyderasn.BMPString`
3889 def _value_sanitize(self, value):
3891 value_decoded = None
3892 if isinstance(value, self.__class__):
3893 value_raw = value._value
3894 elif value.__class__ == text_type:
3895 value_decoded = value
3896 elif value.__class__ == binary_type:
3899 raise InvalidValueType((self.__class__, text_type, binary_type))
3902 value_decoded.encode(self.encoding)
3903 if value_raw is None else value_raw
3906 value_raw.decode(self.encoding)
3907 if value_decoded is None else value_decoded
3909 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3910 raise DecodeError(str(err))
3911 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3919 def __eq__(self, their):
3920 if their.__class__ == binary_type:
3921 return self._value == their
3922 if their.__class__ == text_type:
3923 return self._value == their.encode(self.encoding)
3924 if not isinstance(their, self.__class__):
3927 self._value == their._value and
3928 self.tag == their.tag and
3929 self._expl == their._expl
3932 def __unicode__(self):
3934 return self._value.decode(self.encoding)
3935 return text_type(self._value)
3938 return pp_console_row(next(self.pps(no_unicode=PY2)))
3940 def pps(self, decode_path=(), no_unicode=False):
3944 hexenc(bytes(self)) if no_unicode else
3945 "".join(escape_control_unicode(c) for c in self.__unicode__())
3949 asn1_type_name=self.asn1_type_name,
3950 obj_name=self.__class__.__name__,
3951 decode_path=decode_path,
3953 optional=self.optional,
3954 default=self == self.default,
3955 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3956 expl=None if self._expl is None else tag_decode(self._expl),
3961 expl_offset=self.expl_offset if self.expled else None,
3962 expl_tlen=self.expl_tlen if self.expled else None,
3963 expl_llen=self.expl_llen if self.expled else None,
3964 expl_vlen=self.expl_vlen if self.expled else None,
3965 expl_lenindef=self.expl_lenindef,
3966 ber_encoded=self.ber_encoded,
3969 for pp in self.pps_lenindef(decode_path):
3973 class UTF8String(CommonString):
3975 tag_default = tag_encode(12)
3977 asn1_type_name = "UTF8String"
3980 class AllowableCharsMixin(object):
3982 def allowable_chars(self):
3984 return self._allowable_chars
3985 return frozenset(six_unichr(c) for c in self._allowable_chars)
3988 class NumericString(AllowableCharsMixin, CommonString):
3991 Its value is properly sanitized: only ASCII digits with spaces can
3994 >>> NumericString().allowable_chars
3995 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3998 tag_default = tag_encode(18)
4000 asn1_type_name = "NumericString"
4001 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
4003 def _value_sanitize(self, value):
4004 value = super(NumericString, self)._value_sanitize(value)
4005 if not frozenset(value) <= self._allowable_chars:
4006 raise DecodeError("non-numeric value")
4010 PrintableStringState = namedtuple(
4011 "PrintableStringState",
4012 OctetStringState._fields + ("allowable_chars",),
4017 class PrintableString(AllowableCharsMixin, CommonString):
4020 Its value is properly sanitized: see X.680 41.4 table 10.
4022 >>> PrintableString().allowable_chars
4023 frozenset([' ', "'", ..., 'z'])
4024 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4025 PrintableString PrintableString foo*bar
4026 >>> obj.allow_asterisk, obj.allow_ampersand
4030 tag_default = tag_encode(19)
4032 asn1_type_name = "PrintableString"
4033 _allowable_chars = frozenset(
4034 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4036 _asterisk = frozenset("*".encode("ascii"))
4037 _ampersand = frozenset("&".encode("ascii"))
4049 allow_asterisk=False,
4050 allow_ampersand=False,
4053 :param allow_asterisk: allow asterisk character
4054 :param allow_ampersand: allow ampersand character
4057 self._allowable_chars |= self._asterisk
4059 self._allowable_chars |= self._ampersand
4060 super(PrintableString, self).__init__(
4061 value, bounds, impl, expl, default, optional, _decoded, ctx,
4065 def allow_asterisk(self):
4066 """Is asterisk character allowed?
4068 return self._asterisk <= self._allowable_chars
4071 def allow_ampersand(self):
4072 """Is ampersand character allowed?
4074 return self._ampersand <= self._allowable_chars
4076 def _value_sanitize(self, value):
4077 value = super(PrintableString, self)._value_sanitize(value)
4078 if not frozenset(value) <= self._allowable_chars:
4079 raise DecodeError("non-printable value")
4082 def __getstate__(self):
4083 return PrintableStringState(
4084 *super(PrintableString, self).__getstate__(),
4085 **{"allowable_chars": self._allowable_chars}
4088 def __setstate__(self, state):
4089 super(PrintableString, self).__setstate__(state)
4090 self._allowable_chars = state.allowable_chars
4101 return self.__class__(
4104 (self._bound_min, self._bound_max)
4105 if bounds is None else bounds
4107 impl=self.tag if impl is None else impl,
4108 expl=self._expl if expl is None else expl,
4109 default=self.default if default is None else default,
4110 optional=self.optional if optional is None else optional,
4111 allow_asterisk=self.allow_asterisk,
4112 allow_ampersand=self.allow_ampersand,
4116 class TeletexString(CommonString):
4118 tag_default = tag_encode(20)
4120 asn1_type_name = "TeletexString"
4123 class T61String(TeletexString):
4125 asn1_type_name = "T61String"
4128 class VideotexString(CommonString):
4130 tag_default = tag_encode(21)
4131 encoding = "iso-8859-1"
4132 asn1_type_name = "VideotexString"
4135 class IA5String(CommonString):
4137 tag_default = tag_encode(22)
4139 asn1_type_name = "IA5"
4142 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4143 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4144 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4147 class VisibleString(CommonString):
4149 tag_default = tag_encode(26)
4151 asn1_type_name = "VisibleString"
4154 UTCTimeState = namedtuple(
4156 OctetStringState._fields + ("ber_raw",),
4161 def str_to_time_fractions(value):
4163 year, v = (v // 10**10), (v % 10**10)
4164 month, v = (v // 10**8), (v % 10**8)
4165 day, v = (v // 10**6), (v % 10**6)
4166 hour, v = (v // 10**4), (v % 10**4)
4167 minute, second = (v // 100), (v % 100)
4168 return year, month, day, hour, minute, second
4171 class UTCTime(VisibleString):
4172 """``UTCTime`` datetime type
4174 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4175 UTCTime UTCTime 2017-09-30T22:07:50
4181 datetime.datetime(2017, 9, 30, 22, 7, 50)
4182 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4183 datetime.datetime(1957, 9, 30, 22, 7, 50)
4185 If BER encoded value was met, then ``ber_raw`` attribute will hold
4186 its raw representation.
4190 Pay attention that UTCTime can not hold full year, so all years
4191 having < 50 years are treated as 20xx, 19xx otherwise, according
4192 to X.509 recommendation.
4196 No strict validation of UTC offsets are made, but very crude:
4198 * minutes are not exceeding 60
4199 * offset value is not exceeding 14 hours
4201 __slots__ = ("ber_raw",)
4202 tag_default = tag_encode(23)
4204 asn1_type_name = "UTCTime"
4214 bounds=None, # dummy argument, workability for OctetString.decode
4218 :param value: set the value. Either datetime type, or
4219 :py:class:`pyderasn.UTCTime` object
4220 :param bytes impl: override default tag with ``IMPLICIT`` one
4221 :param bytes expl: override default tag with ``EXPLICIT`` one
4222 :param default: set default value. Type same as in ``value``
4223 :param bool optional: is object ``OPTIONAL`` in sequence
4225 super(UTCTime, self).__init__(
4226 None, None, impl, expl, None, optional, _decoded, ctx,
4230 if value is not None:
4231 self._value, self.ber_raw = self._value_sanitize(value, ctx)
4232 self.ber_encoded = self.ber_raw is not None
4233 if default is not None:
4234 default, _ = self._value_sanitize(default)
4235 self.default = self.__class__(
4240 if self._value is None:
4241 self._value = default
4243 self.optional = optional
4245 def _strptime_bered(self, value):
4246 year, month, day, hour, minute, _ = str_to_time_fractions(value[:10] + "00")
4249 raise ValueError("no timezone")
4250 year += 2000 if year < 50 else 1900
4251 decoded = datetime(year, month, day, hour, minute)
4253 if value[-1] == "Z":
4257 raise ValueError("invalid UTC offset")
4258 if value[-5] == "-":
4260 elif value[-5] == "+":
4263 raise ValueError("invalid UTC offset")
4264 v = pureint(value[-4:])
4265 offset, v = (60 * (v % 100)), v // 100
4267 raise ValueError("invalid UTC offset minutes")
4269 if offset > 14 * 3600:
4270 raise ValueError("too big UTC offset")
4274 return offset, decoded
4276 raise ValueError("invalid UTC offset seconds")
4277 seconds = pureint(value)
4279 raise ValueError("invalid seconds value")
4280 return offset, decoded + timedelta(seconds=seconds)
4282 def _strptime(self, value):
4283 # datetime.strptime's format: %y%m%d%H%M%SZ
4284 if len(value) != LEN_YYMMDDHHMMSSZ:
4285 raise ValueError("invalid UTCTime length")
4286 if value[-1] != "Z":
4287 raise ValueError("non UTC timezone")
4288 year, month, day, hour, minute, second = str_to_time_fractions(value[:-1])
4289 year += 2000 if year < 50 else 1900
4290 return datetime(year, month, day, hour, minute, second)
4292 def _dt_sanitize(self, value):
4293 if value.year < 1950 or value.year > 2049:
4294 raise ValueError("UTCTime can hold only 1950-2049 years")
4295 return value.replace(microsecond=0)
4297 def _value_sanitize(self, value, ctx=None):
4298 if value.__class__ == binary_type:
4300 value_decoded = value.decode("ascii")
4301 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4302 raise DecodeError("invalid UTCTime encoding: %r" % err)
4305 return self._strptime(value_decoded), None
4306 except (TypeError, ValueError) as _err:
4308 if (ctx is not None) and ctx.get("bered", False):
4310 offset, _value = self._strptime_bered(value_decoded)
4311 _value = _value - timedelta(seconds=offset)
4312 return self._dt_sanitize(_value), value
4313 except (TypeError, ValueError, OverflowError) as _err:
4316 "invalid %s format: %r" % (self.asn1_type_name, err),
4317 klass=self.__class__,
4319 if isinstance(value, self.__class__):
4320 return value._value, None
4321 if value.__class__ == datetime:
4322 return self._dt_sanitize(value), None
4323 raise InvalidValueType((self.__class__, datetime))
4325 def _pp_value(self):
4327 value = self._value.isoformat()
4328 if self.ber_encoded:
4329 value += " (%s)" % self.ber_raw
4332 def __unicode__(self):
4334 value = self._value.isoformat()
4335 if self.ber_encoded:
4336 value += " (%s)" % self.ber_raw
4338 return text_type(self._pp_value())
4340 def __getstate__(self):
4341 return UTCTimeState(
4342 *super(UTCTime, self).__getstate__(),
4343 **{"ber_raw": self.ber_raw}
4346 def __setstate__(self, state):
4347 super(UTCTime, self).__setstate__(state)
4348 self.ber_raw = state.ber_raw
4350 def __bytes__(self):
4351 self._assert_ready()
4352 return self._encode_time()
4354 def __eq__(self, their):
4355 if their.__class__ == binary_type:
4356 return self._encode_time() == their
4357 if their.__class__ == datetime:
4358 return self.todatetime() == their
4359 if not isinstance(their, self.__class__):
4362 self._value == their._value and
4363 self.tag == their.tag and
4364 self._expl == their._expl
4367 def _encode_time(self):
4368 return self._value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4371 self._assert_ready()
4372 value = self._encode_time()
4373 return b"".join((self.tag, len_encode(len(value)), value))
4375 def todatetime(self):
4379 return pp_console_row(next(self.pps()))
4381 def pps(self, decode_path=()):
4384 asn1_type_name=self.asn1_type_name,
4385 obj_name=self.__class__.__name__,
4386 decode_path=decode_path,
4387 value=self._pp_value(),
4388 optional=self.optional,
4389 default=self == self.default,
4390 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4391 expl=None if self._expl is None else tag_decode(self._expl),
4396 expl_offset=self.expl_offset if self.expled else None,
4397 expl_tlen=self.expl_tlen if self.expled else None,
4398 expl_llen=self.expl_llen if self.expled else None,
4399 expl_vlen=self.expl_vlen if self.expled else None,
4400 expl_lenindef=self.expl_lenindef,
4401 ber_encoded=self.ber_encoded,
4404 for pp in self.pps_lenindef(decode_path):
4408 class GeneralizedTime(UTCTime):
4409 """``GeneralizedTime`` datetime type
4411 This type is similar to :py:class:`pyderasn.UTCTime`.
4413 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4414 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4416 '20170930220750.000123Z'
4417 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4418 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4422 Only microsecond fractions are supported in DER encoding.
4423 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4424 higher precision values.
4428 BER encoded data can loss information (accuracy) during decoding
4429 because of float transformations.
4433 Local times (without explicit timezone specification) are treated
4434 as UTC one, no transformations are made.
4438 Zero year is unsupported.
4441 tag_default = tag_encode(24)
4442 asn1_type_name = "GeneralizedTime"
4444 def _dt_sanitize(self, value):
4447 def _strptime_bered(self, value):
4448 if len(value) < 4 + 3 * 2:
4449 raise ValueError("invalid GeneralizedTime")
4450 year, month, day, hour, _, _ = str_to_time_fractions(value[:10] + "0000")
4451 decoded = datetime(year, month, day, hour)
4452 offset, value = 0, value[10:]
4454 return offset, decoded
4455 if value[-1] == "Z":
4458 for char, sign in (("-", -1), ("+", 1)):
4459 idx = value.rfind(char)
4462 offset_raw, value = value[idx + 1:].replace(":", ""), value[:idx]
4463 v = pureint(offset_raw)
4464 if len(offset_raw) == 4:
4465 offset, v = (60 * (v % 100)), v // 100
4467 raise ValueError("invalid UTC offset minutes")
4468 elif len(offset_raw) == 2:
4471 raise ValueError("invalid UTC offset")
4473 if offset > 14 * 3600:
4474 raise ValueError("too big UTC offset")
4478 return offset, decoded
4479 if value[0] in DECIMAL_SIGNS:
4481 decoded + timedelta(seconds=3600 * fractions2float(value[1:]))
4484 raise ValueError("stripped minutes")
4485 decoded += timedelta(seconds=60 * pureint(value[:2]))
4488 return offset, decoded
4489 if value[0] in DECIMAL_SIGNS:
4491 decoded + timedelta(seconds=60 * fractions2float(value[1:]))
4494 raise ValueError("stripped seconds")
4495 decoded += timedelta(seconds=pureint(value[:2]))
4498 return offset, decoded
4499 if value[0] not in DECIMAL_SIGNS:
4500 raise ValueError("invalid format after seconds")
4502 decoded + timedelta(microseconds=10**6 * fractions2float(value[1:]))
4505 def _strptime(self, value):
4507 if l == LEN_YYYYMMDDHHMMSSZ:
4508 # datetime.strptime's format: %Y%m%d%H%M%SZ
4509 if value[-1] != "Z":
4510 raise ValueError("non UTC timezone")
4511 return datetime(*str_to_time_fractions(value[:-1]))
4512 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4513 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4514 if value[-1] != "Z":
4515 raise ValueError("non UTC timezone")
4516 if value[14] != ".":
4517 raise ValueError("no fractions separator")
4520 raise ValueError("trailing zero")
4523 raise ValueError("only microsecond fractions are supported")
4524 us = pureint(us + ("0" * (6 - us_len)))
4525 year, month, day, hour, minute, second = str_to_time_fractions(value[:14])
4526 return datetime(year, month, day, hour, minute, second, us)
4527 raise ValueError("invalid GeneralizedTime length")
4529 def _encode_time(self):
4531 encoded = value.strftime("%Y%m%d%H%M%S")
4532 if value.microsecond > 0:
4533 encoded += (".%06d" % value.microsecond).rstrip("0")
4534 return (encoded + "Z").encode("ascii")
4537 class GraphicString(CommonString):
4539 tag_default = tag_encode(25)
4540 encoding = "iso-8859-1"
4541 asn1_type_name = "GraphicString"
4544 class ISO646String(VisibleString):
4546 asn1_type_name = "ISO646String"
4549 class GeneralString(CommonString):
4551 tag_default = tag_encode(27)
4552 encoding = "iso-8859-1"
4553 asn1_type_name = "GeneralString"
4556 class UniversalString(CommonString):
4558 tag_default = tag_encode(28)
4559 encoding = "utf-32-be"
4560 asn1_type_name = "UniversalString"
4563 class BMPString(CommonString):
4565 tag_default = tag_encode(30)
4566 encoding = "utf-16-be"
4567 asn1_type_name = "BMPString"
4570 ChoiceState = namedtuple("ChoiceState", (
4584 ), **NAMEDTUPLE_KWARGS)
4588 """``CHOICE`` special type
4592 class GeneralName(Choice):
4594 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4595 ("dNSName", IA5String(impl=tag_ctxp(2))),
4598 >>> gn = GeneralName()
4600 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4601 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4602 >>> gn["dNSName"] = IA5String("bar.baz")
4603 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4604 >>> gn["rfc822Name"]
4607 [2] IA5String IA5 bar.baz
4610 >>> gn.value == gn["dNSName"]
4613 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4615 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4616 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4618 __slots__ = ("specs",)
4620 asn1_type_name = "CHOICE"
4633 :param value: set the value. Either ``(choice, value)`` tuple, or
4634 :py:class:`pyderasn.Choice` object
4635 :param bytes impl: can not be set, do **not** use it
4636 :param bytes expl: override default tag with ``EXPLICIT`` one
4637 :param default: set default value. Type same as in ``value``
4638 :param bool optional: is object ``OPTIONAL`` in sequence
4640 if impl is not None:
4641 raise ValueError("no implicit tag allowed for CHOICE")
4642 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4644 schema = getattr(self, "schema", ())
4645 if len(schema) == 0:
4646 raise ValueError("schema must be specified")
4648 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
4651 if value is not None:
4652 self._value = self._value_sanitize(value)
4653 if default is not None:
4654 default_value = self._value_sanitize(default)
4655 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4656 default_obj.specs = self.specs
4657 default_obj._value = default_value
4658 self.default = default_obj
4660 self._value = copy(default_obj._value)
4662 def _value_sanitize(self, value):
4663 if (value.__class__ == tuple) and len(value) == 2:
4665 spec = self.specs.get(choice)
4667 raise ObjUnknown(choice)
4668 if not isinstance(obj, spec.__class__):
4669 raise InvalidValueType((spec,))
4670 return (choice, spec(obj))
4671 if isinstance(value, self.__class__):
4673 raise InvalidValueType((self.__class__, tuple))
4677 return self._value is not None and self._value[1].ready
4681 return self.expl_lenindef or (
4682 (self._value is not None) and
4683 self._value[1].bered
4686 def __getstate__(self):
4703 def __setstate__(self, state):
4704 super(Choice, self).__setstate__(state)
4705 self.specs = state.specs
4706 self._value = state.value
4707 self._expl = state.expl
4708 self.default = state.default
4709 self.optional = state.optional
4710 self.offset = state.offset
4711 self.llen = state.llen
4712 self.vlen = state.vlen
4713 self.expl_lenindef = state.expl_lenindef
4714 self.lenindef = state.lenindef
4715 self.ber_encoded = state.ber_encoded
4717 def __eq__(self, their):
4718 if (their.__class__ == tuple) and len(their) == 2:
4719 return self._value == their
4720 if not isinstance(their, self.__class__):
4723 self.specs == their.specs and
4724 self._value == their._value
4734 return self.__class__(
4737 expl=self._expl if expl is None else expl,
4738 default=self.default if default is None else default,
4739 optional=self.optional if optional is None else optional,
4744 self._assert_ready()
4745 return self._value[0]
4749 self._assert_ready()
4750 return self._value[1]
4752 def __getitem__(self, key):
4753 if key not in self.specs:
4754 raise ObjUnknown(key)
4755 if self._value is None:
4757 choice, value = self._value
4762 def __setitem__(self, key, value):
4763 spec = self.specs.get(key)
4765 raise ObjUnknown(key)
4766 if not isinstance(value, spec.__class__):
4767 raise InvalidValueType((spec.__class__,))
4768 self._value = (key, spec(value))
4776 return self._value[1].decoded if self.ready else False
4779 self._assert_ready()
4780 return self._value[1].encode()
4782 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4783 for choice, spec in iteritems(self.specs):
4784 sub_decode_path = decode_path + (choice,)
4790 decode_path=sub_decode_path,
4793 _ctx_immutable=False,
4800 klass=self.__class__,
4801 decode_path=decode_path,
4804 if tag_only: # pragma: no cover
4806 value, tail = spec.decode(
4810 decode_path=sub_decode_path,
4812 _ctx_immutable=False,
4814 obj = self.__class__(
4817 default=self.default,
4818 optional=self.optional,
4819 _decoded=(offset, 0, value.fulllen),
4821 obj._value = (choice, value)
4825 value = pp_console_row(next(self.pps()))
4827 value = "%s[%r]" % (value, self.value)
4830 def pps(self, decode_path=()):
4833 asn1_type_name=self.asn1_type_name,
4834 obj_name=self.__class__.__name__,
4835 decode_path=decode_path,
4836 value=self.choice if self.ready else None,
4837 optional=self.optional,
4838 default=self == self.default,
4839 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4840 expl=None if self._expl is None else tag_decode(self._expl),
4845 expl_lenindef=self.expl_lenindef,
4849 yield self.value.pps(decode_path=decode_path + (self.choice,))
4850 for pp in self.pps_lenindef(decode_path):
4854 class PrimitiveTypes(Choice):
4855 """Predefined ``CHOICE`` for all generic primitive types
4857 It could be useful for general decoding of some unspecified values:
4859 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4860 OCTET STRING 3 bytes 666f6f
4861 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4865 schema = tuple((klass.__name__, klass()) for klass in (
4889 AnyState = namedtuple("AnyState", (
4902 ), **NAMEDTUPLE_KWARGS)
4906 """``ANY`` special type
4908 >>> Any(Integer(-123))
4910 >>> a = Any(OctetString(b"hello world").encode())
4911 ANY 040b68656c6c6f20776f726c64
4912 >>> hexenc(bytes(a))
4913 b'0x040x0bhello world'
4915 __slots__ = ("defined",)
4916 tag_default = tag_encode(0)
4917 asn1_type_name = "ANY"
4927 :param value: set the value. Either any kind of pyderasn's
4928 **ready** object, or bytes. Pay attention that
4929 **no** validation is performed is raw binary value
4931 :param bytes expl: override default tag with ``EXPLICIT`` one
4932 :param bool optional: is object ``OPTIONAL`` in sequence
4934 super(Any, self).__init__(None, expl, None, optional, _decoded)
4935 self._value = None if value is None else self._value_sanitize(value)
4938 def _value_sanitize(self, value):
4939 if value.__class__ == binary_type:
4941 if isinstance(value, self.__class__):
4943 if isinstance(value, Obj):
4944 return value.encode()
4945 raise InvalidValueType((self.__class__, Obj, binary_type))
4949 return self._value is not None
4953 if self.expl_lenindef or self.lenindef:
4955 if self.defined is None:
4957 return self.defined[1].bered
4959 def __getstate__(self):
4975 def __setstate__(self, state):
4976 super(Any, self).__setstate__(state)
4977 self._value = state.value
4978 self.tag = state.tag
4979 self._expl = state.expl
4980 self.optional = state.optional
4981 self.offset = state.offset
4982 self.llen = state.llen
4983 self.vlen = state.vlen
4984 self.expl_lenindef = state.expl_lenindef
4985 self.lenindef = state.lenindef
4986 self.ber_encoded = state.ber_encoded
4987 self.defined = state.defined
4989 def __eq__(self, their):
4990 if their.__class__ == binary_type:
4991 return self._value == their
4992 if issubclass(their.__class__, Any):
4993 return self._value == their._value
5002 return self.__class__(
5004 expl=self._expl if expl is None else expl,
5005 optional=self.optional if optional is None else optional,
5008 def __bytes__(self):
5009 self._assert_ready()
5017 self._assert_ready()
5020 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5022 t, tlen, lv = tag_strip(tlv)
5023 except DecodeError as err:
5024 raise err.__class__(
5026 klass=self.__class__,
5027 decode_path=decode_path,
5031 l, llen, v = len_decode(lv)
5032 except LenIndefForm as err:
5033 if not ctx.get("bered", False):
5034 raise err.__class__(
5036 klass=self.__class__,
5037 decode_path=decode_path,
5040 llen, vlen, v = 1, 0, lv[1:]
5041 sub_offset = offset + tlen + llen
5043 while v[:EOC_LEN].tobytes() != EOC:
5044 chunk, v = Any().decode(
5047 decode_path=decode_path + (str(chunk_i),),
5050 _ctx_immutable=False,
5052 vlen += chunk.tlvlen
5053 sub_offset += chunk.tlvlen
5055 tlvlen = tlen + llen + vlen + EOC_LEN
5056 obj = self.__class__(
5057 value=tlv[:tlvlen].tobytes(),
5059 optional=self.optional,
5060 _decoded=(offset, 0, tlvlen),
5063 obj.tag = t.tobytes()
5064 return obj, v[EOC_LEN:]
5065 except DecodeError as err:
5066 raise err.__class__(
5068 klass=self.__class__,
5069 decode_path=decode_path,
5073 raise NotEnoughData(
5074 "encoded length is longer than data",
5075 klass=self.__class__,
5076 decode_path=decode_path,
5079 tlvlen = tlen + llen + l
5080 v, tail = tlv[:tlvlen], v[l:]
5081 obj = self.__class__(
5084 optional=self.optional,
5085 _decoded=(offset, 0, tlvlen),
5087 obj.tag = t.tobytes()
5091 return pp_console_row(next(self.pps()))
5093 def pps(self, decode_path=()):
5096 asn1_type_name=self.asn1_type_name,
5097 obj_name=self.__class__.__name__,
5098 decode_path=decode_path,
5099 blob=self._value if self.ready else None,
5100 optional=self.optional,
5101 default=self == self.default,
5102 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5103 expl=None if self._expl is None else tag_decode(self._expl),
5108 expl_offset=self.expl_offset if self.expled else None,
5109 expl_tlen=self.expl_tlen if self.expled else None,
5110 expl_llen=self.expl_llen if self.expled else None,
5111 expl_vlen=self.expl_vlen if self.expled else None,
5112 expl_lenindef=self.expl_lenindef,
5113 lenindef=self.lenindef,
5116 defined_by, defined = self.defined or (None, None)
5117 if defined_by is not None:
5119 decode_path=decode_path + (DecodePathDefBy(defined_by),)
5121 for pp in self.pps_lenindef(decode_path):
5125 ########################################################################
5126 # ASN.1 constructed types
5127 ########################################################################
5129 def get_def_by_path(defines_by_path, sub_decode_path):
5130 """Get define by decode path
5132 for path, define in defines_by_path:
5133 if len(path) != len(sub_decode_path):
5135 for p1, p2 in zip(path, sub_decode_path):
5136 if (p1 != any) and (p1 != p2):
5142 def abs_decode_path(decode_path, rel_path):
5143 """Create an absolute decode path from current and relative ones
5145 :param decode_path: current decode path, starting point. Tuple of strings
5146 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5147 If first tuple's element is "/", then treat it as
5148 an absolute path, ignoring ``decode_path`` as
5149 starting point. Also this tuple can contain ".."
5150 elements, stripping the leading element from
5153 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5154 ("foo", "bar", "baz", "whatever")
5155 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5157 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5160 if rel_path[0] == "/":
5162 if rel_path[0] == "..":
5163 return abs_decode_path(decode_path[:-1], rel_path[1:])
5164 return decode_path + rel_path
5167 SequenceState = namedtuple("SequenceState", (
5181 ), **NAMEDTUPLE_KWARGS)
5184 class Sequence(Obj):
5185 """``SEQUENCE`` structure type
5187 You have to make specification of sequence::
5189 class Extension(Sequence):
5191 ("extnID", ObjectIdentifier()),
5192 ("critical", Boolean(default=False)),
5193 ("extnValue", OctetString()),
5196 Then, you can work with it as with dictionary.
5198 >>> ext = Extension()
5199 >>> Extension().specs
5201 ('extnID', OBJECT IDENTIFIER),
5202 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5203 ('extnValue', OCTET STRING),
5205 >>> ext["extnID"] = "1.2.3"
5206 Traceback (most recent call last):
5207 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5208 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5210 You can determine if sequence is ready to be encoded:
5215 Traceback (most recent call last):
5216 pyderasn.ObjNotReady: object is not ready: extnValue
5217 >>> ext["extnValue"] = OctetString(b"foobar")
5221 Value you want to assign, must have the same **type** as in
5222 corresponding specification, but it can have different tags,
5223 optional/default attributes -- they will be taken from specification
5226 class TBSCertificate(Sequence):
5228 ("version", Version(expl=tag_ctxc(0), default="v1")),
5231 >>> tbs = TBSCertificate()
5232 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5234 Assign ``None`` to remove value from sequence.
5236 You can set values in Sequence during its initialization:
5238 >>> AlgorithmIdentifier((
5239 ("algorithm", ObjectIdentifier("1.2.3")),
5240 ("parameters", Any(Null()))
5242 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5244 You can determine if value exists/set in the sequence and take its value:
5246 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5249 OBJECT IDENTIFIER 1.2.3
5251 But pay attention that if value has default, then it won't be (not
5252 in) in the sequence (because ``DEFAULT`` must not be encoded in
5253 DER), but you can read its value:
5255 >>> "critical" in ext, ext["critical"]
5256 (False, BOOLEAN False)
5257 >>> ext["critical"] = Boolean(True)
5258 >>> "critical" in ext, ext["critical"]
5259 (True, BOOLEAN True)
5261 All defaulted values are always optional.
5263 .. _allow_default_values_ctx:
5265 DER prohibits default value encoding and will raise an error if
5266 default value is unexpectedly met during decode.
5267 If :ref:`bered <bered_ctx>` context option is set, then no error
5268 will be raised, but ``bered`` attribute set. You can disable strict
5269 defaulted values existence validation by setting
5270 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5272 Two sequences are equal if they have equal specification (schema),
5273 implicit/explicit tagging and the same values.
5275 __slots__ = ("specs",)
5276 tag_default = tag_encode(form=TagFormConstructed, num=16)
5277 asn1_type_name = "SEQUENCE"
5289 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5291 schema = getattr(self, "schema", ())
5293 schema if schema.__class__ == OrderedDict else OrderedDict(schema)
5296 if value is not None:
5297 if issubclass(value.__class__, Sequence):
5298 self._value = value._value
5299 elif hasattr(value, "__iter__"):
5300 for seq_key, seq_value in value:
5301 self[seq_key] = seq_value
5303 raise InvalidValueType((Sequence,))
5304 if default is not None:
5305 if not issubclass(default.__class__, Sequence):
5306 raise InvalidValueType((Sequence,))
5307 default_value = default._value
5308 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5309 default_obj.specs = self.specs
5310 default_obj._value = default_value
5311 self.default = default_obj
5313 self._value = copy(default_obj._value)
5317 for name, spec in iteritems(self.specs):
5318 value = self._value.get(name)
5329 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5331 return any(value.bered for value in itervalues(self._value))
5333 def __getstate__(self):
5334 return SequenceState(
5337 {k: copy(v) for k, v in iteritems(self._value)},
5350 def __setstate__(self, state):
5351 super(Sequence, self).__setstate__(state)
5352 self.specs = state.specs
5353 self._value = state.value
5354 self.tag = state.tag
5355 self._expl = state.expl
5356 self.default = state.default
5357 self.optional = state.optional
5358 self.offset = state.offset
5359 self.llen = state.llen
5360 self.vlen = state.vlen
5361 self.expl_lenindef = state.expl_lenindef
5362 self.lenindef = state.lenindef
5363 self.ber_encoded = state.ber_encoded
5365 def __eq__(self, their):
5366 if not isinstance(their, self.__class__):
5369 self.specs == their.specs and
5370 self.tag == their.tag and
5371 self._expl == their._expl and
5372 self._value == their._value
5383 return self.__class__(
5386 impl=self.tag if impl is None else impl,
5387 expl=self._expl if expl is None else expl,
5388 default=self.default if default is None else default,
5389 optional=self.optional if optional is None else optional,
5392 def __contains__(self, key):
5393 return key in self._value
5395 def __setitem__(self, key, value):
5396 spec = self.specs.get(key)
5398 raise ObjUnknown(key)
5400 self._value.pop(key, None)
5402 if not isinstance(value, spec.__class__):
5403 raise InvalidValueType((spec.__class__,))
5404 value = spec(value=value)
5405 if spec.default is not None and value == spec.default:
5406 self._value.pop(key, None)
5408 self._value[key] = value
5410 def __getitem__(self, key):
5411 value = self._value.get(key)
5412 if value is not None:
5414 spec = self.specs.get(key)
5416 raise ObjUnknown(key)
5417 if spec.default is not None:
5421 def _encoded_values(self):
5423 for name, spec in iteritems(self.specs):
5424 value = self._value.get(name)
5428 raise ObjNotReady(name)
5429 raws.append(value.encode())
5433 v = b"".join(self._encoded_values())
5434 return b"".join((self.tag, len_encode(len(v)), v))
5436 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5438 t, tlen, lv = tag_strip(tlv)
5439 except DecodeError as err:
5440 raise err.__class__(
5442 klass=self.__class__,
5443 decode_path=decode_path,
5448 klass=self.__class__,
5449 decode_path=decode_path,
5452 if tag_only: # pragma: no cover
5455 ctx_bered = ctx.get("bered", False)
5457 l, llen, v = len_decode(lv)
5458 except LenIndefForm as err:
5460 raise err.__class__(
5462 klass=self.__class__,
5463 decode_path=decode_path,
5466 l, llen, v = 0, 1, lv[1:]
5468 except DecodeError as err:
5469 raise err.__class__(
5471 klass=self.__class__,
5472 decode_path=decode_path,
5476 raise NotEnoughData(
5477 "encoded length is longer than data",
5478 klass=self.__class__,
5479 decode_path=decode_path,
5483 v, tail = v[:l], v[l:]
5485 sub_offset = offset + tlen + llen
5488 ctx_allow_default_values = ctx.get("allow_default_values", False)
5489 for name, spec in iteritems(self.specs):
5490 if spec.optional and (
5491 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5495 sub_decode_path = decode_path + (name,)
5497 value, v_tail = spec.decode(
5501 decode_path=sub_decode_path,
5503 _ctx_immutable=False,
5505 except TagMismatch as err:
5506 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5510 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5511 if defined is not None:
5512 defined_by, defined_spec = defined
5513 if issubclass(value.__class__, SequenceOf):
5514 for i, _value in enumerate(value):
5515 sub_sub_decode_path = sub_decode_path + (
5517 DecodePathDefBy(defined_by),
5519 defined_value, defined_tail = defined_spec.decode(
5520 memoryview(bytes(_value)),
5522 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5523 if value.expled else (value.tlen + value.llen)
5526 decode_path=sub_sub_decode_path,
5528 _ctx_immutable=False,
5530 if len(defined_tail) > 0:
5533 klass=self.__class__,
5534 decode_path=sub_sub_decode_path,
5537 _value.defined = (defined_by, defined_value)
5539 defined_value, defined_tail = defined_spec.decode(
5540 memoryview(bytes(value)),
5542 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5543 if value.expled else (value.tlen + value.llen)
5546 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5548 _ctx_immutable=False,
5550 if len(defined_tail) > 0:
5553 klass=self.__class__,
5554 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5557 value.defined = (defined_by, defined_value)
5559 value_len = value.fulllen
5561 sub_offset += value_len
5563 if spec.default is not None and value == spec.default:
5564 if ctx_bered or ctx_allow_default_values:
5568 "DEFAULT value met",
5569 klass=self.__class__,
5570 decode_path=sub_decode_path,
5573 values[name] = value
5575 spec_defines = getattr(spec, "defines", ())
5576 if len(spec_defines) == 0:
5577 defines_by_path = ctx.get("defines_by_path", ())
5578 if len(defines_by_path) > 0:
5579 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5580 if spec_defines is not None and len(spec_defines) > 0:
5581 for rel_path, schema in spec_defines:
5582 defined = schema.get(value, None)
5583 if defined is not None:
5584 ctx.setdefault("_defines", []).append((
5585 abs_decode_path(sub_decode_path[:-1], rel_path),
5589 if v[:EOC_LEN].tobytes() != EOC:
5592 klass=self.__class__,
5593 decode_path=decode_path,
5601 klass=self.__class__,
5602 decode_path=decode_path,
5605 obj = self.__class__(
5609 default=self.default,
5610 optional=self.optional,
5611 _decoded=(offset, llen, vlen),
5614 obj.lenindef = lenindef
5615 obj.ber_encoded = ber_encoded
5619 value = pp_console_row(next(self.pps()))
5621 for name in self.specs:
5622 _value = self._value.get(name)
5625 cols.append("%s: %s" % (name, repr(_value)))
5626 return "%s[%s]" % (value, "; ".join(cols))
5628 def pps(self, decode_path=()):
5631 asn1_type_name=self.asn1_type_name,
5632 obj_name=self.__class__.__name__,
5633 decode_path=decode_path,
5634 optional=self.optional,
5635 default=self == self.default,
5636 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5637 expl=None if self._expl is None else tag_decode(self._expl),
5642 expl_offset=self.expl_offset if self.expled else None,
5643 expl_tlen=self.expl_tlen if self.expled else None,
5644 expl_llen=self.expl_llen if self.expled else None,
5645 expl_vlen=self.expl_vlen if self.expled else None,
5646 expl_lenindef=self.expl_lenindef,
5647 lenindef=self.lenindef,
5648 ber_encoded=self.ber_encoded,
5651 for name in self.specs:
5652 value = self._value.get(name)
5655 yield value.pps(decode_path=decode_path + (name,))
5656 for pp in self.pps_lenindef(decode_path):
5660 class Set(Sequence):
5661 """``SET`` structure type
5663 Its usage is identical to :py:class:`pyderasn.Sequence`.
5665 .. _allow_unordered_set_ctx:
5667 DER prohibits unordered values encoding and will raise an error
5668 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5669 then no error will occure. Also you can disable strict values
5670 ordering check by setting ``"allow_unordered_set": True``
5671 :ref:`context <ctx>` option.
5674 tag_default = tag_encode(form=TagFormConstructed, num=17)
5675 asn1_type_name = "SET"
5678 raws = self._encoded_values()
5681 return b"".join((self.tag, len_encode(len(v)), v))
5683 def _specs_items(self):
5684 return iteritems(self.specs)
5686 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5688 t, tlen, lv = tag_strip(tlv)
5689 except DecodeError as err:
5690 raise err.__class__(
5692 klass=self.__class__,
5693 decode_path=decode_path,
5698 klass=self.__class__,
5699 decode_path=decode_path,
5705 ctx_bered = ctx.get("bered", False)
5707 l, llen, v = len_decode(lv)
5708 except LenIndefForm as err:
5710 raise err.__class__(
5712 klass=self.__class__,
5713 decode_path=decode_path,
5716 l, llen, v = 0, 1, lv[1:]
5718 except DecodeError as err:
5719 raise err.__class__(
5721 klass=self.__class__,
5722 decode_path=decode_path,
5726 raise NotEnoughData(
5727 "encoded length is longer than data",
5728 klass=self.__class__,
5732 v, tail = v[:l], v[l:]
5734 sub_offset = offset + tlen + llen
5737 ctx_allow_default_values = ctx.get("allow_default_values", False)
5738 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5739 value_prev = memoryview(v[:0])
5742 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5744 for name, spec in self._specs_items():
5745 sub_decode_path = decode_path + (name,)
5751 decode_path=sub_decode_path,
5754 _ctx_immutable=False,
5761 klass=self.__class__,
5762 decode_path=decode_path,
5765 value, v_tail = spec.decode(
5769 decode_path=sub_decode_path,
5771 _ctx_immutable=False,
5773 value_len = value.fulllen
5774 if value_prev.tobytes() > v[:value_len].tobytes():
5775 if ctx_bered or ctx_allow_unordered_set:
5779 "unordered " + self.asn1_type_name,
5780 klass=self.__class__,
5781 decode_path=sub_decode_path,
5784 if spec.default is None or value != spec.default:
5786 elif ctx_bered or ctx_allow_default_values:
5790 "DEFAULT value met",
5791 klass=self.__class__,
5792 decode_path=sub_decode_path,
5795 values[name] = value
5796 value_prev = v[:value_len]
5797 sub_offset += value_len
5800 obj = self.__class__(
5804 default=self.default,
5805 optional=self.optional,
5806 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5809 if v[:EOC_LEN].tobytes() != EOC:
5812 klass=self.__class__,
5813 decode_path=decode_path,
5821 "not all values are ready",
5822 klass=self.__class__,
5823 decode_path=decode_path,
5826 obj.ber_encoded = ber_encoded
5830 SequenceOfState = namedtuple("SequenceOfState", (
5846 ), **NAMEDTUPLE_KWARGS)
5849 class SequenceOf(Obj):
5850 """``SEQUENCE OF`` sequence type
5852 For that kind of type you must specify the object it will carry on
5853 (bounds are for example here, not required)::
5855 class Ints(SequenceOf):
5860 >>> ints.append(Integer(123))
5861 >>> ints.append(Integer(234))
5863 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5864 >>> [int(i) for i in ints]
5866 >>> ints.append(Integer(345))
5867 Traceback (most recent call last):
5868 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5871 >>> ints[1] = Integer(345)
5873 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5875 Also you can initialize sequence with preinitialized values:
5877 >>> ints = Ints([Integer(123), Integer(234)])
5879 __slots__ = ("spec", "_bound_min", "_bound_max")
5880 tag_default = tag_encode(form=TagFormConstructed, num=16)
5881 asn1_type_name = "SEQUENCE OF"
5894 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5896 schema = getattr(self, "schema", None)
5898 raise ValueError("schema must be specified")
5900 self._bound_min, self._bound_max = getattr(
5904 ) if bounds is None else bounds
5906 if value is not None:
5907 self._value = self._value_sanitize(value)
5908 if default is not None:
5909 default_value = self._value_sanitize(default)
5910 default_obj = self.__class__(
5915 default_obj._value = default_value
5916 self.default = default_obj
5918 self._value = copy(default_obj._value)
5920 def _value_sanitize(self, value):
5921 if issubclass(value.__class__, SequenceOf):
5922 value = value._value
5923 elif hasattr(value, "__iter__"):
5926 raise InvalidValueType((self.__class__, iter))
5927 if not self._bound_min <= len(value) <= self._bound_max:
5928 raise BoundsError(self._bound_min, len(value), self._bound_max)
5930 if not isinstance(v, self.spec.__class__):
5931 raise InvalidValueType((self.spec.__class__,))
5936 return all(v.ready for v in self._value)
5940 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5942 return any(v.bered for v in self._value)
5944 def __getstate__(self):
5945 return SequenceOfState(
5948 [copy(v) for v in self._value],
5963 def __setstate__(self, state):
5964 super(SequenceOf, self).__setstate__(state)
5965 self.spec = state.spec
5966 self._value = state.value
5967 self._bound_min = state.bound_min
5968 self._bound_max = state.bound_max
5969 self.tag = state.tag
5970 self._expl = state.expl
5971 self.default = state.default
5972 self.optional = state.optional
5973 self.offset = state.offset
5974 self.llen = state.llen
5975 self.vlen = state.vlen
5976 self.expl_lenindef = state.expl_lenindef
5977 self.lenindef = state.lenindef
5978 self.ber_encoded = state.ber_encoded
5980 def __eq__(self, their):
5981 if isinstance(their, self.__class__):
5983 self.spec == their.spec and
5984 self.tag == their.tag and
5985 self._expl == their._expl and
5986 self._value == their._value
5988 if hasattr(their, "__iter__"):
5989 return self._value == list(their)
6001 return self.__class__(
6005 (self._bound_min, self._bound_max)
6006 if bounds is None else bounds
6008 impl=self.tag if impl is None else impl,
6009 expl=self._expl if expl is None else expl,
6010 default=self.default if default is None else default,
6011 optional=self.optional if optional is None else optional,
6014 def __contains__(self, key):
6015 return key in self._value
6017 def append(self, value):
6018 if not isinstance(value, self.spec.__class__):
6019 raise InvalidValueType((self.spec.__class__,))
6020 if len(self._value) + 1 > self._bound_max:
6023 len(self._value) + 1,
6026 self._value.append(value)
6029 self._assert_ready()
6030 return iter(self._value)
6033 self._assert_ready()
6034 return len(self._value)
6036 def __setitem__(self, key, value):
6037 if not isinstance(value, self.spec.__class__):
6038 raise InvalidValueType((self.spec.__class__,))
6039 self._value[key] = self.spec(value=value)
6041 def __getitem__(self, key):
6042 return self._value[key]
6044 def _encoded_values(self):
6045 return [v.encode() for v in self._value]
6048 v = b"".join(self._encoded_values())
6049 return b"".join((self.tag, len_encode(len(v)), v))
6051 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
6053 t, tlen, lv = tag_strip(tlv)
6054 except DecodeError as err:
6055 raise err.__class__(
6057 klass=self.__class__,
6058 decode_path=decode_path,
6063 klass=self.__class__,
6064 decode_path=decode_path,
6070 ctx_bered = ctx.get("bered", False)
6072 l, llen, v = len_decode(lv)
6073 except LenIndefForm as err:
6075 raise err.__class__(
6077 klass=self.__class__,
6078 decode_path=decode_path,
6081 l, llen, v = 0, 1, lv[1:]
6083 except DecodeError as err:
6084 raise err.__class__(
6086 klass=self.__class__,
6087 decode_path=decode_path,
6091 raise NotEnoughData(
6092 "encoded length is longer than data",
6093 klass=self.__class__,
6094 decode_path=decode_path,
6098 v, tail = v[:l], v[l:]
6100 sub_offset = offset + tlen + llen
6102 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
6103 value_prev = memoryview(v[:0])
6107 if lenindef and v[:EOC_LEN].tobytes() == EOC:
6109 sub_decode_path = decode_path + (str(len(_value)),)
6110 value, v_tail = spec.decode(
6114 decode_path=sub_decode_path,
6116 _ctx_immutable=False,
6118 value_len = value.fulllen
6120 if value_prev.tobytes() > v[:value_len].tobytes():
6121 if ctx_bered or ctx_allow_unordered_set:
6125 "unordered " + self.asn1_type_name,
6126 klass=self.__class__,
6127 decode_path=sub_decode_path,
6130 value_prev = v[:value_len]
6131 _value.append(value)
6132 sub_offset += value_len
6136 obj = self.__class__(
6139 bounds=(self._bound_min, self._bound_max),
6142 default=self.default,
6143 optional=self.optional,
6144 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6146 except BoundsError as err:
6149 klass=self.__class__,
6150 decode_path=decode_path,
6154 if v[:EOC_LEN].tobytes() != EOC:
6157 klass=self.__class__,
6158 decode_path=decode_path,
6163 obj.ber_encoded = ber_encoded
6168 pp_console_row(next(self.pps())),
6169 ", ".join(repr(v) for v in self._value),
6172 def pps(self, decode_path=()):
6175 asn1_type_name=self.asn1_type_name,
6176 obj_name=self.__class__.__name__,
6177 decode_path=decode_path,
6178 optional=self.optional,
6179 default=self == self.default,
6180 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6181 expl=None if self._expl is None else tag_decode(self._expl),
6186 expl_offset=self.expl_offset if self.expled else None,
6187 expl_tlen=self.expl_tlen if self.expled else None,
6188 expl_llen=self.expl_llen if self.expled else None,
6189 expl_vlen=self.expl_vlen if self.expled else None,
6190 expl_lenindef=self.expl_lenindef,
6191 lenindef=self.lenindef,
6192 ber_encoded=self.ber_encoded,
6195 for i, value in enumerate(self._value):
6196 yield value.pps(decode_path=decode_path + (str(i),))
6197 for pp in self.pps_lenindef(decode_path):
6201 class SetOf(SequenceOf):
6202 """``SET OF`` sequence type
6204 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6207 tag_default = tag_encode(form=TagFormConstructed, num=17)
6208 asn1_type_name = "SET OF"
6211 raws = self._encoded_values()
6214 return b"".join((self.tag, len_encode(len(v)), v))
6216 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6217 return super(SetOf, self)._decode(
6223 ordering_check=True,
6227 def obj_by_path(pypath): # pragma: no cover
6228 """Import object specified as string Python path
6230 Modules must be separated from classes/functions with ``:``.
6232 >>> obj_by_path("foo.bar:Baz")
6233 <class 'foo.bar.Baz'>
6234 >>> obj_by_path("foo.bar:Baz.boo")
6235 <classmethod 'foo.bar.Baz.boo'>
6237 mod, objs = pypath.rsplit(":", 1)
6238 from importlib import import_module
6239 obj = import_module(mod)
6240 for obj_name in objs.split("."):
6241 obj = getattr(obj, obj_name)
6245 def generic_decoder(): # pragma: no cover
6246 # All of this below is a big hack with self references
6247 choice = PrimitiveTypes()
6248 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6249 choice.specs["SetOf"] = SetOf(schema=choice)
6250 for i in six_xrange(31):
6251 choice.specs["SequenceOf%d" % i] = SequenceOf(
6255 choice.specs["Any"] = Any()
6257 # Class name equals to type name, to omit it from output
6258 class SEQUENCEOF(SequenceOf):
6266 with_decode_path=False,
6267 decode_path_only=(),
6269 def _pprint_pps(pps):
6271 if hasattr(pp, "_fields"):
6273 decode_path_only != () and
6274 pp.decode_path[:len(decode_path_only)] != decode_path_only
6277 if pp.asn1_type_name == Choice.asn1_type_name:
6279 pp_kwargs = pp._asdict()
6280 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6281 pp = _pp(**pp_kwargs)
6282 yield pp_console_row(
6287 with_colours=with_colours,
6288 with_decode_path=with_decode_path,
6289 decode_path_len_decrease=len(decode_path_only),
6291 for row in pp_console_blob(
6293 decode_path_len_decrease=len(decode_path_only),
6297 for row in _pprint_pps(pp):
6299 return "\n".join(_pprint_pps(obj.pps()))
6300 return SEQUENCEOF(), pprint_any
6303 def main(): # pragma: no cover
6305 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6306 parser.add_argument(
6310 help="Skip that number of bytes from the beginning",
6312 parser.add_argument(
6314 help="Python paths to dictionary with OIDs, comma separated",
6316 parser.add_argument(
6318 help="Python path to schema definition to use",
6320 parser.add_argument(
6321 "--defines-by-path",
6322 help="Python path to decoder's defines_by_path",
6324 parser.add_argument(
6326 action="store_true",
6327 help="Disallow BER encoding",
6329 parser.add_argument(
6330 "--print-decode-path",
6331 action="store_true",
6332 help="Print decode paths",
6334 parser.add_argument(
6335 "--decode-path-only",
6336 help="Print only specified decode path",
6338 parser.add_argument(
6340 action="store_true",
6341 help="Allow explicit tag out-of-bound",
6343 parser.add_argument(
6345 type=argparse.FileType("rb"),
6346 help="Path to DER file you want to decode",
6348 args = parser.parse_args()
6349 args.DERFile.seek(args.skip)
6350 der = memoryview(args.DERFile.read())
6351 args.DERFile.close()
6353 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6354 if args.oids else ()
6357 schema = obj_by_path(args.schema)
6358 from functools import partial
6359 pprinter = partial(pprint, big_blobs=True)
6361 schema, pprinter = generic_decoder()
6363 "bered": not args.nobered,
6364 "allow_expl_oob": args.allow_expl_oob,
6366 if args.defines_by_path is not None:
6367 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6368 obj, tail = schema().decode(der, ctx=ctx)
6372 with_colours=environ.get("NO_COLOR") is None,
6373 with_decode_path=args.print_decode_path,
6375 () if args.decode_path_only is None else
6376 tuple(args.decode_path_only.split(":"))
6380 print("\nTrailing data: %s" % hexenc(tail))
6383 if __name__ == "__main__":