3 # PyDERASN -- Python ASN.1 DER/BER codec with abstract structures
4 # Copyright (C) 2017-2020 Sergey Matveev <stargrave@stargrave.org>
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Lesser General Public License as
8 # published by the Free Software Foundation, version 3 of the License.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this program. If not, see <http://www.gnu.org/licenses/>.
17 """Python ASN.1 DER/BER codec with abstract structures
19 This library allows you to marshal various structures in ASN.1 DER
20 format, unmarshal them in BER/CER/DER ones.
24 >>> Integer().decod(raw) == i
27 There are primitive types, holding single values
28 (:py:class:`pyderasn.BitString`,
29 :py:class:`pyderasn.Boolean`,
30 :py:class:`pyderasn.Enumerated`,
31 :py:class:`pyderasn.GeneralizedTime`,
32 :py:class:`pyderasn.Integer`,
33 :py:class:`pyderasn.Null`,
34 :py:class:`pyderasn.ObjectIdentifier`,
35 :py:class:`pyderasn.OctetString`,
36 :py:class:`pyderasn.UTCTime`,
37 :py:class:`various strings <pyderasn.CommonString>`
38 (:py:class:`pyderasn.BMPString`,
39 :py:class:`pyderasn.GeneralString`,
40 :py:class:`pyderasn.GraphicString`,
41 :py:class:`pyderasn.IA5String`,
42 :py:class:`pyderasn.ISO646String`,
43 :py:class:`pyderasn.NumericString`,
44 :py:class:`pyderasn.PrintableString`,
45 :py:class:`pyderasn.T61String`,
46 :py:class:`pyderasn.TeletexString`,
47 :py:class:`pyderasn.UniversalString`,
48 :py:class:`pyderasn.UTF8String`,
49 :py:class:`pyderasn.VideotexString`,
50 :py:class:`pyderasn.VisibleString`)),
51 constructed types, holding multiple primitive types
52 (:py:class:`pyderasn.Sequence`,
53 :py:class:`pyderasn.SequenceOf`,
54 :py:class:`pyderasn.Set`,
55 :py:class:`pyderasn.SetOf`),
56 and special types like
57 :py:class:`pyderasn.Any` and
58 :py:class:`pyderasn.Choice`.
66 Most types in ASN.1 has specific tag for them. ``Obj.tag_default`` is
67 the default tag used during coding process. You can override it with
68 either ``IMPLICIT`` (using either ``impl`` keyword argument or ``impl``
69 class attribute), or ``EXPLICIT`` one (using either ``expl`` keyword
70 argument or ``expl`` class attribute). Both arguments take raw binary
71 string, containing that tag. You can **not** set implicit and explicit
74 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
75 functions, allowing you to easily create ``CONTEXT``
76 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
77 number. Pay attention that explicit tags always have *constructed* tag
78 (``tag_ctxc``), but implicit tags for primitive types are primitive
83 >>> Integer(impl=tag_ctxp(1))
85 >>> Integer(expl=tag_ctxc(2))
88 Implicit tag is not explicitly shown.
90 Two objects of the same type, but with different implicit/explicit tags
93 You can get object's effective tag (either default or implicited) through
94 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
97 >>> tag_decode(tag_ctxc(123))
99 >>> klass, form, num = tag_decode(tag_ctxc(123))
100 >>> klass == TagClassContext
102 >>> form == TagFormConstructed
105 To determine if object has explicit tag, use ``expled`` boolean property
106 and ``expl_tag`` property, returning explicit tag's value.
111 Many objects in sequences could be ``OPTIONAL`` and could have
112 ``DEFAULT`` value. You can specify that object's property using
113 corresponding keyword arguments.
115 >>> Integer(optional=True, default=123)
116 INTEGER 123 OPTIONAL DEFAULT
118 Those specifications do not play any role in primitive value encoding,
119 but are taken into account when dealing with sequences holding them. For
120 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
123 class Version(Integer):
129 class TBSCertificate(Sequence):
131 ("version", Version(expl=tag_ctxc(0), default="v1")),
134 When default argument is used and value is not specified, then it equals
142 Some objects give ability to set value size constraints. This is either
143 possible integer value, or allowed length of various strings and
144 sequences. Constraints are set in the following way::
149 And values satisfaction is checked as: ``MIN <= X <= MAX``.
151 For simplicity you can also set bounds the following way::
153 bounded_x = X(bounds=(MIN, MAX))
155 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
161 All objects have ``ready`` boolean property, that tells if object is
162 ready to be encoded. If that kind of action is performed on unready
163 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
165 All objects are friendly to ``copy.copy()`` and copied objects can be
168 Also all objects can be safely ``pickle``-d, but pay attention that
169 pickling among different PyDERASN versions is prohibited.
176 Decoding is performed using :py:meth:`pyderasn.Obj.decode` method.
177 ``offset`` optional argument could be used to set initial object's
178 offset in the binary data, for convenience. It returns decoded object
179 and remaining unmarshalled data (tail). Internally all work is done on
180 ``memoryview(data)``, and you can leave returning tail as a memoryview,
181 by specifying ``leavemm=True`` argument.
183 Also note convenient :py:meth:`pyderasn.Obj.decod` method, that
184 immediately checks and raises if there is non-empty tail.
186 When object is decoded, ``decoded`` property is true and you can safely
187 use following properties:
189 * ``offset`` -- position including initial offset where object's tag starts
190 * ``tlen`` -- length of object's tag
191 * ``llen`` -- length of object's length value
192 * ``vlen`` -- length of object's value
193 * ``tlvlen`` -- length of the whole object
195 Pay attention that those values do **not** include anything related to
196 explicit tag. If you want to know information about it, then use:
198 * ``expled`` -- to know if explicit tag is set
199 * ``expl_offset`` (it is lesser than ``offset``)
202 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
203 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
205 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
208 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
215 You can specify so called context keyword argument during
216 :py:meth:`pyderasn.Obj.decode` invocation. It is dictionary containing
217 various options governing decoding process.
219 Currently available context options:
221 * :ref:`allow_default_values <allow_default_values_ctx>`
222 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
223 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
224 * :ref:`bered <bered_ctx>`
225 * :ref:`defines_by_path <defines_by_path_ctx>`
232 All objects have ``pps()`` method, that is a generator of
233 :py:class:`pyderasn.PP` namedtuple, holding various raw information
234 about the object. If ``pps`` is called on sequences, then all underlying
235 ``PP`` will be yielded.
237 You can use :py:func:`pyderasn.pp_console_row` function, converting
238 those ``PP`` to human readable string. Actually exactly it is used for
239 all object ``repr``. But it is easy to write custom formatters.
241 >>> from pyderasn import pprint
242 >>> encoded = Integer(-12345).encode()
243 >>> obj, tail = Integer().decode(encoded)
244 >>> print(pprint(obj))
245 0 [1,1, 2] INTEGER -12345
249 Example certificate::
251 >>> print(pprint(crt))
252 0 [1,3,1604] Certificate SEQUENCE
253 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
254 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
255 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
256 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
257 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
258 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
260 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
261 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
262 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
263 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
264 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
265 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
266 . . . . . . . 13:02:45:53
268 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
269 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
270 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
272 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
273 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
274 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
279 Let's parse that output, human::
281 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
282 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
283 0 1 2 3 4 5 6 7 8 9 10 11
287 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
293 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
299 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
304 Offset of the object, where its DER/BER encoding begins.
305 Pay attention that it does **not** include explicit tag.
307 If explicit tag exists, then this is its length (tag + encoded length).
309 Length of object's tag. For example CHOICE does not have its own tag,
312 Length of encoded length.
314 Length of encoded value.
316 Visual indentation to show the depth of object in the hierarchy.
318 Object's name inside SEQUENCE/CHOICE.
320 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
321 here. "IMPLICIT" is omitted.
323 Object's class name, if set. Omitted if it is just an ordinary simple
324 value (like with ``algorithm`` in example above).
328 Object's value, if set. Can consist of multiple words (like OCTET/BIT
329 STRINGs above). We see ``v3`` value in Version, because it is named.
330 ``rdnSequence`` is the choice of CHOICE type.
332 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
333 default one, specified in the schema.
335 Shows does object contains any kind of BER encoded data (possibly
336 Sequence holding BER-encoded underlying value).
338 Only applicable to BER encoded data. Indefinite length encoding mark.
340 Only applicable to BER encoded data. If object has BER-specific
341 encoding, then ``BER`` will be shown. It does not depend on indefinite
342 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
343 (and its derivatives), ``SET``, ``SET OF`` could be BERed.
351 ASN.1 structures often have ANY and OCTET STRING fields, that are
352 DEFINED BY some previously met ObjectIdentifier. This library provides
353 ability to specify mapping between some OID and field that must be
354 decoded with specific specification.
361 :py:class:`pyderasn.ObjectIdentifier` field inside
362 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
363 necessary for decoding structures. For example, CMS (:rfc:`5652`)
366 class ContentInfo(Sequence):
368 ("contentType", ContentType(defines=((("content",), {
369 id_digestedData: DigestedData(),
370 id_signedData: SignedData(),
372 ("content", Any(expl=tag_ctxc(0))),
375 ``contentType`` field tells that it defines that ``content`` must be
376 decoded with ``SignedData`` specification, if ``contentType`` equals to
377 ``id-signedData``. The same applies to ``DigestedData``. If
378 ``contentType`` contains unknown OID, then no automatic decoding is
381 You can specify multiple fields, that will be autodecoded -- that is why
382 ``defines`` kwarg is a sequence. You can specify defined field
383 relatively or absolutely to current decode path. For example ``defines``
384 for AlgorithmIdentifier of X.509's
385 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
389 id_ecPublicKey: ECParameters(),
390 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
392 (("..", "subjectPublicKey"), {
393 id_rsaEncryption: RSAPublicKey(),
394 id_GostR3410_2001: OctetString(),
398 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
399 autodecode its parameters inside SPKI's algorithm and its public key
402 Following types can be automatically decoded (DEFINED BY):
404 * :py:class:`pyderasn.Any`
405 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
406 * :py:class:`pyderasn.OctetString`
407 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
408 ``Any``/``BitString``/``OctetString``-s
410 When any of those fields is automatically decoded, then ``.defined``
411 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
412 was defined, ``value`` contains corresponding decoded value. For example
413 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
415 .. _defines_by_path_ctx:
417 defines_by_path context option
418 ______________________________
420 Sometimes you either can not or do not want to explicitly set *defines*
421 in the scheme. You can dynamically apply those definitions when calling
422 ``.decode()`` method.
424 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
425 value must be sequence of following tuples::
427 (decode_path, defines)
429 where ``decode_path`` is a tuple holding so-called decode path to the
430 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
431 ``defines``, holding exactly the same value as accepted in its
432 :ref:`keyword argument <defines>`.
434 For example, again for CMS, you want to automatically decode
435 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
436 structures it may hold. Also, automatically decode ``controlSequence``
439 content_info = ContentInfo().decod(data, ctx={"defines_by_path": (
442 ((("content",), {id_signedData: SignedData()}),),
447 DecodePathDefBy(id_signedData),
452 id_cct_PKIData: PKIData(),
453 id_cct_PKIResponse: PKIResponse(),
459 DecodePathDefBy(id_signedData),
462 DecodePathDefBy(id_cct_PKIResponse),
468 id_cmc_recipientNonce: RecipientNonce(),
469 id_cmc_senderNonce: SenderNonce(),
470 id_cmc_statusInfoV2: CMCStatusInfoV2(),
471 id_cmc_transactionId: TransactionId(),
476 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
477 First function is useful for path construction when some automatic
478 decoding is already done. ``any`` means literally any value it meet --
479 useful for SEQUENCE/SET OF-s.
486 By default PyDERASN accepts only DER encoded data. It always encodes to
487 DER. But you can optionally enable BER decoding with setting ``bered``
488 :ref:`context <ctx>` argument to True. Indefinite lengths and
489 constructed primitive types should be parsed successfully.
491 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
492 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
493 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``
495 * If object has an indefinite length encoding, then its ``lenindef``
496 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
497 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
499 * If object has an indefinite length encoded explicit tag, then
500 ``expl_lenindef`` is set to True.
501 * If object has either any of BER-related encoding (explicit tag
502 indefinite length, object's indefinite length, BER-encoding) or any
503 underlying component has that kind of encoding, then ``bered``
504 attribute is set to True. For example SignedData CMS can have
505 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
506 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
508 EOC (end-of-contents) token's length is taken in advance in object's
511 .. _allow_expl_oob_ctx:
513 Allow explicit tag out-of-bound
514 -------------------------------
516 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
517 one value, more than one object. If you set ``allow_expl_oob`` context
518 option to True, then no error will be raised and that invalid encoding
519 will be silently further processed. But pay attention that offsets and
520 lengths will be invalid in that case.
524 This option should be used only for skipping some decode errors, just
525 to see the decoded structure somehow.
529 .. autoclass:: pyderasn.Obj
537 .. autoclass:: pyderasn.Boolean
542 .. autoclass:: pyderasn.Integer
547 .. autoclass:: pyderasn.BitString
552 .. autoclass:: pyderasn.OctetString
557 .. autoclass:: pyderasn.Null
562 .. autoclass:: pyderasn.ObjectIdentifier
567 .. autoclass:: pyderasn.Enumerated
571 .. autoclass:: pyderasn.CommonString
575 .. autoclass:: pyderasn.NumericString
579 .. autoclass:: pyderasn.PrintableString
584 .. autoclass:: pyderasn.UTCTime
585 :members: __init__, todatetime
589 .. autoclass:: pyderasn.GeneralizedTime
596 .. autoclass:: pyderasn.Choice
601 .. autoclass:: PrimitiveTypes
605 .. autoclass:: pyderasn.Any
613 .. autoclass:: pyderasn.Sequence
618 .. autoclass:: pyderasn.Set
623 .. autoclass:: pyderasn.SequenceOf
628 .. autoclass:: pyderasn.SetOf
634 .. autofunction:: pyderasn.abs_decode_path
635 .. autofunction:: pyderasn.colonize_hex
636 .. autofunction:: pyderasn.hexenc
637 .. autofunction:: pyderasn.hexdec
638 .. autofunction:: pyderasn.tag_encode
639 .. autofunction:: pyderasn.tag_decode
640 .. autofunction:: pyderasn.tag_ctxp
641 .. autofunction:: pyderasn.tag_ctxc
642 .. autoclass:: pyderasn.DecodeError
644 .. autoclass:: pyderasn.NotEnoughData
645 .. autoclass:: pyderasn.ExceedingData
646 .. autoclass:: pyderasn.LenIndefForm
647 .. autoclass:: pyderasn.TagMismatch
648 .. autoclass:: pyderasn.InvalidLength
649 .. autoclass:: pyderasn.InvalidOID
650 .. autoclass:: pyderasn.ObjUnknown
651 .. autoclass:: pyderasn.ObjNotReady
652 .. autoclass:: pyderasn.InvalidValueType
653 .. autoclass:: pyderasn.BoundsError
656 from codecs import getdecoder
657 from codecs import getencoder
658 from collections import namedtuple
659 from collections import OrderedDict
660 from copy import copy
661 from datetime import datetime
662 from math import ceil
663 from os import environ
664 from string import ascii_letters
665 from string import digits
666 from unicodedata import category as unicat
668 from six import add_metaclass
669 from six import binary_type
670 from six import byte2int
671 from six import indexbytes
672 from six import int2byte
673 from six import integer_types
674 from six import iterbytes
675 from six import iteritems
676 from six import itervalues
678 from six import string_types
679 from six import text_type
680 from six import unichr as six_unichr
681 from six.moves import xrange as six_xrange
685 from termcolor import colored
686 except ImportError: # pragma: no cover
687 def colored(what, *args, **kwargs):
733 "TagClassApplication",
737 "TagFormConstructed",
748 TagClassUniversal = 0
749 TagClassApplication = 1 << 6
750 TagClassContext = 1 << 7
751 TagClassPrivate = 1 << 6 | 1 << 7
753 TagFormConstructed = 1 << 5
756 TagClassApplication: "APPLICATION ",
757 TagClassPrivate: "PRIVATE ",
758 TagClassUniversal: "UNIV ",
762 LENINDEF = b"\x80" # length indefinite mark
763 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
766 ########################################################################
768 ########################################################################
770 class ASN1Error(ValueError):
774 class DecodeError(ASN1Error):
775 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
777 :param str msg: reason of decode failing
778 :param klass: optional exact DecodeError inherited class (like
779 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
780 :py:exc:`InvalidLength`)
781 :param decode_path: tuple of strings. It contains human
782 readable names of the fields through which
783 decoding process has passed
784 :param int offset: binary offset where failure happened
786 super(DecodeError, self).__init__()
789 self.decode_path = decode_path
795 "" if self.klass is None else self.klass.__name__,
797 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
798 if len(self.decode_path) > 0 else ""
800 ("(at %d)" % self.offset) if self.offset > 0 else "",
806 return "%s(%s)" % (self.__class__.__name__, self)
809 class NotEnoughData(DecodeError):
813 class ExceedingData(ASN1Error):
814 def __init__(self, nbytes):
815 super(ExceedingData, self).__init__()
819 return "%d trailing bytes" % self.nbytes
822 return "%s(%s)" % (self.__class__.__name__, self)
825 class LenIndefForm(DecodeError):
829 class TagMismatch(DecodeError):
833 class InvalidLength(DecodeError):
837 class InvalidOID(DecodeError):
841 class ObjUnknown(ASN1Error):
842 def __init__(self, name):
843 super(ObjUnknown, self).__init__()
847 return "object is unknown: %s" % self.name
850 return "%s(%s)" % (self.__class__.__name__, self)
853 class ObjNotReady(ASN1Error):
854 def __init__(self, name):
855 super(ObjNotReady, self).__init__()
859 return "object is not ready: %s" % self.name
862 return "%s(%s)" % (self.__class__.__name__, self)
865 class InvalidValueType(ASN1Error):
866 def __init__(self, expected_types):
867 super(InvalidValueType, self).__init__()
868 self.expected_types = expected_types
871 return "invalid value type, expected: %s" % ", ".join(
872 [repr(t) for t in self.expected_types]
876 return "%s(%s)" % (self.__class__.__name__, self)
879 class BoundsError(ASN1Error):
880 def __init__(self, bound_min, value, bound_max):
881 super(BoundsError, self).__init__()
882 self.bound_min = bound_min
884 self.bound_max = bound_max
887 return "unsatisfied bounds: %s <= %s <= %s" % (
894 return "%s(%s)" % (self.__class__.__name__, self)
897 ########################################################################
899 ########################################################################
901 _hexdecoder = getdecoder("hex")
902 _hexencoder = getencoder("hex")
906 """Binary data to hexadecimal string convert
908 return _hexdecoder(data)[0]
912 """Hexadecimal string to binary data convert
914 return _hexencoder(data)[0].decode("ascii")
917 def int_bytes_len(num, byte_len=8):
920 return int(ceil(float(num.bit_length()) / byte_len))
923 def zero_ended_encode(num):
924 octets = bytearray(int_bytes_len(num, 7))
926 octets[i] = num & 0x7F
930 octets[i] = 0x80 | (num & 0x7F)
936 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
937 """Encode tag to binary form
939 :param int num: tag's number
940 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
941 :py:data:`pyderasn.TagClassContext`,
942 :py:data:`pyderasn.TagClassApplication`,
943 :py:data:`pyderasn.TagClassPrivate`)
944 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
945 :py:data:`pyderasn.TagFormConstructed`)
949 return int2byte(klass | form | num)
950 # [XX|X|11111][1.......][1.......] ... [0.......]
951 return int2byte(klass | form | 31) + zero_ended_encode(num)
955 """Decode tag from binary form
959 No validation is performed, assuming that it has already passed.
961 It returns tuple with three integers, as
962 :py:func:`pyderasn.tag_encode` accepts.
964 first_octet = byte2int(tag)
965 klass = first_octet & 0xC0
966 form = first_octet & 0x20
967 if first_octet & 0x1F < 0x1F:
968 return (klass, form, first_octet & 0x1F)
970 for octet in iterbytes(tag[1:]):
973 return (klass, form, num)
977 """Create CONTEXT PRIMITIVE tag
979 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
983 """Create CONTEXT CONSTRUCTED tag
985 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
989 """Take off tag from the data
991 :returns: (encoded tag, tag length, remaining data)
994 raise NotEnoughData("no data at all")
995 if byte2int(data) & 0x1F < 31:
996 return data[:1], 1, data[1:]
1001 raise DecodeError("unfinished tag")
1002 if indexbytes(data, i) & 0x80 == 0:
1005 return data[:i], i, data[i:]
1011 octets = bytearray(int_bytes_len(l) + 1)
1012 octets[0] = 0x80 | (len(octets) - 1)
1013 for i in six_xrange(len(octets) - 1, 0, -1):
1014 octets[i] = l & 0xFF
1016 return bytes(octets)
1019 def len_decode(data):
1022 :returns: (decoded length, length's length, remaining data)
1023 :raises LenIndefForm: if indefinite form encoding is met
1026 raise NotEnoughData("no data at all")
1027 first_octet = byte2int(data)
1028 if first_octet & 0x80 == 0:
1029 return first_octet, 1, data[1:]
1030 octets_num = first_octet & 0x7F
1031 if octets_num + 1 > len(data):
1032 raise NotEnoughData("encoded length is longer than data")
1034 raise LenIndefForm()
1035 if byte2int(data[1:]) == 0:
1036 raise DecodeError("leading zeros")
1038 for v in iterbytes(data[1:1 + octets_num]):
1041 raise DecodeError("long form instead of short one")
1042 return l, 1 + octets_num, data[1 + octets_num:]
1045 ########################################################################
1047 ########################################################################
1049 class AutoAddSlots(type):
1050 def __new__(cls, name, bases, _dict):
1051 _dict["__slots__"] = _dict.get("__slots__", ())
1052 return type.__new__(cls, name, bases, _dict)
1055 @add_metaclass(AutoAddSlots)
1057 """Common ASN.1 object class
1059 All ASN.1 types are inherited from it. It has metaclass that
1060 automatically adds ``__slots__`` to all inherited classes.
1084 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1085 self._expl = getattr(self, "expl", None) if expl is None else expl
1086 if self.tag != self.tag_default and self._expl is not None:
1087 raise ValueError("implicit and explicit tags can not be set simultaneously")
1088 if default is not None:
1090 self.optional = optional
1091 self.offset, self.llen, self.vlen = _decoded
1093 self.expl_lenindef = False
1094 self.lenindef = False
1095 self.ber_encoded = False
1098 def ready(self): # pragma: no cover
1099 """Is object ready to be encoded?
1101 raise NotImplementedError()
1103 def _assert_ready(self):
1105 raise ObjNotReady(self.__class__.__name__)
1109 """Is either object or any elements inside is BER encoded?
1111 return self.expl_lenindef or self.lenindef or self.ber_encoded
1115 """Is object decoded?
1117 return (self.llen + self.vlen) > 0
1119 def __getstate__(self): # pragma: no cover
1120 """Used for making safe to be mutable pickleable copies
1122 raise NotImplementedError()
1124 def __setstate__(self, state):
1125 if state.version != __version__:
1126 raise ValueError("data is pickled by different PyDERASN version")
1127 self.tag = self.tag_default
1131 self.optional = False
1135 self.expl_lenindef = False
1136 self.lenindef = False
1137 self.ber_encoded = False
1141 """See :ref:`decoding`
1143 return len(self.tag)
1147 """See :ref:`decoding`
1149 return self.tlen + self.llen + self.vlen
1151 def __str__(self): # pragma: no cover
1152 return self.__bytes__() if PY2 else self.__unicode__()
1154 def __ne__(self, their):
1155 return not(self == their)
1157 def __gt__(self, their): # pragma: no cover
1158 return not(self < their)
1160 def __le__(self, their): # pragma: no cover
1161 return (self == their) or (self < their)
1163 def __ge__(self, their): # pragma: no cover
1164 return (self == their) or (self > their)
1166 def _encode(self): # pragma: no cover
1167 raise NotImplementedError()
1169 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1170 raise NotImplementedError()
1173 """Encode the structure
1175 :returns: DER representation
1177 raw = self._encode()
1178 if self._expl is None:
1180 return b"".join((self._expl, len_encode(len(raw)), raw))
1182 def hexencode(self):
1183 """Do hexadecimal encoded :py:meth:`pyderasn.Obj.encode`
1185 return hexenc(self.encode())
1195 _ctx_immutable=True,
1199 :param data: either binary or memoryview
1200 :param int offset: initial data's offset
1201 :param bool leavemm: do we need to leave memoryview of remaining
1202 data as is, or convert it to bytes otherwise
1203 :param ctx: optional :ref:`context <ctx>` governing decoding process
1204 :param tag_only: decode only the tag, without length and contents
1205 (used only in Choice and Set structures, trying to
1206 determine if tag satisfies the scheme)
1207 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1209 :returns: (Obj, remaining data)
1211 .. seealso:: :ref:`decoding`
1215 elif _ctx_immutable:
1217 tlv = memoryview(data)
1218 if self._expl is None:
1219 result = self._decode(
1222 decode_path=decode_path,
1231 t, tlen, lv = tag_strip(tlv)
1232 except DecodeError as err:
1233 raise err.__class__(
1235 klass=self.__class__,
1236 decode_path=decode_path,
1241 klass=self.__class__,
1242 decode_path=decode_path,
1246 l, llen, v = len_decode(lv)
1247 except LenIndefForm as err:
1248 if not ctx.get("bered", False):
1249 raise err.__class__(
1251 klass=self.__class__,
1252 decode_path=decode_path,
1256 offset += tlen + llen
1257 result = self._decode(
1260 decode_path=decode_path,
1264 if tag_only: # pragma: no cover
1267 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1268 if eoc_expected.tobytes() != EOC:
1271 klass=self.__class__,
1272 decode_path=decode_path,
1276 obj.expl_lenindef = True
1277 except DecodeError as err:
1278 raise err.__class__(
1280 klass=self.__class__,
1281 decode_path=decode_path,
1286 raise NotEnoughData(
1287 "encoded length is longer than data",
1288 klass=self.__class__,
1289 decode_path=decode_path,
1292 result = self._decode(
1294 offset=offset + tlen + llen,
1295 decode_path=decode_path,
1299 if tag_only: # pragma: no cover
1302 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1304 "explicit tag out-of-bound, longer than data",
1305 klass=self.__class__,
1306 decode_path=decode_path,
1309 return obj, (tail if leavemm else tail.tobytes())
1311 def decod(self, data, offset=0, decode_path=(), ctx=None):
1312 """Decode the data, check that tail is empty
1314 :raises ExceedingData: if tail is not empty
1316 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1317 (decode without tail) that also checks that there is no
1320 obj, tail = self.decode(
1323 decode_path=decode_path,
1328 raise ExceedingData(len(tail))
1331 def hexdecode(self, data, *args, **kwargs):
1332 """Do :py:meth:`pyderasn.Obj.decode` with hexadecimal decoded data
1334 return self.decode(hexdec(data), *args, **kwargs)
1336 def hexdecod(self, data, *args, **kwargs):
1337 """Do :py:meth:`pyderasn.Obj.decod` with hexadecimal decoded data
1339 return self.decod(hexdec(data), *args, **kwargs)
1343 """See :ref:`decoding`
1345 return self._expl is not None
1349 """See :ref:`decoding`
1354 def expl_tlen(self):
1355 """See :ref:`decoding`
1357 return len(self._expl)
1360 def expl_llen(self):
1361 """See :ref:`decoding`
1363 if self.expl_lenindef:
1365 return len(len_encode(self.tlvlen))
1368 def expl_offset(self):
1369 """See :ref:`decoding`
1371 return self.offset - self.expl_tlen - self.expl_llen
1374 def expl_vlen(self):
1375 """See :ref:`decoding`
1380 def expl_tlvlen(self):
1381 """See :ref:`decoding`
1383 return self.expl_tlen + self.expl_llen + self.expl_vlen
1386 def fulloffset(self):
1387 """See :ref:`decoding`
1389 return self.expl_offset if self.expled else self.offset
1393 """See :ref:`decoding`
1395 return self.expl_tlvlen if self.expled else self.tlvlen
1397 def pps_lenindef(self, decode_path):
1398 if self.lenindef and not (
1399 getattr(self, "defined", None) is not None and
1400 self.defined[1].lenindef
1403 asn1_type_name="EOC",
1405 decode_path=decode_path,
1407 self.offset + self.tlvlen -
1408 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1416 if self.expl_lenindef:
1418 asn1_type_name="EOC",
1419 obj_name="EXPLICIT",
1420 decode_path=decode_path,
1421 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1430 class DecodePathDefBy(object):
1431 """DEFINED BY representation inside decode path
1433 __slots__ = ("defined_by",)
1435 def __init__(self, defined_by):
1436 self.defined_by = defined_by
1438 def __ne__(self, their):
1439 return not(self == their)
1441 def __eq__(self, their):
1442 if not isinstance(their, self.__class__):
1444 return self.defined_by == their.defined_by
1447 return "DEFINED BY " + str(self.defined_by)
1450 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1453 ########################################################################
1455 ########################################################################
1457 PP = namedtuple("PP", (
1485 asn1_type_name="unknown",
1502 expl_lenindef=False,
1533 def _colourize(what, colour, with_colours, attrs=("bold",)):
1534 return colored(what, colour, attrs=attrs) if with_colours else what
1537 def colonize_hex(hexed):
1538 """Separate hexadecimal string with colons
1540 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1549 with_decode_path=False,
1550 decode_path_len_decrease=0,
1557 " " if pp.expl_offset is None else
1558 ("-%d" % (pp.offset - pp.expl_offset))
1560 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1562 col = _colourize(col, "red", with_colours, ())
1563 col += _colourize("B", "red", with_colours) if pp.bered else " "
1565 col = "[%d,%d,%4d]%s" % (
1569 LENINDEF_PP_CHAR if pp.lenindef else " "
1571 col = _colourize(col, "green", with_colours, ())
1573 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1574 if decode_path_len > 0:
1575 cols.append(" ." * decode_path_len)
1576 ent = pp.decode_path[-1]
1577 if isinstance(ent, DecodePathDefBy):
1578 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1579 value = str(ent.defined_by)
1582 len(oid_maps) > 0 and
1583 ent.defined_by.asn1_type_name ==
1584 ObjectIdentifier.asn1_type_name
1586 for oid_map in oid_maps:
1587 oid_name = oid_map.get(value)
1588 if oid_name is not None:
1589 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1591 if oid_name is None:
1592 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1594 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1595 if pp.expl is not None:
1596 klass, _, num = pp.expl
1597 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1598 cols.append(_colourize(col, "blue", with_colours))
1599 if pp.impl is not None:
1600 klass, _, num = pp.impl
1601 col = "[%s%d]" % (TagClassReprs[klass], num)
1602 cols.append(_colourize(col, "blue", with_colours))
1603 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1604 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1606 cols.append(_colourize("BER", "red", with_colours))
1607 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1608 if pp.value is not None:
1610 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1612 len(oid_maps) > 0 and
1613 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1615 for oid_map in oid_maps:
1616 oid_name = oid_map.get(value)
1617 if oid_name is not None:
1618 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1620 if pp.asn1_type_name == Integer.asn1_type_name:
1621 hex_repr = hex(int(pp.obj._value))[2:].upper()
1622 if len(hex_repr) % 2 != 0:
1623 hex_repr = "0" + hex_repr
1624 cols.append(_colourize(
1625 "(%s)" % colonize_hex(hex_repr),
1630 if isinstance(pp.blob, binary_type):
1631 cols.append(hexenc(pp.blob))
1632 elif isinstance(pp.blob, tuple):
1633 cols.append(", ".join(pp.blob))
1635 cols.append(_colourize("OPTIONAL", "red", with_colours))
1637 cols.append(_colourize("DEFAULT", "red", with_colours))
1638 if with_decode_path:
1639 cols.append(_colourize(
1640 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1644 return " ".join(cols)
1647 def pp_console_blob(pp, decode_path_len_decrease=0):
1648 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1649 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1650 if decode_path_len > 0:
1651 cols.append(" ." * (decode_path_len + 1))
1652 if isinstance(pp.blob, binary_type):
1653 blob = hexenc(pp.blob).upper()
1654 for i in six_xrange(0, len(blob), 32):
1655 chunk = blob[i:i + 32]
1656 yield " ".join(cols + [colonize_hex(chunk)])
1657 elif isinstance(pp.blob, tuple):
1658 yield " ".join(cols + [", ".join(pp.blob)])
1666 with_decode_path=False,
1667 decode_path_only=(),
1669 """Pretty print object
1671 :param Obj obj: object you want to pretty print
1672 :param oid_maps: list of ``OID <-> humand readable string`` dictionary.
1673 When OID from it is met, then its humand readable form
1675 :param big_blobs: if large binary objects are met (like OctetString
1676 values), do we need to print them too, on separate
1678 :param with_colours: colourize output, if ``termcolor`` library
1680 :param with_decode_path: print decode path
1681 :param decode_path_only: print only that specified decode path
1683 def _pprint_pps(pps):
1685 if hasattr(pp, "_fields"):
1687 decode_path_only != () and
1689 str(p) for p in pp.decode_path[:len(decode_path_only)]
1690 ) != decode_path_only
1694 yield pp_console_row(
1699 with_colours=with_colours,
1700 with_decode_path=with_decode_path,
1701 decode_path_len_decrease=len(decode_path_only),
1703 for row in pp_console_blob(
1705 decode_path_len_decrease=len(decode_path_only),
1709 yield pp_console_row(
1714 with_colours=with_colours,
1715 with_decode_path=with_decode_path,
1716 decode_path_len_decrease=len(decode_path_only),
1719 for row in _pprint_pps(pp):
1721 return "\n".join(_pprint_pps(obj.pps()))
1724 ########################################################################
1725 # ASN.1 primitive types
1726 ########################################################################
1728 BooleanState = namedtuple("BooleanState", (
1745 """``BOOLEAN`` boolean type
1747 >>> b = Boolean(True)
1749 >>> b == Boolean(True)
1755 tag_default = tag_encode(1)
1756 asn1_type_name = "BOOLEAN"
1768 :param value: set the value. Either boolean type, or
1769 :py:class:`pyderasn.Boolean` object
1770 :param bytes impl: override default tag with ``IMPLICIT`` one
1771 :param bytes expl: override default tag with ``EXPLICIT`` one
1772 :param default: set default value. Type same as in ``value``
1773 :param bool optional: is object ``OPTIONAL`` in sequence
1775 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1776 self._value = None if value is None else self._value_sanitize(value)
1777 if default is not None:
1778 default = self._value_sanitize(default)
1779 self.default = self.__class__(
1785 self._value = default
1787 def _value_sanitize(self, value):
1788 if isinstance(value, bool):
1790 if issubclass(value.__class__, Boolean):
1792 raise InvalidValueType((self.__class__, bool))
1796 return self._value is not None
1798 def __getstate__(self):
1799 return BooleanState(
1814 def __setstate__(self, state):
1815 super(Boolean, self).__setstate__(state)
1816 self._value = state.value
1817 self.tag = state.tag
1818 self._expl = state.expl
1819 self.default = state.default
1820 self.optional = state.optional
1821 self.offset = state.offset
1822 self.llen = state.llen
1823 self.vlen = state.vlen
1824 self.expl_lenindef = state.expl_lenindef
1825 self.lenindef = state.lenindef
1826 self.ber_encoded = state.ber_encoded
1828 def __nonzero__(self):
1829 self._assert_ready()
1833 self._assert_ready()
1836 def __eq__(self, their):
1837 if isinstance(their, bool):
1838 return self._value == their
1839 if not issubclass(their.__class__, Boolean):
1842 self._value == their._value and
1843 self.tag == their.tag and
1844 self._expl == their._expl
1855 return self.__class__(
1857 impl=self.tag if impl is None else impl,
1858 expl=self._expl if expl is None else expl,
1859 default=self.default if default is None else default,
1860 optional=self.optional if optional is None else optional,
1864 self._assert_ready()
1868 (b"\xFF" if self._value else b"\x00"),
1871 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1873 t, _, lv = tag_strip(tlv)
1874 except DecodeError as err:
1875 raise err.__class__(
1877 klass=self.__class__,
1878 decode_path=decode_path,
1883 klass=self.__class__,
1884 decode_path=decode_path,
1890 l, _, v = len_decode(lv)
1891 except DecodeError as err:
1892 raise err.__class__(
1894 klass=self.__class__,
1895 decode_path=decode_path,
1899 raise InvalidLength(
1900 "Boolean's length must be equal to 1",
1901 klass=self.__class__,
1902 decode_path=decode_path,
1906 raise NotEnoughData(
1907 "encoded length is longer than data",
1908 klass=self.__class__,
1909 decode_path=decode_path,
1912 first_octet = byte2int(v)
1914 if first_octet == 0:
1916 elif first_octet == 0xFF:
1918 elif ctx.get("bered", False):
1923 "unacceptable Boolean value",
1924 klass=self.__class__,
1925 decode_path=decode_path,
1928 obj = self.__class__(
1932 default=self.default,
1933 optional=self.optional,
1934 _decoded=(offset, 1, 1),
1936 obj.ber_encoded = ber_encoded
1940 return pp_console_row(next(self.pps()))
1942 def pps(self, decode_path=()):
1945 asn1_type_name=self.asn1_type_name,
1946 obj_name=self.__class__.__name__,
1947 decode_path=decode_path,
1948 value=str(self._value) if self.ready else None,
1949 optional=self.optional,
1950 default=self == self.default,
1951 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1952 expl=None if self._expl is None else tag_decode(self._expl),
1957 expl_offset=self.expl_offset if self.expled else None,
1958 expl_tlen=self.expl_tlen if self.expled else None,
1959 expl_llen=self.expl_llen if self.expled else None,
1960 expl_vlen=self.expl_vlen if self.expled else None,
1961 expl_lenindef=self.expl_lenindef,
1962 ber_encoded=self.ber_encoded,
1965 for pp in self.pps_lenindef(decode_path):
1969 IntegerState = namedtuple("IntegerState", (
1989 """``INTEGER`` integer type
1991 >>> b = Integer(-123)
1993 >>> b == Integer(-123)
1998 >>> Integer(2, bounds=(1, 3))
2000 >>> Integer(5, bounds=(1, 3))
2001 Traceback (most recent call last):
2002 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2006 class Version(Integer):
2013 >>> v = Version("v1")
2020 {'v3': 2, 'v1': 0, 'v2': 1}
2022 __slots__ = ("specs", "_bound_min", "_bound_max")
2023 tag_default = tag_encode(2)
2024 asn1_type_name = "INTEGER"
2038 :param value: set the value. Either integer type, named value
2039 (if ``schema`` is specified in the class), or
2040 :py:class:`pyderasn.Integer` object
2041 :param bounds: set ``(MIN, MAX)`` value constraint.
2042 (-inf, +inf) by default
2043 :param bytes impl: override default tag with ``IMPLICIT`` one
2044 :param bytes expl: override default tag with ``EXPLICIT`` one
2045 :param default: set default value. Type same as in ``value``
2046 :param bool optional: is object ``OPTIONAL`` in sequence
2048 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2050 specs = getattr(self, "schema", {}) if _specs is None else _specs
2051 self.specs = specs if isinstance(specs, dict) else dict(specs)
2052 self._bound_min, self._bound_max = getattr(
2055 (float("-inf"), float("+inf")),
2056 ) if bounds is None else bounds
2057 if value is not None:
2058 self._value = self._value_sanitize(value)
2059 if default is not None:
2060 default = self._value_sanitize(default)
2061 self.default = self.__class__(
2067 if self._value is None:
2068 self._value = default
2070 def _value_sanitize(self, value):
2071 if isinstance(value, integer_types):
2073 elif issubclass(value.__class__, Integer):
2074 value = value._value
2075 elif isinstance(value, str):
2076 value = self.specs.get(value)
2078 raise ObjUnknown("integer value: %s" % value)
2080 raise InvalidValueType((self.__class__, int, str))
2081 if not self._bound_min <= value <= self._bound_max:
2082 raise BoundsError(self._bound_min, value, self._bound_max)
2087 return self._value is not None
2089 def __getstate__(self):
2090 return IntegerState(
2108 def __setstate__(self, state):
2109 super(Integer, self).__setstate__(state)
2110 self.specs = state.specs
2111 self._value = state.value
2112 self._bound_min = state.bound_min
2113 self._bound_max = state.bound_max
2114 self.tag = state.tag
2115 self._expl = state.expl
2116 self.default = state.default
2117 self.optional = state.optional
2118 self.offset = state.offset
2119 self.llen = state.llen
2120 self.vlen = state.vlen
2121 self.expl_lenindef = state.expl_lenindef
2122 self.lenindef = state.lenindef
2123 self.ber_encoded = state.ber_encoded
2126 self._assert_ready()
2127 return int(self._value)
2130 self._assert_ready()
2133 bytes(self._expl or b"") +
2134 str(self._value).encode("ascii"),
2137 def __eq__(self, their):
2138 if isinstance(their, integer_types):
2139 return self._value == their
2140 if not issubclass(their.__class__, Integer):
2143 self._value == their._value and
2144 self.tag == their.tag and
2145 self._expl == their._expl
2148 def __lt__(self, their):
2149 return self._value < their._value
2153 for name, value in iteritems(self.specs):
2154 if value == self._value:
2167 return self.__class__(
2170 (self._bound_min, self._bound_max)
2171 if bounds is None else bounds
2173 impl=self.tag if impl is None else impl,
2174 expl=self._expl if expl is None else expl,
2175 default=self.default if default is None else default,
2176 optional=self.optional if optional is None else optional,
2181 self._assert_ready()
2185 octets = bytearray([0])
2189 octets = bytearray()
2191 octets.append((value & 0xFF) ^ 0xFF)
2193 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2196 octets = bytearray()
2198 octets.append(value & 0xFF)
2200 if octets[-1] & 0x80 > 0:
2203 octets = bytes(octets)
2205 bytes_len = ceil(value.bit_length() / 8) or 1
2208 octets = value.to_bytes(
2213 except OverflowError:
2217 return b"".join((self.tag, len_encode(len(octets)), octets))
2219 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2221 t, _, lv = tag_strip(tlv)
2222 except DecodeError as err:
2223 raise err.__class__(
2225 klass=self.__class__,
2226 decode_path=decode_path,
2231 klass=self.__class__,
2232 decode_path=decode_path,
2238 l, llen, v = len_decode(lv)
2239 except DecodeError as err:
2240 raise err.__class__(
2242 klass=self.__class__,
2243 decode_path=decode_path,
2247 raise NotEnoughData(
2248 "encoded length is longer than data",
2249 klass=self.__class__,
2250 decode_path=decode_path,
2254 raise NotEnoughData(
2256 klass=self.__class__,
2257 decode_path=decode_path,
2260 v, tail = v[:l], v[l:]
2261 first_octet = byte2int(v)
2263 second_octet = byte2int(v[1:])
2265 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2266 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2269 "non normalized integer",
2270 klass=self.__class__,
2271 decode_path=decode_path,
2276 if first_octet & 0x80 > 0:
2277 octets = bytearray()
2278 for octet in bytearray(v):
2279 octets.append(octet ^ 0xFF)
2280 for octet in octets:
2281 value = (value << 8) | octet
2285 for octet in bytearray(v):
2286 value = (value << 8) | octet
2288 value = int.from_bytes(v, byteorder="big", signed=True)
2290 obj = self.__class__(
2292 bounds=(self._bound_min, self._bound_max),
2295 default=self.default,
2296 optional=self.optional,
2298 _decoded=(offset, llen, l),
2300 except BoundsError as err:
2303 klass=self.__class__,
2304 decode_path=decode_path,
2310 return pp_console_row(next(self.pps()))
2312 def pps(self, decode_path=()):
2315 asn1_type_name=self.asn1_type_name,
2316 obj_name=self.__class__.__name__,
2317 decode_path=decode_path,
2318 value=(self.named or str(self._value)) if self.ready else None,
2319 optional=self.optional,
2320 default=self == self.default,
2321 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2322 expl=None if self._expl is None else tag_decode(self._expl),
2327 expl_offset=self.expl_offset if self.expled else None,
2328 expl_tlen=self.expl_tlen if self.expled else None,
2329 expl_llen=self.expl_llen if self.expled else None,
2330 expl_vlen=self.expl_vlen if self.expled else None,
2331 expl_lenindef=self.expl_lenindef,
2334 for pp in self.pps_lenindef(decode_path):
2338 SET01 = frozenset(("0", "1"))
2339 BitStringState = namedtuple("BitStringState", (
2358 class BitString(Obj):
2359 """``BIT STRING`` bit string type
2361 >>> BitString(b"hello world")
2362 BIT STRING 88 bits 68656c6c6f20776f726c64
2365 >>> b == b"hello world"
2370 >>> BitString("'0A3B5F291CD'H")
2371 BIT STRING 44 bits 0a3b5f291cd0
2372 >>> b = BitString("'010110000000'B")
2373 BIT STRING 12 bits 5800
2376 >>> b[0], b[1], b[2], b[3]
2377 (False, True, False, True)
2381 [False, True, False, True, True, False, False, False, False, False, False, False]
2385 class KeyUsage(BitString):
2387 ("digitalSignature", 0),
2388 ("nonRepudiation", 1),
2389 ("keyEncipherment", 2),
2392 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2393 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2395 ['nonRepudiation', 'keyEncipherment']
2397 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2401 Pay attention that BIT STRING can be encoded both in primitive
2402 and constructed forms. Decoder always checks constructed form tag
2403 additionally to specified primitive one. If BER decoding is
2404 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2405 of DER restrictions.
2407 __slots__ = ("tag_constructed", "specs", "defined")
2408 tag_default = tag_encode(3)
2409 asn1_type_name = "BIT STRING"
2422 :param value: set the value. Either binary type, tuple of named
2423 values (if ``schema`` is specified in the class),
2424 string in ``'XXX...'B`` form, or
2425 :py:class:`pyderasn.BitString` object
2426 :param bytes impl: override default tag with ``IMPLICIT`` one
2427 :param bytes expl: override default tag with ``EXPLICIT`` one
2428 :param default: set default value. Type same as in ``value``
2429 :param bool optional: is object ``OPTIONAL`` in sequence
2431 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2432 specs = getattr(self, "schema", {}) if _specs is None else _specs
2433 self.specs = specs if isinstance(specs, dict) else dict(specs)
2434 self._value = None if value is None else self._value_sanitize(value)
2435 if default is not None:
2436 default = self._value_sanitize(default)
2437 self.default = self.__class__(
2443 self._value = default
2445 tag_klass, _, tag_num = tag_decode(self.tag)
2446 self.tag_constructed = tag_encode(
2448 form=TagFormConstructed,
2452 def _bits2octets(self, bits):
2453 if len(self.specs) > 0:
2454 bits = bits.rstrip("0")
2456 bits += "0" * ((8 - (bit_len % 8)) % 8)
2457 octets = bytearray(len(bits) // 8)
2458 for i in six_xrange(len(octets)):
2459 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2460 return bit_len, bytes(octets)
2462 def _value_sanitize(self, value):
2463 if isinstance(value, (string_types, binary_type)):
2465 isinstance(value, string_types) and
2466 value.startswith("'")
2468 if value.endswith("'B"):
2470 if not frozenset(value) <= SET01:
2471 raise ValueError("B's coding contains unacceptable chars")
2472 return self._bits2octets(value)
2473 if value.endswith("'H"):
2477 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2479 if isinstance(value, binary_type):
2480 return (len(value) * 8, value)
2481 raise InvalidValueType((self.__class__, string_types, binary_type))
2482 if isinstance(value, tuple):
2485 isinstance(value[0], integer_types) and
2486 isinstance(value[1], binary_type)
2491 bit = self.specs.get(name)
2493 raise ObjUnknown("BitString value: %s" % name)
2496 return self._bits2octets("")
2497 bits = frozenset(bits)
2498 return self._bits2octets("".join(
2499 ("1" if bit in bits else "0")
2500 for bit in six_xrange(max(bits) + 1)
2502 if issubclass(value.__class__, BitString):
2504 raise InvalidValueType((self.__class__, binary_type, string_types))
2508 return self._value is not None
2510 def __getstate__(self):
2511 return BitStringState(
2525 self.tag_constructed,
2529 def __setstate__(self, state):
2530 super(BitString, self).__setstate__(state)
2531 self.specs = state.specs
2532 self._value = state.value
2533 self.tag = state.tag
2534 self._expl = state.expl
2535 self.default = state.default
2536 self.optional = state.optional
2537 self.offset = state.offset
2538 self.llen = state.llen
2539 self.vlen = state.vlen
2540 self.expl_lenindef = state.expl_lenindef
2541 self.lenindef = state.lenindef
2542 self.ber_encoded = state.ber_encoded
2543 self.tag_constructed = state.tag_constructed
2544 self.defined = state.defined
2547 self._assert_ready()
2548 for i in six_xrange(self._value[0]):
2553 self._assert_ready()
2554 return self._value[0]
2556 def __bytes__(self):
2557 self._assert_ready()
2558 return self._value[1]
2560 def __eq__(self, their):
2561 if isinstance(their, bytes):
2562 return self._value[1] == their
2563 if not issubclass(their.__class__, BitString):
2566 self._value == their._value and
2567 self.tag == their.tag and
2568 self._expl == their._expl
2573 return [name for name, bit in iteritems(self.specs) if self[bit]]
2583 return self.__class__(
2585 impl=self.tag if impl is None else impl,
2586 expl=self._expl if expl is None else expl,
2587 default=self.default if default is None else default,
2588 optional=self.optional if optional is None else optional,
2592 def __getitem__(self, key):
2593 if isinstance(key, int):
2594 bit_len, octets = self._value
2598 byte2int(memoryview(octets)[key // 8:]) >>
2601 if isinstance(key, string_types):
2602 value = self.specs.get(key)
2604 raise ObjUnknown("BitString value: %s" % key)
2606 raise InvalidValueType((int, str))
2609 self._assert_ready()
2610 bit_len, octets = self._value
2613 len_encode(len(octets) + 1),
2614 int2byte((8 - bit_len % 8) % 8),
2618 def _decode_chunk(self, lv, offset, decode_path):
2620 l, llen, v = len_decode(lv)
2621 except DecodeError as err:
2622 raise err.__class__(
2624 klass=self.__class__,
2625 decode_path=decode_path,
2629 raise NotEnoughData(
2630 "encoded length is longer than data",
2631 klass=self.__class__,
2632 decode_path=decode_path,
2636 raise NotEnoughData(
2638 klass=self.__class__,
2639 decode_path=decode_path,
2642 pad_size = byte2int(v)
2643 if l == 1 and pad_size != 0:
2645 "invalid empty value",
2646 klass=self.__class__,
2647 decode_path=decode_path,
2653 klass=self.__class__,
2654 decode_path=decode_path,
2657 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2660 klass=self.__class__,
2661 decode_path=decode_path,
2664 v, tail = v[:l], v[l:]
2665 obj = self.__class__(
2666 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2669 default=self.default,
2670 optional=self.optional,
2672 _decoded=(offset, llen, l),
2676 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2678 t, tlen, lv = tag_strip(tlv)
2679 except DecodeError as err:
2680 raise err.__class__(
2682 klass=self.__class__,
2683 decode_path=decode_path,
2687 if tag_only: # pragma: no cover
2689 return self._decode_chunk(lv, offset, decode_path)
2690 if t == self.tag_constructed:
2691 if not ctx.get("bered", False):
2693 "unallowed BER constructed encoding",
2694 klass=self.__class__,
2695 decode_path=decode_path,
2698 if tag_only: # pragma: no cover
2702 l, llen, v = len_decode(lv)
2703 except LenIndefForm:
2704 llen, l, v = 1, 0, lv[1:]
2706 except DecodeError as err:
2707 raise err.__class__(
2709 klass=self.__class__,
2710 decode_path=decode_path,
2714 raise NotEnoughData(
2715 "encoded length is longer than data",
2716 klass=self.__class__,
2717 decode_path=decode_path,
2720 if not lenindef and l == 0:
2721 raise NotEnoughData(
2723 klass=self.__class__,
2724 decode_path=decode_path,
2728 sub_offset = offset + tlen + llen
2732 if v[:EOC_LEN].tobytes() == EOC:
2739 "chunk out of bounds",
2740 klass=self.__class__,
2741 decode_path=decode_path + (str(len(chunks) - 1),),
2742 offset=chunks[-1].offset,
2744 sub_decode_path = decode_path + (str(len(chunks)),)
2746 chunk, v_tail = BitString().decode(
2749 decode_path=sub_decode_path,
2752 _ctx_immutable=False,
2756 "expected BitString encoded chunk",
2757 klass=self.__class__,
2758 decode_path=sub_decode_path,
2761 chunks.append(chunk)
2762 sub_offset += chunk.tlvlen
2763 vlen += chunk.tlvlen
2765 if len(chunks) == 0:
2768 klass=self.__class__,
2769 decode_path=decode_path,
2774 for chunk_i, chunk in enumerate(chunks[:-1]):
2775 if chunk.bit_len % 8 != 0:
2777 "BitString chunk is not multiple of 8 bits",
2778 klass=self.__class__,
2779 decode_path=decode_path + (str(chunk_i),),
2780 offset=chunk.offset,
2782 values.append(bytes(chunk))
2783 bit_len += chunk.bit_len
2784 chunk_last = chunks[-1]
2785 values.append(bytes(chunk_last))
2786 bit_len += chunk_last.bit_len
2787 obj = self.__class__(
2788 value=(bit_len, b"".join(values)),
2791 default=self.default,
2792 optional=self.optional,
2794 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2796 obj.lenindef = lenindef
2797 obj.ber_encoded = True
2798 return obj, (v[EOC_LEN:] if lenindef else v)
2800 klass=self.__class__,
2801 decode_path=decode_path,
2806 return pp_console_row(next(self.pps()))
2808 def pps(self, decode_path=()):
2812 bit_len, blob = self._value
2813 value = "%d bits" % bit_len
2814 if len(self.specs) > 0:
2815 blob = tuple(self.named)
2818 asn1_type_name=self.asn1_type_name,
2819 obj_name=self.__class__.__name__,
2820 decode_path=decode_path,
2823 optional=self.optional,
2824 default=self == self.default,
2825 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2826 expl=None if self._expl is None else tag_decode(self._expl),
2831 expl_offset=self.expl_offset if self.expled else None,
2832 expl_tlen=self.expl_tlen if self.expled else None,
2833 expl_llen=self.expl_llen if self.expled else None,
2834 expl_vlen=self.expl_vlen if self.expled else None,
2835 expl_lenindef=self.expl_lenindef,
2836 lenindef=self.lenindef,
2837 ber_encoded=self.ber_encoded,
2840 defined_by, defined = self.defined or (None, None)
2841 if defined_by is not None:
2843 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2845 for pp in self.pps_lenindef(decode_path):
2849 OctetStringState = namedtuple("OctetStringState", (
2869 class OctetString(Obj):
2870 """``OCTET STRING`` binary string type
2872 >>> s = OctetString(b"hello world")
2873 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2874 >>> s == OctetString(b"hello world")
2879 >>> OctetString(b"hello", bounds=(4, 4))
2880 Traceback (most recent call last):
2881 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2882 >>> OctetString(b"hell", bounds=(4, 4))
2883 OCTET STRING 4 bytes 68656c6c
2887 Pay attention that OCTET STRING can be encoded both in primitive
2888 and constructed forms. Decoder always checks constructed form tag
2889 additionally to specified primitive one. If BER decoding is
2890 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2891 of DER restrictions.
2893 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2894 tag_default = tag_encode(4)
2895 asn1_type_name = "OCTET STRING"
2908 :param value: set the value. Either binary type, or
2909 :py:class:`pyderasn.OctetString` object
2910 :param bounds: set ``(MIN, MAX)`` value size constraint.
2911 (-inf, +inf) by default
2912 :param bytes impl: override default tag with ``IMPLICIT`` one
2913 :param bytes expl: override default tag with ``EXPLICIT`` one
2914 :param default: set default value. Type same as in ``value``
2915 :param bool optional: is object ``OPTIONAL`` in sequence
2917 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2919 self._bound_min, self._bound_max = getattr(
2923 ) if bounds is None else bounds
2924 if value is not None:
2925 self._value = self._value_sanitize(value)
2926 if default is not None:
2927 default = self._value_sanitize(default)
2928 self.default = self.__class__(
2933 if self._value is None:
2934 self._value = default
2936 tag_klass, _, tag_num = tag_decode(self.tag)
2937 self.tag_constructed = tag_encode(
2939 form=TagFormConstructed,
2943 def _value_sanitize(self, value):
2944 if isinstance(value, binary_type):
2946 elif issubclass(value.__class__, OctetString):
2947 value = value._value
2949 raise InvalidValueType((self.__class__, bytes))
2950 if not self._bound_min <= len(value) <= self._bound_max:
2951 raise BoundsError(self._bound_min, len(value), self._bound_max)
2956 return self._value is not None
2958 def __getstate__(self):
2959 return OctetStringState(
2974 self.tag_constructed,
2978 def __setstate__(self, state):
2979 super(OctetString, self).__setstate__(state)
2980 self._value = state.value
2981 self._bound_min = state.bound_min
2982 self._bound_max = state.bound_max
2983 self.tag = state.tag
2984 self._expl = state.expl
2985 self.default = state.default
2986 self.optional = state.optional
2987 self.offset = state.offset
2988 self.llen = state.llen
2989 self.vlen = state.vlen
2990 self.expl_lenindef = state.expl_lenindef
2991 self.lenindef = state.lenindef
2992 self.ber_encoded = state.ber_encoded
2993 self.tag_constructed = state.tag_constructed
2994 self.defined = state.defined
2996 def __bytes__(self):
2997 self._assert_ready()
3000 def __eq__(self, their):
3001 if isinstance(their, binary_type):
3002 return self._value == their
3003 if not issubclass(their.__class__, OctetString):
3006 self._value == their._value and
3007 self.tag == their.tag and
3008 self._expl == their._expl
3011 def __lt__(self, their):
3012 return self._value < their._value
3023 return self.__class__(
3026 (self._bound_min, self._bound_max)
3027 if bounds is None else bounds
3029 impl=self.tag if impl is None else impl,
3030 expl=self._expl if expl is None else expl,
3031 default=self.default if default is None else default,
3032 optional=self.optional if optional is None else optional,
3036 self._assert_ready()
3039 len_encode(len(self._value)),
3043 def _decode_chunk(self, lv, offset, decode_path):
3045 l, llen, v = len_decode(lv)
3046 except DecodeError as err:
3047 raise err.__class__(
3049 klass=self.__class__,
3050 decode_path=decode_path,
3054 raise NotEnoughData(
3055 "encoded length is longer than data",
3056 klass=self.__class__,
3057 decode_path=decode_path,
3060 v, tail = v[:l], v[l:]
3062 obj = self.__class__(
3064 bounds=(self._bound_min, self._bound_max),
3067 default=self.default,
3068 optional=self.optional,
3069 _decoded=(offset, llen, l),
3071 except DecodeError as err:
3074 klass=self.__class__,
3075 decode_path=decode_path,
3078 except BoundsError as err:
3081 klass=self.__class__,
3082 decode_path=decode_path,
3087 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3089 t, tlen, lv = tag_strip(tlv)
3090 except DecodeError as err:
3091 raise err.__class__(
3093 klass=self.__class__,
3094 decode_path=decode_path,
3100 return self._decode_chunk(lv, offset, decode_path)
3101 if t == self.tag_constructed:
3102 if not ctx.get("bered", False):
3104 "unallowed BER constructed encoding",
3105 klass=self.__class__,
3106 decode_path=decode_path,
3113 l, llen, v = len_decode(lv)
3114 except LenIndefForm:
3115 llen, l, v = 1, 0, lv[1:]
3117 except DecodeError as err:
3118 raise err.__class__(
3120 klass=self.__class__,
3121 decode_path=decode_path,
3125 raise NotEnoughData(
3126 "encoded length is longer than data",
3127 klass=self.__class__,
3128 decode_path=decode_path,
3132 sub_offset = offset + tlen + llen
3136 if v[:EOC_LEN].tobytes() == EOC:
3143 "chunk out of bounds",
3144 klass=self.__class__,
3145 decode_path=decode_path + (str(len(chunks) - 1),),
3146 offset=chunks[-1].offset,
3148 sub_decode_path = decode_path + (str(len(chunks)),)
3150 chunk, v_tail = OctetString().decode(
3153 decode_path=sub_decode_path,
3156 _ctx_immutable=False,
3160 "expected OctetString encoded chunk",
3161 klass=self.__class__,
3162 decode_path=sub_decode_path,
3165 chunks.append(chunk)
3166 sub_offset += chunk.tlvlen
3167 vlen += chunk.tlvlen
3170 obj = self.__class__(
3171 value=b"".join(bytes(chunk) for chunk in chunks),
3172 bounds=(self._bound_min, self._bound_max),
3175 default=self.default,
3176 optional=self.optional,
3177 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3179 except DecodeError as err:
3182 klass=self.__class__,
3183 decode_path=decode_path,
3186 except BoundsError as err:
3189 klass=self.__class__,
3190 decode_path=decode_path,
3193 obj.lenindef = lenindef
3194 obj.ber_encoded = True
3195 return obj, (v[EOC_LEN:] if lenindef else v)
3197 klass=self.__class__,
3198 decode_path=decode_path,
3203 return pp_console_row(next(self.pps()))
3205 def pps(self, decode_path=()):
3208 asn1_type_name=self.asn1_type_name,
3209 obj_name=self.__class__.__name__,
3210 decode_path=decode_path,
3211 value=("%d bytes" % len(self._value)) if self.ready else None,
3212 blob=self._value if self.ready else None,
3213 optional=self.optional,
3214 default=self == self.default,
3215 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3216 expl=None if self._expl is None else tag_decode(self._expl),
3221 expl_offset=self.expl_offset if self.expled else None,
3222 expl_tlen=self.expl_tlen if self.expled else None,
3223 expl_llen=self.expl_llen if self.expled else None,
3224 expl_vlen=self.expl_vlen if self.expled else None,
3225 expl_lenindef=self.expl_lenindef,
3226 lenindef=self.lenindef,
3227 ber_encoded=self.ber_encoded,
3230 defined_by, defined = self.defined or (None, None)
3231 if defined_by is not None:
3233 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3235 for pp in self.pps_lenindef(decode_path):
3239 NullState = namedtuple("NullState", (
3255 """``NULL`` null object
3263 tag_default = tag_encode(5)
3264 asn1_type_name = "NULL"
3268 value=None, # unused, but Sequence passes it
3275 :param bytes impl: override default tag with ``IMPLICIT`` one
3276 :param bytes expl: override default tag with ``EXPLICIT`` one
3277 :param bool optional: is object ``OPTIONAL`` in sequence
3279 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3286 def __getstate__(self):
3301 def __setstate__(self, state):
3302 super(Null, self).__setstate__(state)
3303 self.tag = state.tag
3304 self._expl = state.expl
3305 self.default = state.default
3306 self.optional = state.optional
3307 self.offset = state.offset
3308 self.llen = state.llen
3309 self.vlen = state.vlen
3310 self.expl_lenindef = state.expl_lenindef
3311 self.lenindef = state.lenindef
3312 self.ber_encoded = state.ber_encoded
3314 def __eq__(self, their):
3315 if not issubclass(their.__class__, Null):
3318 self.tag == their.tag and
3319 self._expl == their._expl
3329 return self.__class__(
3330 impl=self.tag if impl is None else impl,
3331 expl=self._expl if expl is None else expl,
3332 optional=self.optional if optional is None else optional,
3336 return self.tag + len_encode(0)
3338 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3340 t, _, lv = tag_strip(tlv)
3341 except DecodeError as err:
3342 raise err.__class__(
3344 klass=self.__class__,
3345 decode_path=decode_path,
3350 klass=self.__class__,
3351 decode_path=decode_path,
3354 if tag_only: # pragma: no cover
3357 l, _, v = len_decode(lv)
3358 except DecodeError as err:
3359 raise err.__class__(
3361 klass=self.__class__,
3362 decode_path=decode_path,
3366 raise InvalidLength(
3367 "Null must have zero length",
3368 klass=self.__class__,
3369 decode_path=decode_path,
3372 obj = self.__class__(
3375 optional=self.optional,
3376 _decoded=(offset, 1, 0),
3381 return pp_console_row(next(self.pps()))
3383 def pps(self, decode_path=()):
3386 asn1_type_name=self.asn1_type_name,
3387 obj_name=self.__class__.__name__,
3388 decode_path=decode_path,
3389 optional=self.optional,
3390 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3391 expl=None if self._expl is None else tag_decode(self._expl),
3396 expl_offset=self.expl_offset if self.expled else None,
3397 expl_tlen=self.expl_tlen if self.expled else None,
3398 expl_llen=self.expl_llen if self.expled else None,
3399 expl_vlen=self.expl_vlen if self.expled else None,
3400 expl_lenindef=self.expl_lenindef,
3403 for pp in self.pps_lenindef(decode_path):
3407 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3424 class ObjectIdentifier(Obj):
3425 """``OBJECT IDENTIFIER`` OID type
3427 >>> oid = ObjectIdentifier((1, 2, 3))
3428 OBJECT IDENTIFIER 1.2.3
3429 >>> oid == ObjectIdentifier("1.2.3")
3435 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3436 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3438 >>> str(ObjectIdentifier((3, 1)))
3439 Traceback (most recent call last):
3440 pyderasn.InvalidOID: unacceptable first arc value
3442 __slots__ = ("defines",)
3443 tag_default = tag_encode(6)
3444 asn1_type_name = "OBJECT IDENTIFIER"
3457 :param value: set the value. Either tuples of integers,
3458 string of "."-concatenated integers, or
3459 :py:class:`pyderasn.ObjectIdentifier` object
3460 :param defines: sequence of tuples. Each tuple has two elements.
3461 First one is relative to current one decode
3462 path, aiming to the field defined by that OID.
3463 Read about relative path in
3464 :py:func:`pyderasn.abs_decode_path`. Second
3465 tuple element is ``{OID: pyderasn.Obj()}``
3466 dictionary, mapping between current OID value
3467 and structure applied to defined field.
3468 :ref:`Read about DEFINED BY <definedby>`
3469 :param bytes impl: override default tag with ``IMPLICIT`` one
3470 :param bytes expl: override default tag with ``EXPLICIT`` one
3471 :param default: set default value. Type same as in ``value``
3472 :param bool optional: is object ``OPTIONAL`` in sequence
3474 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3476 if value is not None:
3477 self._value = self._value_sanitize(value)
3478 if default is not None:
3479 default = self._value_sanitize(default)
3480 self.default = self.__class__(
3485 if self._value is None:
3486 self._value = default
3487 self.defines = defines
3489 def __add__(self, their):
3490 if isinstance(their, self.__class__):
3491 return self.__class__(self._value + their._value)
3492 if isinstance(their, tuple):
3493 return self.__class__(self._value + their)
3494 raise InvalidValueType((self.__class__, tuple))
3496 def _value_sanitize(self, value):
3497 if issubclass(value.__class__, ObjectIdentifier):
3499 if isinstance(value, string_types):
3501 value = tuple(int(arc) for arc in value.split("."))
3503 raise InvalidOID("unacceptable arcs values")
3504 if isinstance(value, tuple):
3506 raise InvalidOID("less than 2 arcs")
3507 first_arc = value[0]
3508 if first_arc in (0, 1):
3509 if not (0 <= value[1] <= 39):
3510 raise InvalidOID("second arc is too wide")
3511 elif first_arc == 2:
3514 raise InvalidOID("unacceptable first arc value")
3516 raise InvalidValueType((self.__class__, str, tuple))
3520 return self._value is not None
3522 def __getstate__(self):
3523 return ObjectIdentifierState(
3539 def __setstate__(self, state):
3540 super(ObjectIdentifier, self).__setstate__(state)
3541 self._value = state.value
3542 self.tag = state.tag
3543 self._expl = state.expl
3544 self.default = state.default
3545 self.optional = state.optional
3546 self.offset = state.offset
3547 self.llen = state.llen
3548 self.vlen = state.vlen
3549 self.expl_lenindef = state.expl_lenindef
3550 self.lenindef = state.lenindef
3551 self.ber_encoded = state.ber_encoded
3552 self.defines = state.defines
3555 self._assert_ready()
3556 return iter(self._value)
3559 return ".".join(str(arc) for arc in self._value or ())
3562 self._assert_ready()
3565 bytes(self._expl or b"") +
3566 str(self._value).encode("ascii"),
3569 def __eq__(self, their):
3570 if isinstance(their, tuple):
3571 return self._value == their
3572 if not issubclass(their.__class__, ObjectIdentifier):
3575 self.tag == their.tag and
3576 self._expl == their._expl and
3577 self._value == their._value
3580 def __lt__(self, their):
3581 return self._value < their._value
3592 return self.__class__(
3594 defines=self.defines if defines is None else defines,
3595 impl=self.tag if impl is None else impl,
3596 expl=self._expl if expl is None else expl,
3597 default=self.default if default is None else default,
3598 optional=self.optional if optional is None else optional,
3602 self._assert_ready()
3604 first_value = value[1]
3605 first_arc = value[0]
3608 elif first_arc == 1:
3610 elif first_arc == 2:
3612 else: # pragma: no cover
3613 raise RuntimeError("invalid arc is stored")
3614 octets = [zero_ended_encode(first_value)]
3615 for arc in value[2:]:
3616 octets.append(zero_ended_encode(arc))
3617 v = b"".join(octets)
3618 return b"".join((self.tag, len_encode(len(v)), v))
3620 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3622 t, _, lv = tag_strip(tlv)
3623 except DecodeError as err:
3624 raise err.__class__(
3626 klass=self.__class__,
3627 decode_path=decode_path,
3632 klass=self.__class__,
3633 decode_path=decode_path,
3636 if tag_only: # pragma: no cover
3639 l, llen, v = len_decode(lv)
3640 except DecodeError as err:
3641 raise err.__class__(
3643 klass=self.__class__,
3644 decode_path=decode_path,
3648 raise NotEnoughData(
3649 "encoded length is longer than data",
3650 klass=self.__class__,
3651 decode_path=decode_path,
3655 raise NotEnoughData(
3657 klass=self.__class__,
3658 decode_path=decode_path,
3661 v, tail = v[:l], v[l:]
3668 octet = indexbytes(v, i)
3669 if i == 0 and octet == 0x80:
3670 if ctx.get("bered", False):
3673 raise DecodeError("non normalized arc encoding")
3674 arc = (arc << 7) | (octet & 0x7F)
3675 if octet & 0x80 == 0:
3683 klass=self.__class__,
3684 decode_path=decode_path,
3688 second_arc = arcs[0]
3689 if 0 <= second_arc <= 39:
3691 elif 40 <= second_arc <= 79:
3697 obj = self.__class__(
3698 value=tuple([first_arc, second_arc] + arcs[1:]),
3701 default=self.default,
3702 optional=self.optional,
3703 _decoded=(offset, llen, l),
3706 obj.ber_encoded = True
3710 return pp_console_row(next(self.pps()))
3712 def pps(self, decode_path=()):
3715 asn1_type_name=self.asn1_type_name,
3716 obj_name=self.__class__.__name__,
3717 decode_path=decode_path,
3718 value=str(self) if self.ready else None,
3719 optional=self.optional,
3720 default=self == self.default,
3721 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3722 expl=None if self._expl is None else tag_decode(self._expl),
3727 expl_offset=self.expl_offset if self.expled else None,
3728 expl_tlen=self.expl_tlen if self.expled else None,
3729 expl_llen=self.expl_llen if self.expled else None,
3730 expl_vlen=self.expl_vlen if self.expled else None,
3731 expl_lenindef=self.expl_lenindef,
3732 ber_encoded=self.ber_encoded,
3735 for pp in self.pps_lenindef(decode_path):
3739 class Enumerated(Integer):
3740 """``ENUMERATED`` integer type
3742 This type is identical to :py:class:`pyderasn.Integer`, but requires
3743 schema to be specified and does not accept values missing from it.
3746 tag_default = tag_encode(10)
3747 asn1_type_name = "ENUMERATED"
3758 bounds=None, # dummy argument, workability for Integer.decode
3760 super(Enumerated, self).__init__(
3761 value, bounds, impl, expl, default, optional, _specs, _decoded,
3763 if len(self.specs) == 0:
3764 raise ValueError("schema must be specified")
3766 def _value_sanitize(self, value):
3767 if isinstance(value, self.__class__):
3768 value = value._value
3769 elif isinstance(value, integer_types):
3770 for _value in itervalues(self.specs):
3775 "unknown integer value: %s" % value,
3776 klass=self.__class__,
3778 elif isinstance(value, string_types):
3779 value = self.specs.get(value)
3781 raise ObjUnknown("integer value: %s" % value)
3783 raise InvalidValueType((self.__class__, int, str))
3795 return self.__class__(
3797 impl=self.tag if impl is None else impl,
3798 expl=self._expl if expl is None else expl,
3799 default=self.default if default is None else default,
3800 optional=self.optional if optional is None else optional,
3805 def escape_control_unicode(c):
3806 if unicat(c).startswith("C"):
3807 c = repr(c).lstrip("u").strip("'")
3811 class CommonString(OctetString):
3812 """Common class for all strings
3814 Everything resembles :py:class:`pyderasn.OctetString`, except
3815 ability to deal with unicode text strings.
3817 >>> hexenc("привет мир".encode("utf-8"))
3818 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3819 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3821 >>> s = UTF8String("привет мир")
3822 UTF8String UTF8String привет мир
3824 'привет мир'
3825 >>> hexenc(bytes(s))
3826 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3828 >>> PrintableString("привет мир")
3829 Traceback (most recent call last):
3830 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3832 >>> BMPString("ада", bounds=(2, 2))
3833 Traceback (most recent call last):
3834 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3835 >>> s = BMPString("ад", bounds=(2, 2))
3838 >>> hexenc(bytes(s))
3846 * - :py:class:`pyderasn.UTF8String`
3848 * - :py:class:`pyderasn.NumericString`
3850 * - :py:class:`pyderasn.PrintableString`
3852 * - :py:class:`pyderasn.TeletexString`
3854 * - :py:class:`pyderasn.T61String`
3856 * - :py:class:`pyderasn.VideotexString`
3858 * - :py:class:`pyderasn.IA5String`
3860 * - :py:class:`pyderasn.GraphicString`
3862 * - :py:class:`pyderasn.VisibleString`
3864 * - :py:class:`pyderasn.ISO646String`
3866 * - :py:class:`pyderasn.GeneralString`
3868 * - :py:class:`pyderasn.UniversalString`
3870 * - :py:class:`pyderasn.BMPString`
3875 def _value_sanitize(self, value):
3877 value_decoded = None
3878 if isinstance(value, self.__class__):
3879 value_raw = value._value
3880 elif isinstance(value, text_type):
3881 value_decoded = value
3882 elif isinstance(value, binary_type):
3885 raise InvalidValueType((self.__class__, text_type, binary_type))
3888 value_decoded.encode(self.encoding)
3889 if value_raw is None else value_raw
3892 value_raw.decode(self.encoding)
3893 if value_decoded is None else value_decoded
3895 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3896 raise DecodeError(str(err))
3897 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3905 def __eq__(self, their):
3906 if isinstance(their, binary_type):
3907 return self._value == their
3908 if isinstance(their, text_type):
3909 return self._value == their.encode(self.encoding)
3910 if not isinstance(their, self.__class__):
3913 self._value == their._value and
3914 self.tag == their.tag and
3915 self._expl == their._expl
3918 def __unicode__(self):
3920 return self._value.decode(self.encoding)
3921 return text_type(self._value)
3924 return pp_console_row(next(self.pps(no_unicode=PY2)))
3926 def pps(self, decode_path=(), no_unicode=False):
3930 hexenc(bytes(self)) if no_unicode else
3931 "".join(escape_control_unicode(c) for c in self.__unicode__())
3935 asn1_type_name=self.asn1_type_name,
3936 obj_name=self.__class__.__name__,
3937 decode_path=decode_path,
3939 optional=self.optional,
3940 default=self == self.default,
3941 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3942 expl=None if self._expl is None else tag_decode(self._expl),
3947 expl_offset=self.expl_offset if self.expled else None,
3948 expl_tlen=self.expl_tlen if self.expled else None,
3949 expl_llen=self.expl_llen if self.expled else None,
3950 expl_vlen=self.expl_vlen if self.expled else None,
3951 expl_lenindef=self.expl_lenindef,
3952 ber_encoded=self.ber_encoded,
3955 for pp in self.pps_lenindef(decode_path):
3959 class UTF8String(CommonString):
3961 tag_default = tag_encode(12)
3963 asn1_type_name = "UTF8String"
3966 class AllowableCharsMixin(object):
3968 def allowable_chars(self):
3970 return self._allowable_chars
3971 return frozenset(six_unichr(c) for c in self._allowable_chars)
3974 class NumericString(AllowableCharsMixin, CommonString):
3977 Its value is properly sanitized: only ASCII digits with spaces can
3980 >>> NumericString().allowable_chars
3981 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3984 tag_default = tag_encode(18)
3986 asn1_type_name = "NumericString"
3987 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3989 def _value_sanitize(self, value):
3990 value = super(NumericString, self)._value_sanitize(value)
3991 if not frozenset(value) <= self._allowable_chars:
3992 raise DecodeError("non-numeric value")
3996 PrintableStringState = namedtuple(
3997 "PrintableStringState",
3998 OctetStringState._fields + ("allowable_chars",),
4002 class PrintableString(AllowableCharsMixin, CommonString):
4005 Its value is properly sanitized: see X.680 41.4 table 10.
4007 >>> PrintableString().allowable_chars
4008 frozenset([' ', "'", ..., 'z'])
4009 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4010 PrintableString PrintableString foo*bar
4011 >>> obj.allow_asterisk, obj.allow_ampersand
4015 tag_default = tag_encode(19)
4017 asn1_type_name = "PrintableString"
4018 _allowable_chars = frozenset(
4019 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4021 _asterisk = frozenset("*".encode("ascii"))
4022 _ampersand = frozenset("&".encode("ascii"))
4033 allow_asterisk=False,
4034 allow_ampersand=False,
4037 :param allow_asterisk: allow asterisk character
4038 :param allow_ampersand: allow ampersand character
4041 self._allowable_chars |= self._asterisk
4043 self._allowable_chars |= self._ampersand
4044 super(PrintableString, self).__init__(
4045 value, bounds, impl, expl, default, optional, _decoded,
4049 def allow_asterisk(self):
4050 """Is asterisk character allowed?
4052 return self._asterisk <= self._allowable_chars
4055 def allow_ampersand(self):
4056 """Is ampersand character allowed?
4058 return self._ampersand <= self._allowable_chars
4060 def _value_sanitize(self, value):
4061 value = super(PrintableString, self)._value_sanitize(value)
4062 if not frozenset(value) <= self._allowable_chars:
4063 raise DecodeError("non-printable value")
4066 def __getstate__(self):
4067 return PrintableStringState(
4068 *super(PrintableString, self).__getstate__(),
4069 **{"allowable_chars": self._allowable_chars}
4072 def __setstate__(self, state):
4073 super(PrintableString, self).__setstate__(state)
4074 self._allowable_chars = state.allowable_chars
4085 return self.__class__(
4088 (self._bound_min, self._bound_max)
4089 if bounds is None else bounds
4091 impl=self.tag if impl is None else impl,
4092 expl=self._expl if expl is None else expl,
4093 default=self.default if default is None else default,
4094 optional=self.optional if optional is None else optional,
4095 allow_asterisk=self.allow_asterisk,
4096 allow_ampersand=self.allow_ampersand,
4100 class TeletexString(CommonString):
4102 tag_default = tag_encode(20)
4104 asn1_type_name = "TeletexString"
4107 class T61String(TeletexString):
4109 asn1_type_name = "T61String"
4112 class VideotexString(CommonString):
4114 tag_default = tag_encode(21)
4115 encoding = "iso-8859-1"
4116 asn1_type_name = "VideotexString"
4119 class IA5String(CommonString):
4121 tag_default = tag_encode(22)
4123 asn1_type_name = "IA5"
4126 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4127 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4128 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4131 class UTCTime(CommonString):
4132 """``UTCTime`` datetime type
4134 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4135 UTCTime UTCTime 2017-09-30T22:07:50
4141 datetime.datetime(2017, 9, 30, 22, 7, 50)
4142 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4143 datetime.datetime(1957, 9, 30, 22, 7, 50)
4147 BER encoding is unsupported.
4150 tag_default = tag_encode(23)
4152 asn1_type_name = "UTCTime"
4162 bounds=None, # dummy argument, workability for OctetString.decode
4165 :param value: set the value. Either datetime type, or
4166 :py:class:`pyderasn.UTCTime` object
4167 :param bytes impl: override default tag with ``IMPLICIT`` one
4168 :param bytes expl: override default tag with ``EXPLICIT`` one
4169 :param default: set default value. Type same as in ``value``
4170 :param bool optional: is object ``OPTIONAL`` in sequence
4172 super(UTCTime, self).__init__(
4173 None, None, impl, expl, default, optional, _decoded,
4176 if value is not None:
4177 self._value = self._value_sanitize(value)
4178 if default is not None:
4179 default = self._value_sanitize(default)
4180 self.default = self.__class__(
4185 if self._value is None:
4186 self._value = default
4188 def _strptime(self, value):
4189 # datetime.strptime's format: %y%m%d%H%M%SZ
4190 if len(value) != LEN_YYMMDDHHMMSSZ:
4191 raise ValueError("invalid UTCTime length")
4192 if value[-1] != "Z":
4193 raise ValueError("non UTC timezone")
4195 2000 + int(value[:2]), # %y
4196 int(value[2:4]), # %m
4197 int(value[4:6]), # %d
4198 int(value[6:8]), # %H
4199 int(value[8:10]), # %M
4200 int(value[10:12]), # %S
4203 def _value_sanitize(self, value):
4204 if isinstance(value, binary_type):
4206 value_decoded = value.decode("ascii")
4207 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4208 raise DecodeError("invalid UTCTime encoding: %r" % err)
4210 self._strptime(value_decoded)
4211 except (TypeError, ValueError) as err:
4212 raise DecodeError("invalid UTCTime format: %r" % err)
4214 if isinstance(value, self.__class__):
4216 if isinstance(value, datetime):
4217 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4218 raise InvalidValueType((self.__class__, datetime))
4220 def __eq__(self, their):
4221 if isinstance(their, binary_type):
4222 return self._value == their
4223 if isinstance(their, datetime):
4224 return self.todatetime() == their
4225 if not isinstance(their, self.__class__):
4228 self._value == their._value and
4229 self.tag == their.tag and
4230 self._expl == their._expl
4233 def todatetime(self):
4234 """Convert to datetime
4238 Pay attention that UTCTime can not hold full year, so all years
4239 having < 50 years are treated as 20xx, 19xx otherwise, according
4240 to X.509 recomendation.
4242 value = self._strptime(self._value.decode("ascii"))
4243 year = value.year % 100
4245 year=(2000 + year) if year < 50 else (1900 + year),
4249 minute=value.minute,
4250 second=value.second,
4254 return pp_console_row(next(self.pps()))
4256 def pps(self, decode_path=()):
4259 asn1_type_name=self.asn1_type_name,
4260 obj_name=self.__class__.__name__,
4261 decode_path=decode_path,
4262 value=self.todatetime().isoformat() if self.ready else None,
4263 optional=self.optional,
4264 default=self == self.default,
4265 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4266 expl=None if self._expl is None else tag_decode(self._expl),
4271 expl_offset=self.expl_offset if self.expled else None,
4272 expl_tlen=self.expl_tlen if self.expled else None,
4273 expl_llen=self.expl_llen if self.expled else None,
4274 expl_vlen=self.expl_vlen if self.expled else None,
4275 expl_lenindef=self.expl_lenindef,
4276 ber_encoded=self.ber_encoded,
4279 for pp in self.pps_lenindef(decode_path):
4283 class GeneralizedTime(UTCTime):
4284 """``GeneralizedTime`` datetime type
4286 This type is similar to :py:class:`pyderasn.UTCTime`.
4288 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4289 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4291 '20170930220750.000123Z'
4292 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4293 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4297 BER encoding is unsupported.
4301 Only microsecond fractions are supported.
4302 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4303 higher precision values.
4307 Zero year is unsupported.
4310 tag_default = tag_encode(24)
4311 asn1_type_name = "GeneralizedTime"
4313 def _strptime(self, value):
4315 if l == LEN_YYYYMMDDHHMMSSZ:
4316 # datetime.strptime's format: %Y%m%d%H%M%SZ
4317 if value[-1] != "Z":
4318 raise ValueError("non UTC timezone")
4320 int(value[:4]), # %Y
4321 int(value[4:6]), # %m
4322 int(value[6:8]), # %d
4323 int(value[8:10]), # %H
4324 int(value[10:12]), # %M
4325 int(value[12:14]), # %S
4327 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4328 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4329 if value[-1] != "Z":
4330 raise ValueError("non UTC timezone")
4331 if value[14] != ".":
4332 raise ValueError("no fractions separator")
4335 raise ValueError("trailing zero")
4338 raise ValueError("only microsecond fractions are supported")
4339 us = int(us + ("0" * (6 - us_len)))
4341 int(value[:4]), # %Y
4342 int(value[4:6]), # %m
4343 int(value[6:8]), # %d
4344 int(value[8:10]), # %H
4345 int(value[10:12]), # %M
4346 int(value[12:14]), # %S
4350 raise ValueError("invalid GeneralizedTime length")
4352 def _value_sanitize(self, value):
4353 if isinstance(value, binary_type):
4355 value_decoded = value.decode("ascii")
4356 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4357 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4359 self._strptime(value_decoded)
4360 except (TypeError, ValueError) as err:
4362 "invalid GeneralizedTime format: %r" % err,
4363 klass=self.__class__,
4366 if isinstance(value, self.__class__):
4368 if isinstance(value, datetime):
4369 encoded = value.strftime("%Y%m%d%H%M%S")
4370 if value.microsecond > 0:
4371 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4372 return (encoded + "Z").encode("ascii")
4373 raise InvalidValueType((self.__class__, datetime))
4375 def todatetime(self):
4376 return self._strptime(self._value.decode("ascii"))
4379 class GraphicString(CommonString):
4381 tag_default = tag_encode(25)
4382 encoding = "iso-8859-1"
4383 asn1_type_name = "GraphicString"
4386 class VisibleString(CommonString):
4388 tag_default = tag_encode(26)
4390 asn1_type_name = "VisibleString"
4393 class ISO646String(VisibleString):
4395 asn1_type_name = "ISO646String"
4398 class GeneralString(CommonString):
4400 tag_default = tag_encode(27)
4401 encoding = "iso-8859-1"
4402 asn1_type_name = "GeneralString"
4405 class UniversalString(CommonString):
4407 tag_default = tag_encode(28)
4408 encoding = "utf-32-be"
4409 asn1_type_name = "UniversalString"
4412 class BMPString(CommonString):
4414 tag_default = tag_encode(30)
4415 encoding = "utf-16-be"
4416 asn1_type_name = "BMPString"
4419 ChoiceState = namedtuple("ChoiceState", (
4437 """``CHOICE`` special type
4441 class GeneralName(Choice):
4443 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4444 ("dNSName", IA5String(impl=tag_ctxp(2))),
4447 >>> gn = GeneralName()
4449 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4450 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4451 >>> gn["dNSName"] = IA5String("bar.baz")
4452 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4453 >>> gn["rfc822Name"]
4456 [2] IA5String IA5 bar.baz
4459 >>> gn.value == gn["dNSName"]
4462 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4464 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4465 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4467 __slots__ = ("specs",)
4469 asn1_type_name = "CHOICE"
4482 :param value: set the value. Either ``(choice, value)`` tuple, or
4483 :py:class:`pyderasn.Choice` object
4484 :param bytes impl: can not be set, do **not** use it
4485 :param bytes expl: override default tag with ``EXPLICIT`` one
4486 :param default: set default value. Type same as in ``value``
4487 :param bool optional: is object ``OPTIONAL`` in sequence
4489 if impl is not None:
4490 raise ValueError("no implicit tag allowed for CHOICE")
4491 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4493 schema = getattr(self, "schema", ())
4494 if len(schema) == 0:
4495 raise ValueError("schema must be specified")
4497 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4500 if value is not None:
4501 self._value = self._value_sanitize(value)
4502 if default is not None:
4503 default_value = self._value_sanitize(default)
4504 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4505 default_obj.specs = self.specs
4506 default_obj._value = default_value
4507 self.default = default_obj
4509 self._value = copy(default_obj._value)
4511 def _value_sanitize(self, value):
4512 if isinstance(value, tuple) and len(value) == 2:
4514 spec = self.specs.get(choice)
4516 raise ObjUnknown(choice)
4517 if not isinstance(obj, spec.__class__):
4518 raise InvalidValueType((spec,))
4519 return (choice, spec(obj))
4520 if isinstance(value, self.__class__):
4522 raise InvalidValueType((self.__class__, tuple))
4526 return self._value is not None and self._value[1].ready
4530 return self.expl_lenindef or (
4531 (self._value is not None) and
4532 self._value[1].bered
4535 def __getstate__(self):
4552 def __setstate__(self, state):
4553 super(Choice, self).__setstate__(state)
4554 self.specs = state.specs
4555 self._value = state.value
4556 self._expl = state.expl
4557 self.default = state.default
4558 self.optional = state.optional
4559 self.offset = state.offset
4560 self.llen = state.llen
4561 self.vlen = state.vlen
4562 self.expl_lenindef = state.expl_lenindef
4563 self.lenindef = state.lenindef
4564 self.ber_encoded = state.ber_encoded
4566 def __eq__(self, their):
4567 if isinstance(their, tuple) and len(their) == 2:
4568 return self._value == their
4569 if not isinstance(their, self.__class__):
4572 self.specs == their.specs and
4573 self._value == their._value
4583 return self.__class__(
4586 expl=self._expl if expl is None else expl,
4587 default=self.default if default is None else default,
4588 optional=self.optional if optional is None else optional,
4593 self._assert_ready()
4594 return self._value[0]
4598 self._assert_ready()
4599 return self._value[1]
4601 def __getitem__(self, key):
4602 if key not in self.specs:
4603 raise ObjUnknown(key)
4604 if self._value is None:
4606 choice, value = self._value
4611 def __setitem__(self, key, value):
4612 spec = self.specs.get(key)
4614 raise ObjUnknown(key)
4615 if not isinstance(value, spec.__class__):
4616 raise InvalidValueType((spec.__class__,))
4617 self._value = (key, spec(value))
4625 return self._value[1].decoded if self.ready else False
4628 self._assert_ready()
4629 return self._value[1].encode()
4631 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4632 for choice, spec in iteritems(self.specs):
4633 sub_decode_path = decode_path + (choice,)
4639 decode_path=sub_decode_path,
4642 _ctx_immutable=False,
4649 klass=self.__class__,
4650 decode_path=decode_path,
4653 if tag_only: # pragma: no cover
4655 value, tail = spec.decode(
4659 decode_path=sub_decode_path,
4661 _ctx_immutable=False,
4663 obj = self.__class__(
4666 default=self.default,
4667 optional=self.optional,
4668 _decoded=(offset, 0, value.fulllen),
4670 obj._value = (choice, value)
4674 value = pp_console_row(next(self.pps()))
4676 value = "%s[%r]" % (value, self.value)
4679 def pps(self, decode_path=()):
4682 asn1_type_name=self.asn1_type_name,
4683 obj_name=self.__class__.__name__,
4684 decode_path=decode_path,
4685 value=self.choice if self.ready else None,
4686 optional=self.optional,
4687 default=self == self.default,
4688 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4689 expl=None if self._expl is None else tag_decode(self._expl),
4694 expl_lenindef=self.expl_lenindef,
4698 yield self.value.pps(decode_path=decode_path + (self.choice,))
4699 for pp in self.pps_lenindef(decode_path):
4703 class PrimitiveTypes(Choice):
4704 """Predefined ``CHOICE`` for all generic primitive types
4706 It could be useful for general decoding of some unspecified values:
4708 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4709 OCTET STRING 3 bytes 666f6f
4710 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4714 schema = tuple((klass.__name__, klass()) for klass in (
4738 AnyState = namedtuple("AnyState", (
4755 """``ANY`` special type
4757 >>> Any(Integer(-123))
4759 >>> a = Any(OctetString(b"hello world").encode())
4760 ANY 040b68656c6c6f20776f726c64
4761 >>> hexenc(bytes(a))
4762 b'0x040x0bhello world'
4764 __slots__ = ("defined",)
4765 tag_default = tag_encode(0)
4766 asn1_type_name = "ANY"
4776 :param value: set the value. Either any kind of pyderasn's
4777 **ready** object, or bytes. Pay attention that
4778 **no** validation is performed is raw binary value
4780 :param bytes expl: override default tag with ``EXPLICIT`` one
4781 :param bool optional: is object ``OPTIONAL`` in sequence
4783 super(Any, self).__init__(None, expl, None, optional, _decoded)
4784 self._value = None if value is None else self._value_sanitize(value)
4787 def _value_sanitize(self, value):
4788 if isinstance(value, binary_type):
4790 if isinstance(value, self.__class__):
4792 if isinstance(value, Obj):
4793 return value.encode()
4794 raise InvalidValueType((self.__class__, Obj, binary_type))
4798 return self._value is not None
4802 if self.expl_lenindef or self.lenindef:
4804 if self.defined is None:
4806 return self.defined[1].bered
4808 def __getstate__(self):
4824 def __setstate__(self, state):
4825 super(Any, self).__setstate__(state)
4826 self._value = state.value
4827 self.tag = state.tag
4828 self._expl = state.expl
4829 self.optional = state.optional
4830 self.offset = state.offset
4831 self.llen = state.llen
4832 self.vlen = state.vlen
4833 self.expl_lenindef = state.expl_lenindef
4834 self.lenindef = state.lenindef
4835 self.ber_encoded = state.ber_encoded
4836 self.defined = state.defined
4838 def __eq__(self, their):
4839 if isinstance(their, binary_type):
4840 return self._value == their
4841 if issubclass(their.__class__, Any):
4842 return self._value == their._value
4851 return self.__class__(
4853 expl=self._expl if expl is None else expl,
4854 optional=self.optional if optional is None else optional,
4857 def __bytes__(self):
4858 self._assert_ready()
4866 self._assert_ready()
4869 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4871 t, tlen, lv = tag_strip(tlv)
4872 except DecodeError as err:
4873 raise err.__class__(
4875 klass=self.__class__,
4876 decode_path=decode_path,
4880 l, llen, v = len_decode(lv)
4881 except LenIndefForm as err:
4882 if not ctx.get("bered", False):
4883 raise err.__class__(
4885 klass=self.__class__,
4886 decode_path=decode_path,
4889 llen, vlen, v = 1, 0, lv[1:]
4890 sub_offset = offset + tlen + llen
4892 while v[:EOC_LEN].tobytes() != EOC:
4893 chunk, v = Any().decode(
4896 decode_path=decode_path + (str(chunk_i),),
4899 _ctx_immutable=False,
4901 vlen += chunk.tlvlen
4902 sub_offset += chunk.tlvlen
4904 tlvlen = tlen + llen + vlen + EOC_LEN
4905 obj = self.__class__(
4906 value=tlv[:tlvlen].tobytes(),
4908 optional=self.optional,
4909 _decoded=(offset, 0, tlvlen),
4912 obj.tag = t.tobytes()
4913 return obj, v[EOC_LEN:]
4914 except DecodeError as err:
4915 raise err.__class__(
4917 klass=self.__class__,
4918 decode_path=decode_path,
4922 raise NotEnoughData(
4923 "encoded length is longer than data",
4924 klass=self.__class__,
4925 decode_path=decode_path,
4928 tlvlen = tlen + llen + l
4929 v, tail = tlv[:tlvlen], v[l:]
4930 obj = self.__class__(
4933 optional=self.optional,
4934 _decoded=(offset, 0, tlvlen),
4936 obj.tag = t.tobytes()
4940 return pp_console_row(next(self.pps()))
4942 def pps(self, decode_path=()):
4945 asn1_type_name=self.asn1_type_name,
4946 obj_name=self.__class__.__name__,
4947 decode_path=decode_path,
4948 blob=self._value if self.ready else None,
4949 optional=self.optional,
4950 default=self == self.default,
4951 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4952 expl=None if self._expl is None else tag_decode(self._expl),
4957 expl_offset=self.expl_offset if self.expled else None,
4958 expl_tlen=self.expl_tlen if self.expled else None,
4959 expl_llen=self.expl_llen if self.expled else None,
4960 expl_vlen=self.expl_vlen if self.expled else None,
4961 expl_lenindef=self.expl_lenindef,
4962 lenindef=self.lenindef,
4965 defined_by, defined = self.defined or (None, None)
4966 if defined_by is not None:
4968 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4970 for pp in self.pps_lenindef(decode_path):
4974 ########################################################################
4975 # ASN.1 constructed types
4976 ########################################################################
4978 def get_def_by_path(defines_by_path, sub_decode_path):
4979 """Get define by decode path
4981 for path, define in defines_by_path:
4982 if len(path) != len(sub_decode_path):
4984 for p1, p2 in zip(path, sub_decode_path):
4985 if (p1 != any) and (p1 != p2):
4991 def abs_decode_path(decode_path, rel_path):
4992 """Create an absolute decode path from current and relative ones
4994 :param decode_path: current decode path, starting point. Tuple of strings
4995 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4996 If first tuple's element is "/", then treat it as
4997 an absolute path, ignoring ``decode_path`` as
4998 starting point. Also this tuple can contain ".."
4999 elements, stripping the leading element from
5002 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5003 ("foo", "bar", "baz", "whatever")
5004 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5006 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5009 if rel_path[0] == "/":
5011 if rel_path[0] == "..":
5012 return abs_decode_path(decode_path[:-1], rel_path[1:])
5013 return decode_path + rel_path
5016 SequenceState = namedtuple("SequenceState", (
5033 class Sequence(Obj):
5034 """``SEQUENCE`` structure type
5036 You have to make specification of sequence::
5038 class Extension(Sequence):
5040 ("extnID", ObjectIdentifier()),
5041 ("critical", Boolean(default=False)),
5042 ("extnValue", OctetString()),
5045 Then, you can work with it as with dictionary.
5047 >>> ext = Extension()
5048 >>> Extension().specs
5050 ('extnID', OBJECT IDENTIFIER),
5051 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5052 ('extnValue', OCTET STRING),
5054 >>> ext["extnID"] = "1.2.3"
5055 Traceback (most recent call last):
5056 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5057 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5059 You can determine if sequence is ready to be encoded:
5064 Traceback (most recent call last):
5065 pyderasn.ObjNotReady: object is not ready: extnValue
5066 >>> ext["extnValue"] = OctetString(b"foobar")
5070 Value you want to assign, must have the same **type** as in
5071 corresponding specification, but it can have different tags,
5072 optional/default attributes -- they will be taken from specification
5075 class TBSCertificate(Sequence):
5077 ("version", Version(expl=tag_ctxc(0), default="v1")),
5080 >>> tbs = TBSCertificate()
5081 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5083 Assign ``None`` to remove value from sequence.
5085 You can set values in Sequence during its initialization:
5087 >>> AlgorithmIdentifier((
5088 ("algorithm", ObjectIdentifier("1.2.3")),
5089 ("parameters", Any(Null()))
5091 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5093 You can determine if value exists/set in the sequence and take its value:
5095 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5098 OBJECT IDENTIFIER 1.2.3
5100 But pay attention that if value has default, then it won't be (not
5101 in) in the sequence (because ``DEFAULT`` must not be encoded in
5102 DER), but you can read its value:
5104 >>> "critical" in ext, ext["critical"]
5105 (False, BOOLEAN False)
5106 >>> ext["critical"] = Boolean(True)
5107 >>> "critical" in ext, ext["critical"]
5108 (True, BOOLEAN True)
5110 All defaulted values are always optional.
5112 .. _allow_default_values_ctx:
5114 DER prohibits default value encoding and will raise an error if
5115 default value is unexpectedly met during decode.
5116 If :ref:`bered <bered_ctx>` context option is set, then no error
5117 will be raised, but ``bered`` attribute set. You can disable strict
5118 defaulted values existence validation by setting
5119 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5121 Two sequences are equal if they have equal specification (schema),
5122 implicit/explicit tagging and the same values.
5124 __slots__ = ("specs",)
5125 tag_default = tag_encode(form=TagFormConstructed, num=16)
5126 asn1_type_name = "SEQUENCE"
5138 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5140 schema = getattr(self, "schema", ())
5142 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5145 if value is not None:
5146 if issubclass(value.__class__, Sequence):
5147 self._value = value._value
5148 elif hasattr(value, "__iter__"):
5149 for seq_key, seq_value in value:
5150 self[seq_key] = seq_value
5152 raise InvalidValueType((Sequence,))
5153 if default is not None:
5154 if not issubclass(default.__class__, Sequence):
5155 raise InvalidValueType((Sequence,))
5156 default_value = default._value
5157 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5158 default_obj.specs = self.specs
5159 default_obj._value = default_value
5160 self.default = default_obj
5162 self._value = copy(default_obj._value)
5166 for name, spec in iteritems(self.specs):
5167 value = self._value.get(name)
5178 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5180 return any(value.bered for value in itervalues(self._value))
5182 def __getstate__(self):
5183 return SequenceState(
5186 {k: copy(v) for k, v in iteritems(self._value)},
5199 def __setstate__(self, state):
5200 super(Sequence, self).__setstate__(state)
5201 self.specs = state.specs
5202 self._value = state.value
5203 self.tag = state.tag
5204 self._expl = state.expl
5205 self.default = state.default
5206 self.optional = state.optional
5207 self.offset = state.offset
5208 self.llen = state.llen
5209 self.vlen = state.vlen
5210 self.expl_lenindef = state.expl_lenindef
5211 self.lenindef = state.lenindef
5212 self.ber_encoded = state.ber_encoded
5214 def __eq__(self, their):
5215 if not isinstance(their, self.__class__):
5218 self.specs == their.specs and
5219 self.tag == their.tag and
5220 self._expl == their._expl and
5221 self._value == their._value
5232 return self.__class__(
5235 impl=self.tag if impl is None else impl,
5236 expl=self._expl if expl is None else expl,
5237 default=self.default if default is None else default,
5238 optional=self.optional if optional is None else optional,
5241 def __contains__(self, key):
5242 return key in self._value
5244 def __setitem__(self, key, value):
5245 spec = self.specs.get(key)
5247 raise ObjUnknown(key)
5249 self._value.pop(key, None)
5251 if not isinstance(value, spec.__class__):
5252 raise InvalidValueType((spec.__class__,))
5253 value = spec(value=value)
5254 if spec.default is not None and value == spec.default:
5255 self._value.pop(key, None)
5257 self._value[key] = value
5259 def __getitem__(self, key):
5260 value = self._value.get(key)
5261 if value is not None:
5263 spec = self.specs.get(key)
5265 raise ObjUnknown(key)
5266 if spec.default is not None:
5270 def _encoded_values(self):
5272 for name, spec in iteritems(self.specs):
5273 value = self._value.get(name)
5277 raise ObjNotReady(name)
5278 raws.append(value.encode())
5282 v = b"".join(self._encoded_values())
5283 return b"".join((self.tag, len_encode(len(v)), v))
5285 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5287 t, tlen, lv = tag_strip(tlv)
5288 except DecodeError as err:
5289 raise err.__class__(
5291 klass=self.__class__,
5292 decode_path=decode_path,
5297 klass=self.__class__,
5298 decode_path=decode_path,
5301 if tag_only: # pragma: no cover
5304 ctx_bered = ctx.get("bered", False)
5306 l, llen, v = len_decode(lv)
5307 except LenIndefForm as err:
5309 raise err.__class__(
5311 klass=self.__class__,
5312 decode_path=decode_path,
5315 l, llen, v = 0, 1, lv[1:]
5317 except DecodeError as err:
5318 raise err.__class__(
5320 klass=self.__class__,
5321 decode_path=decode_path,
5325 raise NotEnoughData(
5326 "encoded length is longer than data",
5327 klass=self.__class__,
5328 decode_path=decode_path,
5332 v, tail = v[:l], v[l:]
5334 sub_offset = offset + tlen + llen
5337 ctx_allow_default_values = ctx.get("allow_default_values", False)
5338 for name, spec in iteritems(self.specs):
5339 if spec.optional and (
5340 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5344 sub_decode_path = decode_path + (name,)
5346 value, v_tail = spec.decode(
5350 decode_path=sub_decode_path,
5352 _ctx_immutable=False,
5354 except TagMismatch as err:
5355 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5359 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5360 if defined is not None:
5361 defined_by, defined_spec = defined
5362 if issubclass(value.__class__, SequenceOf):
5363 for i, _value in enumerate(value):
5364 sub_sub_decode_path = sub_decode_path + (
5366 DecodePathDefBy(defined_by),
5368 defined_value, defined_tail = defined_spec.decode(
5369 memoryview(bytes(_value)),
5371 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5372 if value.expled else (value.tlen + value.llen)
5375 decode_path=sub_sub_decode_path,
5377 _ctx_immutable=False,
5379 if len(defined_tail) > 0:
5382 klass=self.__class__,
5383 decode_path=sub_sub_decode_path,
5386 _value.defined = (defined_by, defined_value)
5388 defined_value, defined_tail = defined_spec.decode(
5389 memoryview(bytes(value)),
5391 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5392 if value.expled else (value.tlen + value.llen)
5395 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5397 _ctx_immutable=False,
5399 if len(defined_tail) > 0:
5402 klass=self.__class__,
5403 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5406 value.defined = (defined_by, defined_value)
5408 value_len = value.fulllen
5410 sub_offset += value_len
5412 if spec.default is not None and value == spec.default:
5413 if ctx_bered or ctx_allow_default_values:
5417 "DEFAULT value met",
5418 klass=self.__class__,
5419 decode_path=sub_decode_path,
5422 values[name] = value
5424 spec_defines = getattr(spec, "defines", ())
5425 if len(spec_defines) == 0:
5426 defines_by_path = ctx.get("defines_by_path", ())
5427 if len(defines_by_path) > 0:
5428 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5429 if spec_defines is not None and len(spec_defines) > 0:
5430 for rel_path, schema in spec_defines:
5431 defined = schema.get(value, None)
5432 if defined is not None:
5433 ctx.setdefault("_defines", []).append((
5434 abs_decode_path(sub_decode_path[:-1], rel_path),
5438 if v[:EOC_LEN].tobytes() != EOC:
5441 klass=self.__class__,
5442 decode_path=decode_path,
5450 klass=self.__class__,
5451 decode_path=decode_path,
5454 obj = self.__class__(
5458 default=self.default,
5459 optional=self.optional,
5460 _decoded=(offset, llen, vlen),
5463 obj.lenindef = lenindef
5464 obj.ber_encoded = ber_encoded
5468 value = pp_console_row(next(self.pps()))
5470 for name in self.specs:
5471 _value = self._value.get(name)
5474 cols.append("%s: %s" % (name, repr(_value)))
5475 return "%s[%s]" % (value, "; ".join(cols))
5477 def pps(self, decode_path=()):
5480 asn1_type_name=self.asn1_type_name,
5481 obj_name=self.__class__.__name__,
5482 decode_path=decode_path,
5483 optional=self.optional,
5484 default=self == self.default,
5485 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5486 expl=None if self._expl is None else tag_decode(self._expl),
5491 expl_offset=self.expl_offset if self.expled else None,
5492 expl_tlen=self.expl_tlen if self.expled else None,
5493 expl_llen=self.expl_llen if self.expled else None,
5494 expl_vlen=self.expl_vlen if self.expled else None,
5495 expl_lenindef=self.expl_lenindef,
5496 lenindef=self.lenindef,
5497 ber_encoded=self.ber_encoded,
5500 for name in self.specs:
5501 value = self._value.get(name)
5504 yield value.pps(decode_path=decode_path + (name,))
5505 for pp in self.pps_lenindef(decode_path):
5509 class Set(Sequence):
5510 """``SET`` structure type
5512 Its usage is identical to :py:class:`pyderasn.Sequence`.
5514 .. _allow_unordered_set_ctx:
5516 DER prohibits unordered values encoding and will raise an error
5517 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5518 then no error will occure. Also you can disable strict values
5519 ordering check by setting ``"allow_unordered_set": True``
5520 :ref:`context <ctx>` option.
5523 tag_default = tag_encode(form=TagFormConstructed, num=17)
5524 asn1_type_name = "SET"
5527 raws = self._encoded_values()
5530 return b"".join((self.tag, len_encode(len(v)), v))
5532 def _specs_items(self):
5533 return iteritems(self.specs)
5535 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5537 t, tlen, lv = tag_strip(tlv)
5538 except DecodeError as err:
5539 raise err.__class__(
5541 klass=self.__class__,
5542 decode_path=decode_path,
5547 klass=self.__class__,
5548 decode_path=decode_path,
5554 ctx_bered = ctx.get("bered", False)
5556 l, llen, v = len_decode(lv)
5557 except LenIndefForm as err:
5559 raise err.__class__(
5561 klass=self.__class__,
5562 decode_path=decode_path,
5565 l, llen, v = 0, 1, lv[1:]
5567 except DecodeError as err:
5568 raise err.__class__(
5570 klass=self.__class__,
5571 decode_path=decode_path,
5575 raise NotEnoughData(
5576 "encoded length is longer than data",
5577 klass=self.__class__,
5581 v, tail = v[:l], v[l:]
5583 sub_offset = offset + tlen + llen
5586 ctx_allow_default_values = ctx.get("allow_default_values", False)
5587 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5588 value_prev = memoryview(v[:0])
5591 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5593 for name, spec in self._specs_items():
5594 sub_decode_path = decode_path + (name,)
5600 decode_path=sub_decode_path,
5603 _ctx_immutable=False,
5610 klass=self.__class__,
5611 decode_path=decode_path,
5614 value, v_tail = spec.decode(
5618 decode_path=sub_decode_path,
5620 _ctx_immutable=False,
5622 value_len = value.fulllen
5623 if value_prev.tobytes() > v[:value_len].tobytes():
5624 if ctx_bered or ctx_allow_unordered_set:
5628 "unordered " + self.asn1_type_name,
5629 klass=self.__class__,
5630 decode_path=sub_decode_path,
5633 if spec.default is None or value != spec.default:
5635 elif ctx_bered or ctx_allow_default_values:
5639 "DEFAULT value met",
5640 klass=self.__class__,
5641 decode_path=sub_decode_path,
5644 values[name] = value
5645 value_prev = v[:value_len]
5646 sub_offset += value_len
5649 obj = self.__class__(
5653 default=self.default,
5654 optional=self.optional,
5655 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5658 if v[:EOC_LEN].tobytes() != EOC:
5661 klass=self.__class__,
5662 decode_path=decode_path,
5670 "not all values are ready",
5671 klass=self.__class__,
5672 decode_path=decode_path,
5675 obj.ber_encoded = ber_encoded
5679 SequenceOfState = namedtuple("SequenceOfState", (
5698 class SequenceOf(Obj):
5699 """``SEQUENCE OF`` sequence type
5701 For that kind of type you must specify the object it will carry on
5702 (bounds are for example here, not required)::
5704 class Ints(SequenceOf):
5709 >>> ints.append(Integer(123))
5710 >>> ints.append(Integer(234))
5712 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5713 >>> [int(i) for i in ints]
5715 >>> ints.append(Integer(345))
5716 Traceback (most recent call last):
5717 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5720 >>> ints[1] = Integer(345)
5722 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5724 Also you can initialize sequence with preinitialized values:
5726 >>> ints = Ints([Integer(123), Integer(234)])
5728 __slots__ = ("spec", "_bound_min", "_bound_max")
5729 tag_default = tag_encode(form=TagFormConstructed, num=16)
5730 asn1_type_name = "SEQUENCE OF"
5743 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5745 schema = getattr(self, "schema", None)
5747 raise ValueError("schema must be specified")
5749 self._bound_min, self._bound_max = getattr(
5753 ) if bounds is None else bounds
5755 if value is not None:
5756 self._value = self._value_sanitize(value)
5757 if default is not None:
5758 default_value = self._value_sanitize(default)
5759 default_obj = self.__class__(
5764 default_obj._value = default_value
5765 self.default = default_obj
5767 self._value = copy(default_obj._value)
5769 def _value_sanitize(self, value):
5770 if issubclass(value.__class__, SequenceOf):
5771 value = value._value
5772 elif hasattr(value, "__iter__"):
5775 raise InvalidValueType((self.__class__, iter))
5776 if not self._bound_min <= len(value) <= self._bound_max:
5777 raise BoundsError(self._bound_min, len(value), self._bound_max)
5779 if not isinstance(v, self.spec.__class__):
5780 raise InvalidValueType((self.spec.__class__,))
5785 return all(v.ready for v in self._value)
5789 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5791 return any(v.bered for v in self._value)
5793 def __getstate__(self):
5794 return SequenceOfState(
5797 [copy(v) for v in self._value],
5812 def __setstate__(self, state):
5813 super(SequenceOf, self).__setstate__(state)
5814 self.spec = state.spec
5815 self._value = state.value
5816 self._bound_min = state.bound_min
5817 self._bound_max = state.bound_max
5818 self.tag = state.tag
5819 self._expl = state.expl
5820 self.default = state.default
5821 self.optional = state.optional
5822 self.offset = state.offset
5823 self.llen = state.llen
5824 self.vlen = state.vlen
5825 self.expl_lenindef = state.expl_lenindef
5826 self.lenindef = state.lenindef
5827 self.ber_encoded = state.ber_encoded
5829 def __eq__(self, their):
5830 if isinstance(their, self.__class__):
5832 self.spec == their.spec and
5833 self.tag == their.tag and
5834 self._expl == their._expl and
5835 self._value == their._value
5837 if hasattr(their, "__iter__"):
5838 return self._value == list(their)
5850 return self.__class__(
5854 (self._bound_min, self._bound_max)
5855 if bounds is None else bounds
5857 impl=self.tag if impl is None else impl,
5858 expl=self._expl if expl is None else expl,
5859 default=self.default if default is None else default,
5860 optional=self.optional if optional is None else optional,
5863 def __contains__(self, key):
5864 return key in self._value
5866 def append(self, value):
5867 if not isinstance(value, self.spec.__class__):
5868 raise InvalidValueType((self.spec.__class__,))
5869 if len(self._value) + 1 > self._bound_max:
5872 len(self._value) + 1,
5875 self._value.append(value)
5878 self._assert_ready()
5879 return iter(self._value)
5882 self._assert_ready()
5883 return len(self._value)
5885 def __setitem__(self, key, value):
5886 if not isinstance(value, self.spec.__class__):
5887 raise InvalidValueType((self.spec.__class__,))
5888 self._value[key] = self.spec(value=value)
5890 def __getitem__(self, key):
5891 return self._value[key]
5893 def _encoded_values(self):
5894 return [v.encode() for v in self._value]
5897 v = b"".join(self._encoded_values())
5898 return b"".join((self.tag, len_encode(len(v)), v))
5900 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5902 t, tlen, lv = tag_strip(tlv)
5903 except DecodeError as err:
5904 raise err.__class__(
5906 klass=self.__class__,
5907 decode_path=decode_path,
5912 klass=self.__class__,
5913 decode_path=decode_path,
5919 ctx_bered = ctx.get("bered", False)
5921 l, llen, v = len_decode(lv)
5922 except LenIndefForm as err:
5924 raise err.__class__(
5926 klass=self.__class__,
5927 decode_path=decode_path,
5930 l, llen, v = 0, 1, lv[1:]
5932 except DecodeError as err:
5933 raise err.__class__(
5935 klass=self.__class__,
5936 decode_path=decode_path,
5940 raise NotEnoughData(
5941 "encoded length is longer than data",
5942 klass=self.__class__,
5943 decode_path=decode_path,
5947 v, tail = v[:l], v[l:]
5949 sub_offset = offset + tlen + llen
5951 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5952 value_prev = memoryview(v[:0])
5956 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5958 sub_decode_path = decode_path + (str(len(_value)),)
5959 value, v_tail = spec.decode(
5963 decode_path=sub_decode_path,
5965 _ctx_immutable=False,
5967 value_len = value.fulllen
5969 if value_prev.tobytes() > v[:value_len].tobytes():
5970 if ctx_bered or ctx_allow_unordered_set:
5974 "unordered " + self.asn1_type_name,
5975 klass=self.__class__,
5976 decode_path=sub_decode_path,
5979 value_prev = v[:value_len]
5980 _value.append(value)
5981 sub_offset += value_len
5985 obj = self.__class__(
5988 bounds=(self._bound_min, self._bound_max),
5991 default=self.default,
5992 optional=self.optional,
5993 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5995 except BoundsError as err:
5998 klass=self.__class__,
5999 decode_path=decode_path,
6003 if v[:EOC_LEN].tobytes() != EOC:
6006 klass=self.__class__,
6007 decode_path=decode_path,
6012 obj.ber_encoded = ber_encoded
6017 pp_console_row(next(self.pps())),
6018 ", ".join(repr(v) for v in self._value),
6021 def pps(self, decode_path=()):
6024 asn1_type_name=self.asn1_type_name,
6025 obj_name=self.__class__.__name__,
6026 decode_path=decode_path,
6027 optional=self.optional,
6028 default=self == self.default,
6029 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6030 expl=None if self._expl is None else tag_decode(self._expl),
6035 expl_offset=self.expl_offset if self.expled else None,
6036 expl_tlen=self.expl_tlen if self.expled else None,
6037 expl_llen=self.expl_llen if self.expled else None,
6038 expl_vlen=self.expl_vlen if self.expled else None,
6039 expl_lenindef=self.expl_lenindef,
6040 lenindef=self.lenindef,
6041 ber_encoded=self.ber_encoded,
6044 for i, value in enumerate(self._value):
6045 yield value.pps(decode_path=decode_path + (str(i),))
6046 for pp in self.pps_lenindef(decode_path):
6050 class SetOf(SequenceOf):
6051 """``SET OF`` sequence type
6053 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6056 tag_default = tag_encode(form=TagFormConstructed, num=17)
6057 asn1_type_name = "SET OF"
6060 raws = self._encoded_values()
6063 return b"".join((self.tag, len_encode(len(v)), v))
6065 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6066 return super(SetOf, self)._decode(
6072 ordering_check=True,
6076 def obj_by_path(pypath): # pragma: no cover
6077 """Import object specified as string Python path
6079 Modules must be separated from classes/functions with ``:``.
6081 >>> obj_by_path("foo.bar:Baz")
6082 <class 'foo.bar.Baz'>
6083 >>> obj_by_path("foo.bar:Baz.boo")
6084 <classmethod 'foo.bar.Baz.boo'>
6086 mod, objs = pypath.rsplit(":", 1)
6087 from importlib import import_module
6088 obj = import_module(mod)
6089 for obj_name in objs.split("."):
6090 obj = getattr(obj, obj_name)
6094 def generic_decoder(): # pragma: no cover
6095 # All of this below is a big hack with self references
6096 choice = PrimitiveTypes()
6097 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6098 choice.specs["SetOf"] = SetOf(schema=choice)
6099 for i in six_xrange(31):
6100 choice.specs["SequenceOf%d" % i] = SequenceOf(
6104 choice.specs["Any"] = Any()
6106 # Class name equals to type name, to omit it from output
6107 class SEQUENCEOF(SequenceOf):
6115 with_decode_path=False,
6116 decode_path_only=(),
6118 def _pprint_pps(pps):
6120 if hasattr(pp, "_fields"):
6122 decode_path_only != () and
6123 pp.decode_path[:len(decode_path_only)] != decode_path_only
6126 if pp.asn1_type_name == Choice.asn1_type_name:
6128 pp_kwargs = pp._asdict()
6129 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6130 pp = _pp(**pp_kwargs)
6131 yield pp_console_row(
6136 with_colours=with_colours,
6137 with_decode_path=with_decode_path,
6138 decode_path_len_decrease=len(decode_path_only),
6140 for row in pp_console_blob(
6142 decode_path_len_decrease=len(decode_path_only),
6146 for row in _pprint_pps(pp):
6148 return "\n".join(_pprint_pps(obj.pps()))
6149 return SEQUENCEOF(), pprint_any
6152 def main(): # pragma: no cover
6154 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6155 parser.add_argument(
6159 help="Skip that number of bytes from the beginning",
6161 parser.add_argument(
6163 help="Python paths to dictionary with OIDs, comma separated",
6165 parser.add_argument(
6167 help="Python path to schema definition to use",
6169 parser.add_argument(
6170 "--defines-by-path",
6171 help="Python path to decoder's defines_by_path",
6173 parser.add_argument(
6175 action="store_true",
6176 help="Disallow BER encoding",
6178 parser.add_argument(
6179 "--print-decode-path",
6180 action="store_true",
6181 help="Print decode paths",
6183 parser.add_argument(
6184 "--decode-path-only",
6185 help="Print only specified decode path",
6187 parser.add_argument(
6189 action="store_true",
6190 help="Allow explicit tag out-of-bound",
6192 parser.add_argument(
6194 type=argparse.FileType("rb"),
6195 help="Path to DER file you want to decode",
6197 args = parser.parse_args()
6198 args.DERFile.seek(args.skip)
6199 der = memoryview(args.DERFile.read())
6200 args.DERFile.close()
6202 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6203 if args.oids else ()
6206 schema = obj_by_path(args.schema)
6207 from functools import partial
6208 pprinter = partial(pprint, big_blobs=True)
6210 schema, pprinter = generic_decoder()
6212 "bered": not args.nobered,
6213 "allow_expl_oob": args.allow_expl_oob,
6215 if args.defines_by_path is not None:
6216 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6217 obj, tail = schema().decode(der, ctx=ctx)
6221 with_colours=environ.get("NO_COLOR") is None,
6222 with_decode_path=args.print_decode_path,
6224 () if args.decode_path_only is None else
6225 tuple(args.decode_path_only.split(":"))
6229 print("\nTrailing data: %s" % hexenc(tail))
6232 if __name__ == "__main__":