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))
1190 _ctx_immutable=True,
1194 :param data: either binary or memoryview
1195 :param int offset: initial data's offset
1196 :param bool leavemm: do we need to leave memoryview of remaining
1197 data as is, or convert it to bytes otherwise
1198 :param ctx: optional :ref:`context <ctx>` governing decoding process
1199 :param tag_only: decode only the tag, without length and contents
1200 (used only in Choice and Set structures, trying to
1201 determine if tag satisfies the scheme)
1202 :param _ctx_immutable: do we need to ``copy.copy()`` ``ctx``
1204 :returns: (Obj, remaining data)
1206 .. seealso:: :ref:`decoding`
1210 elif _ctx_immutable:
1212 tlv = memoryview(data)
1213 if self._expl is None:
1214 result = self._decode(
1217 decode_path=decode_path,
1226 t, tlen, lv = tag_strip(tlv)
1227 except DecodeError as err:
1228 raise err.__class__(
1230 klass=self.__class__,
1231 decode_path=decode_path,
1236 klass=self.__class__,
1237 decode_path=decode_path,
1241 l, llen, v = len_decode(lv)
1242 except LenIndefForm as err:
1243 if not ctx.get("bered", False):
1244 raise err.__class__(
1246 klass=self.__class__,
1247 decode_path=decode_path,
1251 offset += tlen + llen
1252 result = self._decode(
1255 decode_path=decode_path,
1259 if tag_only: # pragma: no cover
1262 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1263 if eoc_expected.tobytes() != EOC:
1266 klass=self.__class__,
1267 decode_path=decode_path,
1271 obj.expl_lenindef = True
1272 except DecodeError as err:
1273 raise err.__class__(
1275 klass=self.__class__,
1276 decode_path=decode_path,
1281 raise NotEnoughData(
1282 "encoded length is longer than data",
1283 klass=self.__class__,
1284 decode_path=decode_path,
1287 result = self._decode(
1289 offset=offset + tlen + llen,
1290 decode_path=decode_path,
1294 if tag_only: # pragma: no cover
1297 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1299 "explicit tag out-of-bound, longer than data",
1300 klass=self.__class__,
1301 decode_path=decode_path,
1304 return obj, (tail if leavemm else tail.tobytes())
1306 def decod(self, data, offset=0, decode_path=(), ctx=None):
1307 """Decode the data, check that tail is empty
1309 :raises ExceedingData: if tail is not empty
1311 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1312 (decode without tail) that also checks that there is no
1315 obj, tail = self.decode(
1318 decode_path=decode_path,
1323 raise ExceedingData(len(tail))
1328 """See :ref:`decoding`
1330 return self._expl is not None
1334 """See :ref:`decoding`
1339 def expl_tlen(self):
1340 """See :ref:`decoding`
1342 return len(self._expl)
1345 def expl_llen(self):
1346 """See :ref:`decoding`
1348 if self.expl_lenindef:
1350 return len(len_encode(self.tlvlen))
1353 def expl_offset(self):
1354 """See :ref:`decoding`
1356 return self.offset - self.expl_tlen - self.expl_llen
1359 def expl_vlen(self):
1360 """See :ref:`decoding`
1365 def expl_tlvlen(self):
1366 """See :ref:`decoding`
1368 return self.expl_tlen + self.expl_llen + self.expl_vlen
1371 def fulloffset(self):
1372 """See :ref:`decoding`
1374 return self.expl_offset if self.expled else self.offset
1378 """See :ref:`decoding`
1380 return self.expl_tlvlen if self.expled else self.tlvlen
1382 def pps_lenindef(self, decode_path):
1383 if self.lenindef and not (
1384 getattr(self, "defined", None) is not None and
1385 self.defined[1].lenindef
1388 asn1_type_name="EOC",
1390 decode_path=decode_path,
1392 self.offset + self.tlvlen -
1393 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1401 if self.expl_lenindef:
1403 asn1_type_name="EOC",
1404 obj_name="EXPLICIT",
1405 decode_path=decode_path,
1406 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1415 class DecodePathDefBy(object):
1416 """DEFINED BY representation inside decode path
1418 __slots__ = ("defined_by",)
1420 def __init__(self, defined_by):
1421 self.defined_by = defined_by
1423 def __ne__(self, their):
1424 return not(self == their)
1426 def __eq__(self, their):
1427 if not isinstance(their, self.__class__):
1429 return self.defined_by == their.defined_by
1432 return "DEFINED BY " + str(self.defined_by)
1435 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1438 ########################################################################
1440 ########################################################################
1442 PP = namedtuple("PP", (
1470 asn1_type_name="unknown",
1487 expl_lenindef=False,
1518 def _colourize(what, colour, with_colours, attrs=("bold",)):
1519 return colored(what, colour, attrs=attrs) if with_colours else what
1522 def colonize_hex(hexed):
1523 """Separate hexadecimal string with colons
1525 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1534 with_decode_path=False,
1535 decode_path_len_decrease=0,
1542 " " if pp.expl_offset is None else
1543 ("-%d" % (pp.offset - pp.expl_offset))
1545 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1547 col = _colourize(col, "red", with_colours, ())
1548 col += _colourize("B", "red", with_colours) if pp.bered else " "
1550 col = "[%d,%d,%4d]%s" % (
1554 LENINDEF_PP_CHAR if pp.lenindef else " "
1556 col = _colourize(col, "green", with_colours, ())
1558 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1559 if decode_path_len > 0:
1560 cols.append(" ." * decode_path_len)
1561 ent = pp.decode_path[-1]
1562 if isinstance(ent, DecodePathDefBy):
1563 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1564 value = str(ent.defined_by)
1567 len(oid_maps) > 0 and
1568 ent.defined_by.asn1_type_name ==
1569 ObjectIdentifier.asn1_type_name
1571 for oid_map in oid_maps:
1572 oid_name = oid_map.get(value)
1573 if oid_name is not None:
1574 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1576 if oid_name is None:
1577 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1579 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1580 if pp.expl is not None:
1581 klass, _, num = pp.expl
1582 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1583 cols.append(_colourize(col, "blue", with_colours))
1584 if pp.impl is not None:
1585 klass, _, num = pp.impl
1586 col = "[%s%d]" % (TagClassReprs[klass], num)
1587 cols.append(_colourize(col, "blue", with_colours))
1588 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1589 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1591 cols.append(_colourize("BER", "red", with_colours))
1592 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1593 if pp.value is not None:
1595 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1597 len(oid_maps) > 0 and
1598 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1600 for oid_map in oid_maps:
1601 oid_name = oid_map.get(value)
1602 if oid_name is not None:
1603 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1605 if pp.asn1_type_name == Integer.asn1_type_name:
1606 hex_repr = hex(int(pp.obj._value))[2:].upper()
1607 if len(hex_repr) % 2 != 0:
1608 hex_repr = "0" + hex_repr
1609 cols.append(_colourize(
1610 "(%s)" % colonize_hex(hex_repr),
1615 if isinstance(pp.blob, binary_type):
1616 cols.append(hexenc(pp.blob))
1617 elif isinstance(pp.blob, tuple):
1618 cols.append(", ".join(pp.blob))
1620 cols.append(_colourize("OPTIONAL", "red", with_colours))
1622 cols.append(_colourize("DEFAULT", "red", with_colours))
1623 if with_decode_path:
1624 cols.append(_colourize(
1625 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1629 return " ".join(cols)
1632 def pp_console_blob(pp, decode_path_len_decrease=0):
1633 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1634 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1635 if decode_path_len > 0:
1636 cols.append(" ." * (decode_path_len + 1))
1637 if isinstance(pp.blob, binary_type):
1638 blob = hexenc(pp.blob).upper()
1639 for i in six_xrange(0, len(blob), 32):
1640 chunk = blob[i:i + 32]
1641 yield " ".join(cols + [colonize_hex(chunk)])
1642 elif isinstance(pp.blob, tuple):
1643 yield " ".join(cols + [", ".join(pp.blob)])
1651 with_decode_path=False,
1652 decode_path_only=(),
1654 """Pretty print object
1656 :param Obj obj: object you want to pretty print
1657 :param oid_maps: list of ``OID <-> humand readable string`` dictionary.
1658 When OID from it is met, then its humand readable form
1660 :param big_blobs: if large binary objects are met (like OctetString
1661 values), do we need to print them too, on separate
1663 :param with_colours: colourize output, if ``termcolor`` library
1665 :param with_decode_path: print decode path
1666 :param decode_path_only: print only that specified decode path
1668 def _pprint_pps(pps):
1670 if hasattr(pp, "_fields"):
1672 decode_path_only != () and
1674 str(p) for p in pp.decode_path[:len(decode_path_only)]
1675 ) != decode_path_only
1679 yield pp_console_row(
1684 with_colours=with_colours,
1685 with_decode_path=with_decode_path,
1686 decode_path_len_decrease=len(decode_path_only),
1688 for row in pp_console_blob(
1690 decode_path_len_decrease=len(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),
1704 for row in _pprint_pps(pp):
1706 return "\n".join(_pprint_pps(obj.pps()))
1709 ########################################################################
1710 # ASN.1 primitive types
1711 ########################################################################
1713 BooleanState = namedtuple("BooleanState", (
1730 """``BOOLEAN`` boolean type
1732 >>> b = Boolean(True)
1734 >>> b == Boolean(True)
1740 tag_default = tag_encode(1)
1741 asn1_type_name = "BOOLEAN"
1753 :param value: set the value. Either boolean type, or
1754 :py:class:`pyderasn.Boolean` object
1755 :param bytes impl: override default tag with ``IMPLICIT`` one
1756 :param bytes expl: override default tag with ``EXPLICIT`` one
1757 :param default: set default value. Type same as in ``value``
1758 :param bool optional: is object ``OPTIONAL`` in sequence
1760 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1761 self._value = None if value is None else self._value_sanitize(value)
1762 if default is not None:
1763 default = self._value_sanitize(default)
1764 self.default = self.__class__(
1770 self._value = default
1772 def _value_sanitize(self, value):
1773 if isinstance(value, bool):
1775 if issubclass(value.__class__, Boolean):
1777 raise InvalidValueType((self.__class__, bool))
1781 return self._value is not None
1783 def __getstate__(self):
1784 return BooleanState(
1799 def __setstate__(self, state):
1800 super(Boolean, self).__setstate__(state)
1801 self._value = state.value
1802 self.tag = state.tag
1803 self._expl = state.expl
1804 self.default = state.default
1805 self.optional = state.optional
1806 self.offset = state.offset
1807 self.llen = state.llen
1808 self.vlen = state.vlen
1809 self.expl_lenindef = state.expl_lenindef
1810 self.lenindef = state.lenindef
1811 self.ber_encoded = state.ber_encoded
1813 def __nonzero__(self):
1814 self._assert_ready()
1818 self._assert_ready()
1821 def __eq__(self, their):
1822 if isinstance(their, bool):
1823 return self._value == their
1824 if not issubclass(their.__class__, Boolean):
1827 self._value == their._value and
1828 self.tag == their.tag and
1829 self._expl == their._expl
1840 return self.__class__(
1842 impl=self.tag if impl is None else impl,
1843 expl=self._expl if expl is None else expl,
1844 default=self.default if default is None else default,
1845 optional=self.optional if optional is None else optional,
1849 self._assert_ready()
1853 (b"\xFF" if self._value else b"\x00"),
1856 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1858 t, _, lv = tag_strip(tlv)
1859 except DecodeError as err:
1860 raise err.__class__(
1862 klass=self.__class__,
1863 decode_path=decode_path,
1868 klass=self.__class__,
1869 decode_path=decode_path,
1875 l, _, v = len_decode(lv)
1876 except DecodeError as err:
1877 raise err.__class__(
1879 klass=self.__class__,
1880 decode_path=decode_path,
1884 raise InvalidLength(
1885 "Boolean's length must be equal to 1",
1886 klass=self.__class__,
1887 decode_path=decode_path,
1891 raise NotEnoughData(
1892 "encoded length is longer than data",
1893 klass=self.__class__,
1894 decode_path=decode_path,
1897 first_octet = byte2int(v)
1899 if first_octet == 0:
1901 elif first_octet == 0xFF:
1903 elif ctx.get("bered", False):
1908 "unacceptable Boolean value",
1909 klass=self.__class__,
1910 decode_path=decode_path,
1913 obj = self.__class__(
1917 default=self.default,
1918 optional=self.optional,
1919 _decoded=(offset, 1, 1),
1921 obj.ber_encoded = ber_encoded
1925 return pp_console_row(next(self.pps()))
1927 def pps(self, decode_path=()):
1930 asn1_type_name=self.asn1_type_name,
1931 obj_name=self.__class__.__name__,
1932 decode_path=decode_path,
1933 value=str(self._value) if self.ready else None,
1934 optional=self.optional,
1935 default=self == self.default,
1936 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1937 expl=None if self._expl is None else tag_decode(self._expl),
1942 expl_offset=self.expl_offset if self.expled else None,
1943 expl_tlen=self.expl_tlen if self.expled else None,
1944 expl_llen=self.expl_llen if self.expled else None,
1945 expl_vlen=self.expl_vlen if self.expled else None,
1946 expl_lenindef=self.expl_lenindef,
1947 ber_encoded=self.ber_encoded,
1950 for pp in self.pps_lenindef(decode_path):
1954 IntegerState = namedtuple("IntegerState", (
1974 """``INTEGER`` integer type
1976 >>> b = Integer(-123)
1978 >>> b == Integer(-123)
1983 >>> Integer(2, bounds=(1, 3))
1985 >>> Integer(5, bounds=(1, 3))
1986 Traceback (most recent call last):
1987 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1991 class Version(Integer):
1998 >>> v = Version("v1")
2005 {'v3': 2, 'v1': 0, 'v2': 1}
2007 __slots__ = ("specs", "_bound_min", "_bound_max")
2008 tag_default = tag_encode(2)
2009 asn1_type_name = "INTEGER"
2023 :param value: set the value. Either integer type, named value
2024 (if ``schema`` is specified in the class), or
2025 :py:class:`pyderasn.Integer` object
2026 :param bounds: set ``(MIN, MAX)`` value constraint.
2027 (-inf, +inf) by default
2028 :param bytes impl: override default tag with ``IMPLICIT`` one
2029 :param bytes expl: override default tag with ``EXPLICIT`` one
2030 :param default: set default value. Type same as in ``value``
2031 :param bool optional: is object ``OPTIONAL`` in sequence
2033 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2035 specs = getattr(self, "schema", {}) if _specs is None else _specs
2036 self.specs = specs if isinstance(specs, dict) else dict(specs)
2037 self._bound_min, self._bound_max = getattr(
2040 (float("-inf"), float("+inf")),
2041 ) if bounds is None else bounds
2042 if value is not None:
2043 self._value = self._value_sanitize(value)
2044 if default is not None:
2045 default = self._value_sanitize(default)
2046 self.default = self.__class__(
2052 if self._value is None:
2053 self._value = default
2055 def _value_sanitize(self, value):
2056 if isinstance(value, integer_types):
2058 elif issubclass(value.__class__, Integer):
2059 value = value._value
2060 elif isinstance(value, str):
2061 value = self.specs.get(value)
2063 raise ObjUnknown("integer value: %s" % value)
2065 raise InvalidValueType((self.__class__, int, str))
2066 if not self._bound_min <= value <= self._bound_max:
2067 raise BoundsError(self._bound_min, value, self._bound_max)
2072 return self._value is not None
2074 def __getstate__(self):
2075 return IntegerState(
2093 def __setstate__(self, state):
2094 super(Integer, self).__setstate__(state)
2095 self.specs = state.specs
2096 self._value = state.value
2097 self._bound_min = state.bound_min
2098 self._bound_max = state.bound_max
2099 self.tag = state.tag
2100 self._expl = state.expl
2101 self.default = state.default
2102 self.optional = state.optional
2103 self.offset = state.offset
2104 self.llen = state.llen
2105 self.vlen = state.vlen
2106 self.expl_lenindef = state.expl_lenindef
2107 self.lenindef = state.lenindef
2108 self.ber_encoded = state.ber_encoded
2111 self._assert_ready()
2112 return int(self._value)
2115 self._assert_ready()
2118 bytes(self._expl or b"") +
2119 str(self._value).encode("ascii"),
2122 def __eq__(self, their):
2123 if isinstance(their, integer_types):
2124 return self._value == their
2125 if not issubclass(their.__class__, Integer):
2128 self._value == their._value and
2129 self.tag == their.tag and
2130 self._expl == their._expl
2133 def __lt__(self, their):
2134 return self._value < their._value
2138 for name, value in iteritems(self.specs):
2139 if value == self._value:
2152 return self.__class__(
2155 (self._bound_min, self._bound_max)
2156 if bounds is None else bounds
2158 impl=self.tag if impl is None else impl,
2159 expl=self._expl if expl is None else expl,
2160 default=self.default if default is None else default,
2161 optional=self.optional if optional is None else optional,
2166 self._assert_ready()
2170 octets = bytearray([0])
2174 octets = bytearray()
2176 octets.append((value & 0xFF) ^ 0xFF)
2178 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2181 octets = bytearray()
2183 octets.append(value & 0xFF)
2185 if octets[-1] & 0x80 > 0:
2188 octets = bytes(octets)
2190 bytes_len = ceil(value.bit_length() / 8) or 1
2193 octets = value.to_bytes(
2198 except OverflowError:
2202 return b"".join((self.tag, len_encode(len(octets)), octets))
2204 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2206 t, _, lv = tag_strip(tlv)
2207 except DecodeError as err:
2208 raise err.__class__(
2210 klass=self.__class__,
2211 decode_path=decode_path,
2216 klass=self.__class__,
2217 decode_path=decode_path,
2223 l, llen, v = len_decode(lv)
2224 except DecodeError as err:
2225 raise err.__class__(
2227 klass=self.__class__,
2228 decode_path=decode_path,
2232 raise NotEnoughData(
2233 "encoded length is longer than data",
2234 klass=self.__class__,
2235 decode_path=decode_path,
2239 raise NotEnoughData(
2241 klass=self.__class__,
2242 decode_path=decode_path,
2245 v, tail = v[:l], v[l:]
2246 first_octet = byte2int(v)
2248 second_octet = byte2int(v[1:])
2250 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2251 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2254 "non normalized integer",
2255 klass=self.__class__,
2256 decode_path=decode_path,
2261 if first_octet & 0x80 > 0:
2262 octets = bytearray()
2263 for octet in bytearray(v):
2264 octets.append(octet ^ 0xFF)
2265 for octet in octets:
2266 value = (value << 8) | octet
2270 for octet in bytearray(v):
2271 value = (value << 8) | octet
2273 value = int.from_bytes(v, byteorder="big", signed=True)
2275 obj = self.__class__(
2277 bounds=(self._bound_min, self._bound_max),
2280 default=self.default,
2281 optional=self.optional,
2283 _decoded=(offset, llen, l),
2285 except BoundsError as err:
2288 klass=self.__class__,
2289 decode_path=decode_path,
2295 return pp_console_row(next(self.pps()))
2297 def pps(self, decode_path=()):
2300 asn1_type_name=self.asn1_type_name,
2301 obj_name=self.__class__.__name__,
2302 decode_path=decode_path,
2303 value=(self.named or str(self._value)) if self.ready else None,
2304 optional=self.optional,
2305 default=self == self.default,
2306 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2307 expl=None if self._expl is None else tag_decode(self._expl),
2312 expl_offset=self.expl_offset if self.expled else None,
2313 expl_tlen=self.expl_tlen if self.expled else None,
2314 expl_llen=self.expl_llen if self.expled else None,
2315 expl_vlen=self.expl_vlen if self.expled else None,
2316 expl_lenindef=self.expl_lenindef,
2319 for pp in self.pps_lenindef(decode_path):
2323 SET01 = frozenset(("0", "1"))
2324 BitStringState = namedtuple("BitStringState", (
2343 class BitString(Obj):
2344 """``BIT STRING`` bit string type
2346 >>> BitString(b"hello world")
2347 BIT STRING 88 bits 68656c6c6f20776f726c64
2350 >>> b == b"hello world"
2355 >>> BitString("'0A3B5F291CD'H")
2356 BIT STRING 44 bits 0a3b5f291cd0
2357 >>> b = BitString("'010110000000'B")
2358 BIT STRING 12 bits 5800
2361 >>> b[0], b[1], b[2], b[3]
2362 (False, True, False, True)
2366 [False, True, False, True, True, False, False, False, False, False, False, False]
2370 class KeyUsage(BitString):
2372 ("digitalSignature", 0),
2373 ("nonRepudiation", 1),
2374 ("keyEncipherment", 2),
2377 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2378 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2380 ['nonRepudiation', 'keyEncipherment']
2382 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2386 Pay attention that BIT STRING can be encoded both in primitive
2387 and constructed forms. Decoder always checks constructed form tag
2388 additionally to specified primitive one. If BER decoding is
2389 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2390 of DER restrictions.
2392 __slots__ = ("tag_constructed", "specs", "defined")
2393 tag_default = tag_encode(3)
2394 asn1_type_name = "BIT STRING"
2407 :param value: set the value. Either binary type, tuple of named
2408 values (if ``schema`` is specified in the class),
2409 string in ``'XXX...'B`` form, or
2410 :py:class:`pyderasn.BitString` object
2411 :param bytes impl: override default tag with ``IMPLICIT`` one
2412 :param bytes expl: override default tag with ``EXPLICIT`` one
2413 :param default: set default value. Type same as in ``value``
2414 :param bool optional: is object ``OPTIONAL`` in sequence
2416 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2417 specs = getattr(self, "schema", {}) if _specs is None else _specs
2418 self.specs = specs if isinstance(specs, dict) else dict(specs)
2419 self._value = None if value is None else self._value_sanitize(value)
2420 if default is not None:
2421 default = self._value_sanitize(default)
2422 self.default = self.__class__(
2428 self._value = default
2430 tag_klass, _, tag_num = tag_decode(self.tag)
2431 self.tag_constructed = tag_encode(
2433 form=TagFormConstructed,
2437 def _bits2octets(self, bits):
2438 if len(self.specs) > 0:
2439 bits = bits.rstrip("0")
2441 bits += "0" * ((8 - (bit_len % 8)) % 8)
2442 octets = bytearray(len(bits) // 8)
2443 for i in six_xrange(len(octets)):
2444 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2445 return bit_len, bytes(octets)
2447 def _value_sanitize(self, value):
2448 if isinstance(value, (string_types, binary_type)):
2450 isinstance(value, string_types) and
2451 value.startswith("'")
2453 if value.endswith("'B"):
2455 if not frozenset(value) <= SET01:
2456 raise ValueError("B's coding contains unacceptable chars")
2457 return self._bits2octets(value)
2458 if value.endswith("'H"):
2462 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2464 if isinstance(value, binary_type):
2465 return (len(value) * 8, value)
2466 raise InvalidValueType((self.__class__, string_types, binary_type))
2467 if isinstance(value, tuple):
2470 isinstance(value[0], integer_types) and
2471 isinstance(value[1], binary_type)
2476 bit = self.specs.get(name)
2478 raise ObjUnknown("BitString value: %s" % name)
2481 return self._bits2octets("")
2482 bits = frozenset(bits)
2483 return self._bits2octets("".join(
2484 ("1" if bit in bits else "0")
2485 for bit in six_xrange(max(bits) + 1)
2487 if issubclass(value.__class__, BitString):
2489 raise InvalidValueType((self.__class__, binary_type, string_types))
2493 return self._value is not None
2495 def __getstate__(self):
2496 return BitStringState(
2510 self.tag_constructed,
2514 def __setstate__(self, state):
2515 super(BitString, self).__setstate__(state)
2516 self.specs = state.specs
2517 self._value = state.value
2518 self.tag = state.tag
2519 self._expl = state.expl
2520 self.default = state.default
2521 self.optional = state.optional
2522 self.offset = state.offset
2523 self.llen = state.llen
2524 self.vlen = state.vlen
2525 self.expl_lenindef = state.expl_lenindef
2526 self.lenindef = state.lenindef
2527 self.ber_encoded = state.ber_encoded
2528 self.tag_constructed = state.tag_constructed
2529 self.defined = state.defined
2532 self._assert_ready()
2533 for i in six_xrange(self._value[0]):
2538 self._assert_ready()
2539 return self._value[0]
2541 def __bytes__(self):
2542 self._assert_ready()
2543 return self._value[1]
2545 def __eq__(self, their):
2546 if isinstance(their, bytes):
2547 return self._value[1] == their
2548 if not issubclass(their.__class__, BitString):
2551 self._value == their._value and
2552 self.tag == their.tag and
2553 self._expl == their._expl
2558 return [name for name, bit in iteritems(self.specs) if self[bit]]
2568 return self.__class__(
2570 impl=self.tag if impl is None else impl,
2571 expl=self._expl if expl is None else expl,
2572 default=self.default if default is None else default,
2573 optional=self.optional if optional is None else optional,
2577 def __getitem__(self, key):
2578 if isinstance(key, int):
2579 bit_len, octets = self._value
2583 byte2int(memoryview(octets)[key // 8:]) >>
2586 if isinstance(key, string_types):
2587 value = self.specs.get(key)
2589 raise ObjUnknown("BitString value: %s" % key)
2591 raise InvalidValueType((int, str))
2594 self._assert_ready()
2595 bit_len, octets = self._value
2598 len_encode(len(octets) + 1),
2599 int2byte((8 - bit_len % 8) % 8),
2603 def _decode_chunk(self, lv, offset, decode_path):
2605 l, llen, v = len_decode(lv)
2606 except DecodeError as err:
2607 raise err.__class__(
2609 klass=self.__class__,
2610 decode_path=decode_path,
2614 raise NotEnoughData(
2615 "encoded length is longer than data",
2616 klass=self.__class__,
2617 decode_path=decode_path,
2621 raise NotEnoughData(
2623 klass=self.__class__,
2624 decode_path=decode_path,
2627 pad_size = byte2int(v)
2628 if l == 1 and pad_size != 0:
2630 "invalid empty value",
2631 klass=self.__class__,
2632 decode_path=decode_path,
2638 klass=self.__class__,
2639 decode_path=decode_path,
2642 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2645 klass=self.__class__,
2646 decode_path=decode_path,
2649 v, tail = v[:l], v[l:]
2650 obj = self.__class__(
2651 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2654 default=self.default,
2655 optional=self.optional,
2657 _decoded=(offset, llen, l),
2661 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2663 t, tlen, lv = tag_strip(tlv)
2664 except DecodeError as err:
2665 raise err.__class__(
2667 klass=self.__class__,
2668 decode_path=decode_path,
2672 if tag_only: # pragma: no cover
2674 return self._decode_chunk(lv, offset, decode_path)
2675 if t == self.tag_constructed:
2676 if not ctx.get("bered", False):
2678 "unallowed BER constructed encoding",
2679 klass=self.__class__,
2680 decode_path=decode_path,
2683 if tag_only: # pragma: no cover
2687 l, llen, v = len_decode(lv)
2688 except LenIndefForm:
2689 llen, l, v = 1, 0, lv[1:]
2691 except DecodeError as err:
2692 raise err.__class__(
2694 klass=self.__class__,
2695 decode_path=decode_path,
2699 raise NotEnoughData(
2700 "encoded length is longer than data",
2701 klass=self.__class__,
2702 decode_path=decode_path,
2705 if not lenindef and l == 0:
2706 raise NotEnoughData(
2708 klass=self.__class__,
2709 decode_path=decode_path,
2713 sub_offset = offset + tlen + llen
2717 if v[:EOC_LEN].tobytes() == EOC:
2724 "chunk out of bounds",
2725 klass=self.__class__,
2726 decode_path=decode_path + (str(len(chunks) - 1),),
2727 offset=chunks[-1].offset,
2729 sub_decode_path = decode_path + (str(len(chunks)),)
2731 chunk, v_tail = BitString().decode(
2734 decode_path=sub_decode_path,
2737 _ctx_immutable=False,
2741 "expected BitString encoded chunk",
2742 klass=self.__class__,
2743 decode_path=sub_decode_path,
2746 chunks.append(chunk)
2747 sub_offset += chunk.tlvlen
2748 vlen += chunk.tlvlen
2750 if len(chunks) == 0:
2753 klass=self.__class__,
2754 decode_path=decode_path,
2759 for chunk_i, chunk in enumerate(chunks[:-1]):
2760 if chunk.bit_len % 8 != 0:
2762 "BitString chunk is not multiple of 8 bits",
2763 klass=self.__class__,
2764 decode_path=decode_path + (str(chunk_i),),
2765 offset=chunk.offset,
2767 values.append(bytes(chunk))
2768 bit_len += chunk.bit_len
2769 chunk_last = chunks[-1]
2770 values.append(bytes(chunk_last))
2771 bit_len += chunk_last.bit_len
2772 obj = self.__class__(
2773 value=(bit_len, b"".join(values)),
2776 default=self.default,
2777 optional=self.optional,
2779 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2781 obj.lenindef = lenindef
2782 obj.ber_encoded = True
2783 return obj, (v[EOC_LEN:] if lenindef else v)
2785 klass=self.__class__,
2786 decode_path=decode_path,
2791 return pp_console_row(next(self.pps()))
2793 def pps(self, decode_path=()):
2797 bit_len, blob = self._value
2798 value = "%d bits" % bit_len
2799 if len(self.specs) > 0:
2800 blob = tuple(self.named)
2803 asn1_type_name=self.asn1_type_name,
2804 obj_name=self.__class__.__name__,
2805 decode_path=decode_path,
2808 optional=self.optional,
2809 default=self == self.default,
2810 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2811 expl=None if self._expl is None else tag_decode(self._expl),
2816 expl_offset=self.expl_offset if self.expled else None,
2817 expl_tlen=self.expl_tlen if self.expled else None,
2818 expl_llen=self.expl_llen if self.expled else None,
2819 expl_vlen=self.expl_vlen if self.expled else None,
2820 expl_lenindef=self.expl_lenindef,
2821 lenindef=self.lenindef,
2822 ber_encoded=self.ber_encoded,
2825 defined_by, defined = self.defined or (None, None)
2826 if defined_by is not None:
2828 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2830 for pp in self.pps_lenindef(decode_path):
2834 OctetStringState = namedtuple("OctetStringState", (
2854 class OctetString(Obj):
2855 """``OCTET STRING`` binary string type
2857 >>> s = OctetString(b"hello world")
2858 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2859 >>> s == OctetString(b"hello world")
2864 >>> OctetString(b"hello", bounds=(4, 4))
2865 Traceback (most recent call last):
2866 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2867 >>> OctetString(b"hell", bounds=(4, 4))
2868 OCTET STRING 4 bytes 68656c6c
2872 Pay attention that OCTET STRING can be encoded both in primitive
2873 and constructed forms. Decoder always checks constructed form tag
2874 additionally to specified primitive one. If BER decoding is
2875 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2876 of DER restrictions.
2878 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2879 tag_default = tag_encode(4)
2880 asn1_type_name = "OCTET STRING"
2893 :param value: set the value. Either binary type, or
2894 :py:class:`pyderasn.OctetString` object
2895 :param bounds: set ``(MIN, MAX)`` value size constraint.
2896 (-inf, +inf) by default
2897 :param bytes impl: override default tag with ``IMPLICIT`` one
2898 :param bytes expl: override default tag with ``EXPLICIT`` one
2899 :param default: set default value. Type same as in ``value``
2900 :param bool optional: is object ``OPTIONAL`` in sequence
2902 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2904 self._bound_min, self._bound_max = getattr(
2908 ) if bounds is None else bounds
2909 if value is not None:
2910 self._value = self._value_sanitize(value)
2911 if default is not None:
2912 default = self._value_sanitize(default)
2913 self.default = self.__class__(
2918 if self._value is None:
2919 self._value = default
2921 tag_klass, _, tag_num = tag_decode(self.tag)
2922 self.tag_constructed = tag_encode(
2924 form=TagFormConstructed,
2928 def _value_sanitize(self, value):
2929 if isinstance(value, binary_type):
2931 elif issubclass(value.__class__, OctetString):
2932 value = value._value
2934 raise InvalidValueType((self.__class__, bytes))
2935 if not self._bound_min <= len(value) <= self._bound_max:
2936 raise BoundsError(self._bound_min, len(value), self._bound_max)
2941 return self._value is not None
2943 def __getstate__(self):
2944 return OctetStringState(
2959 self.tag_constructed,
2963 def __setstate__(self, state):
2964 super(OctetString, self).__setstate__(state)
2965 self._value = state.value
2966 self._bound_min = state.bound_min
2967 self._bound_max = state.bound_max
2968 self.tag = state.tag
2969 self._expl = state.expl
2970 self.default = state.default
2971 self.optional = state.optional
2972 self.offset = state.offset
2973 self.llen = state.llen
2974 self.vlen = state.vlen
2975 self.expl_lenindef = state.expl_lenindef
2976 self.lenindef = state.lenindef
2977 self.ber_encoded = state.ber_encoded
2978 self.tag_constructed = state.tag_constructed
2979 self.defined = state.defined
2981 def __bytes__(self):
2982 self._assert_ready()
2985 def __eq__(self, their):
2986 if isinstance(their, binary_type):
2987 return self._value == their
2988 if not issubclass(their.__class__, OctetString):
2991 self._value == their._value and
2992 self.tag == their.tag and
2993 self._expl == their._expl
2996 def __lt__(self, their):
2997 return self._value < their._value
3008 return self.__class__(
3011 (self._bound_min, self._bound_max)
3012 if bounds is None else bounds
3014 impl=self.tag if impl is None else impl,
3015 expl=self._expl if expl is None else expl,
3016 default=self.default if default is None else default,
3017 optional=self.optional if optional is None else optional,
3021 self._assert_ready()
3024 len_encode(len(self._value)),
3028 def _decode_chunk(self, lv, offset, decode_path):
3030 l, llen, v = len_decode(lv)
3031 except DecodeError as err:
3032 raise err.__class__(
3034 klass=self.__class__,
3035 decode_path=decode_path,
3039 raise NotEnoughData(
3040 "encoded length is longer than data",
3041 klass=self.__class__,
3042 decode_path=decode_path,
3045 v, tail = v[:l], v[l:]
3047 obj = self.__class__(
3049 bounds=(self._bound_min, self._bound_max),
3052 default=self.default,
3053 optional=self.optional,
3054 _decoded=(offset, llen, l),
3056 except DecodeError as err:
3059 klass=self.__class__,
3060 decode_path=decode_path,
3063 except BoundsError as err:
3066 klass=self.__class__,
3067 decode_path=decode_path,
3072 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3074 t, tlen, lv = tag_strip(tlv)
3075 except DecodeError as err:
3076 raise err.__class__(
3078 klass=self.__class__,
3079 decode_path=decode_path,
3085 return self._decode_chunk(lv, offset, decode_path)
3086 if t == self.tag_constructed:
3087 if not ctx.get("bered", False):
3089 "unallowed BER constructed encoding",
3090 klass=self.__class__,
3091 decode_path=decode_path,
3098 l, llen, v = len_decode(lv)
3099 except LenIndefForm:
3100 llen, l, v = 1, 0, lv[1:]
3102 except DecodeError as err:
3103 raise err.__class__(
3105 klass=self.__class__,
3106 decode_path=decode_path,
3110 raise NotEnoughData(
3111 "encoded length is longer than data",
3112 klass=self.__class__,
3113 decode_path=decode_path,
3117 sub_offset = offset + tlen + llen
3121 if v[:EOC_LEN].tobytes() == EOC:
3128 "chunk out of bounds",
3129 klass=self.__class__,
3130 decode_path=decode_path + (str(len(chunks) - 1),),
3131 offset=chunks[-1].offset,
3133 sub_decode_path = decode_path + (str(len(chunks)),)
3135 chunk, v_tail = OctetString().decode(
3138 decode_path=sub_decode_path,
3141 _ctx_immutable=False,
3145 "expected OctetString encoded chunk",
3146 klass=self.__class__,
3147 decode_path=sub_decode_path,
3150 chunks.append(chunk)
3151 sub_offset += chunk.tlvlen
3152 vlen += chunk.tlvlen
3155 obj = self.__class__(
3156 value=b"".join(bytes(chunk) for chunk in chunks),
3157 bounds=(self._bound_min, self._bound_max),
3160 default=self.default,
3161 optional=self.optional,
3162 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3164 except DecodeError as err:
3167 klass=self.__class__,
3168 decode_path=decode_path,
3171 except BoundsError as err:
3174 klass=self.__class__,
3175 decode_path=decode_path,
3178 obj.lenindef = lenindef
3179 obj.ber_encoded = True
3180 return obj, (v[EOC_LEN:] if lenindef else v)
3182 klass=self.__class__,
3183 decode_path=decode_path,
3188 return pp_console_row(next(self.pps()))
3190 def pps(self, decode_path=()):
3193 asn1_type_name=self.asn1_type_name,
3194 obj_name=self.__class__.__name__,
3195 decode_path=decode_path,
3196 value=("%d bytes" % len(self._value)) if self.ready else None,
3197 blob=self._value if self.ready else None,
3198 optional=self.optional,
3199 default=self == self.default,
3200 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3201 expl=None if self._expl is None else tag_decode(self._expl),
3206 expl_offset=self.expl_offset if self.expled else None,
3207 expl_tlen=self.expl_tlen if self.expled else None,
3208 expl_llen=self.expl_llen if self.expled else None,
3209 expl_vlen=self.expl_vlen if self.expled else None,
3210 expl_lenindef=self.expl_lenindef,
3211 lenindef=self.lenindef,
3212 ber_encoded=self.ber_encoded,
3215 defined_by, defined = self.defined or (None, None)
3216 if defined_by is not None:
3218 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3220 for pp in self.pps_lenindef(decode_path):
3224 NullState = namedtuple("NullState", (
3240 """``NULL`` null object
3248 tag_default = tag_encode(5)
3249 asn1_type_name = "NULL"
3253 value=None, # unused, but Sequence passes it
3260 :param bytes impl: override default tag with ``IMPLICIT`` one
3261 :param bytes expl: override default tag with ``EXPLICIT`` one
3262 :param bool optional: is object ``OPTIONAL`` in sequence
3264 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3271 def __getstate__(self):
3286 def __setstate__(self, state):
3287 super(Null, self).__setstate__(state)
3288 self.tag = state.tag
3289 self._expl = state.expl
3290 self.default = state.default
3291 self.optional = state.optional
3292 self.offset = state.offset
3293 self.llen = state.llen
3294 self.vlen = state.vlen
3295 self.expl_lenindef = state.expl_lenindef
3296 self.lenindef = state.lenindef
3297 self.ber_encoded = state.ber_encoded
3299 def __eq__(self, their):
3300 if not issubclass(their.__class__, Null):
3303 self.tag == their.tag and
3304 self._expl == their._expl
3314 return self.__class__(
3315 impl=self.tag if impl is None else impl,
3316 expl=self._expl if expl is None else expl,
3317 optional=self.optional if optional is None else optional,
3321 return self.tag + len_encode(0)
3323 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3325 t, _, lv = tag_strip(tlv)
3326 except DecodeError as err:
3327 raise err.__class__(
3329 klass=self.__class__,
3330 decode_path=decode_path,
3335 klass=self.__class__,
3336 decode_path=decode_path,
3339 if tag_only: # pragma: no cover
3342 l, _, v = len_decode(lv)
3343 except DecodeError as err:
3344 raise err.__class__(
3346 klass=self.__class__,
3347 decode_path=decode_path,
3351 raise InvalidLength(
3352 "Null must have zero length",
3353 klass=self.__class__,
3354 decode_path=decode_path,
3357 obj = self.__class__(
3360 optional=self.optional,
3361 _decoded=(offset, 1, 0),
3366 return pp_console_row(next(self.pps()))
3368 def pps(self, decode_path=()):
3371 asn1_type_name=self.asn1_type_name,
3372 obj_name=self.__class__.__name__,
3373 decode_path=decode_path,
3374 optional=self.optional,
3375 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3376 expl=None if self._expl is None else tag_decode(self._expl),
3381 expl_offset=self.expl_offset if self.expled else None,
3382 expl_tlen=self.expl_tlen if self.expled else None,
3383 expl_llen=self.expl_llen if self.expled else None,
3384 expl_vlen=self.expl_vlen if self.expled else None,
3385 expl_lenindef=self.expl_lenindef,
3388 for pp in self.pps_lenindef(decode_path):
3392 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3409 class ObjectIdentifier(Obj):
3410 """``OBJECT IDENTIFIER`` OID type
3412 >>> oid = ObjectIdentifier((1, 2, 3))
3413 OBJECT IDENTIFIER 1.2.3
3414 >>> oid == ObjectIdentifier("1.2.3")
3420 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3421 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3423 >>> str(ObjectIdentifier((3, 1)))
3424 Traceback (most recent call last):
3425 pyderasn.InvalidOID: unacceptable first arc value
3427 __slots__ = ("defines",)
3428 tag_default = tag_encode(6)
3429 asn1_type_name = "OBJECT IDENTIFIER"
3442 :param value: set the value. Either tuples of integers,
3443 string of "."-concatenated integers, or
3444 :py:class:`pyderasn.ObjectIdentifier` object
3445 :param defines: sequence of tuples. Each tuple has two elements.
3446 First one is relative to current one decode
3447 path, aiming to the field defined by that OID.
3448 Read about relative path in
3449 :py:func:`pyderasn.abs_decode_path`. Second
3450 tuple element is ``{OID: pyderasn.Obj()}``
3451 dictionary, mapping between current OID value
3452 and structure applied to defined field.
3453 :ref:`Read about DEFINED BY <definedby>`
3454 :param bytes impl: override default tag with ``IMPLICIT`` one
3455 :param bytes expl: override default tag with ``EXPLICIT`` one
3456 :param default: set default value. Type same as in ``value``
3457 :param bool optional: is object ``OPTIONAL`` in sequence
3459 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3461 if value is not None:
3462 self._value = self._value_sanitize(value)
3463 if default is not None:
3464 default = self._value_sanitize(default)
3465 self.default = self.__class__(
3470 if self._value is None:
3471 self._value = default
3472 self.defines = defines
3474 def __add__(self, their):
3475 if isinstance(their, self.__class__):
3476 return self.__class__(self._value + their._value)
3477 if isinstance(their, tuple):
3478 return self.__class__(self._value + their)
3479 raise InvalidValueType((self.__class__, tuple))
3481 def _value_sanitize(self, value):
3482 if issubclass(value.__class__, ObjectIdentifier):
3484 if isinstance(value, string_types):
3486 value = tuple(int(arc) for arc in value.split("."))
3488 raise InvalidOID("unacceptable arcs values")
3489 if isinstance(value, tuple):
3491 raise InvalidOID("less than 2 arcs")
3492 first_arc = value[0]
3493 if first_arc in (0, 1):
3494 if not (0 <= value[1] <= 39):
3495 raise InvalidOID("second arc is too wide")
3496 elif first_arc == 2:
3499 raise InvalidOID("unacceptable first arc value")
3501 raise InvalidValueType((self.__class__, str, tuple))
3505 return self._value is not None
3507 def __getstate__(self):
3508 return ObjectIdentifierState(
3524 def __setstate__(self, state):
3525 super(ObjectIdentifier, self).__setstate__(state)
3526 self._value = state.value
3527 self.tag = state.tag
3528 self._expl = state.expl
3529 self.default = state.default
3530 self.optional = state.optional
3531 self.offset = state.offset
3532 self.llen = state.llen
3533 self.vlen = state.vlen
3534 self.expl_lenindef = state.expl_lenindef
3535 self.lenindef = state.lenindef
3536 self.ber_encoded = state.ber_encoded
3537 self.defines = state.defines
3540 self._assert_ready()
3541 return iter(self._value)
3544 return ".".join(str(arc) for arc in self._value or ())
3547 self._assert_ready()
3550 bytes(self._expl or b"") +
3551 str(self._value).encode("ascii"),
3554 def __eq__(self, their):
3555 if isinstance(their, tuple):
3556 return self._value == their
3557 if not issubclass(their.__class__, ObjectIdentifier):
3560 self.tag == their.tag and
3561 self._expl == their._expl and
3562 self._value == their._value
3565 def __lt__(self, their):
3566 return self._value < their._value
3577 return self.__class__(
3579 defines=self.defines if defines is None else defines,
3580 impl=self.tag if impl is None else impl,
3581 expl=self._expl if expl is None else expl,
3582 default=self.default if default is None else default,
3583 optional=self.optional if optional is None else optional,
3587 self._assert_ready()
3589 first_value = value[1]
3590 first_arc = value[0]
3593 elif first_arc == 1:
3595 elif first_arc == 2:
3597 else: # pragma: no cover
3598 raise RuntimeError("invalid arc is stored")
3599 octets = [zero_ended_encode(first_value)]
3600 for arc in value[2:]:
3601 octets.append(zero_ended_encode(arc))
3602 v = b"".join(octets)
3603 return b"".join((self.tag, len_encode(len(v)), v))
3605 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3607 t, _, lv = tag_strip(tlv)
3608 except DecodeError as err:
3609 raise err.__class__(
3611 klass=self.__class__,
3612 decode_path=decode_path,
3617 klass=self.__class__,
3618 decode_path=decode_path,
3621 if tag_only: # pragma: no cover
3624 l, llen, v = len_decode(lv)
3625 except DecodeError as err:
3626 raise err.__class__(
3628 klass=self.__class__,
3629 decode_path=decode_path,
3633 raise NotEnoughData(
3634 "encoded length is longer than data",
3635 klass=self.__class__,
3636 decode_path=decode_path,
3640 raise NotEnoughData(
3642 klass=self.__class__,
3643 decode_path=decode_path,
3646 v, tail = v[:l], v[l:]
3653 octet = indexbytes(v, i)
3654 if i == 0 and octet == 0x80:
3655 if ctx.get("bered", False):
3658 raise DecodeError("non normalized arc encoding")
3659 arc = (arc << 7) | (octet & 0x7F)
3660 if octet & 0x80 == 0:
3668 klass=self.__class__,
3669 decode_path=decode_path,
3673 second_arc = arcs[0]
3674 if 0 <= second_arc <= 39:
3676 elif 40 <= second_arc <= 79:
3682 obj = self.__class__(
3683 value=tuple([first_arc, second_arc] + arcs[1:]),
3686 default=self.default,
3687 optional=self.optional,
3688 _decoded=(offset, llen, l),
3691 obj.ber_encoded = True
3695 return pp_console_row(next(self.pps()))
3697 def pps(self, decode_path=()):
3700 asn1_type_name=self.asn1_type_name,
3701 obj_name=self.__class__.__name__,
3702 decode_path=decode_path,
3703 value=str(self) if self.ready else None,
3704 optional=self.optional,
3705 default=self == self.default,
3706 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3707 expl=None if self._expl is None else tag_decode(self._expl),
3712 expl_offset=self.expl_offset if self.expled else None,
3713 expl_tlen=self.expl_tlen if self.expled else None,
3714 expl_llen=self.expl_llen if self.expled else None,
3715 expl_vlen=self.expl_vlen if self.expled else None,
3716 expl_lenindef=self.expl_lenindef,
3717 ber_encoded=self.ber_encoded,
3720 for pp in self.pps_lenindef(decode_path):
3724 class Enumerated(Integer):
3725 """``ENUMERATED`` integer type
3727 This type is identical to :py:class:`pyderasn.Integer`, but requires
3728 schema to be specified and does not accept values missing from it.
3731 tag_default = tag_encode(10)
3732 asn1_type_name = "ENUMERATED"
3743 bounds=None, # dummy argument, workability for Integer.decode
3745 super(Enumerated, self).__init__(
3746 value, bounds, impl, expl, default, optional, _specs, _decoded,
3748 if len(self.specs) == 0:
3749 raise ValueError("schema must be specified")
3751 def _value_sanitize(self, value):
3752 if isinstance(value, self.__class__):
3753 value = value._value
3754 elif isinstance(value, integer_types):
3755 for _value in itervalues(self.specs):
3760 "unknown integer value: %s" % value,
3761 klass=self.__class__,
3763 elif isinstance(value, string_types):
3764 value = self.specs.get(value)
3766 raise ObjUnknown("integer value: %s" % value)
3768 raise InvalidValueType((self.__class__, int, str))
3780 return self.__class__(
3782 impl=self.tag if impl is None else impl,
3783 expl=self._expl if expl is None else expl,
3784 default=self.default if default is None else default,
3785 optional=self.optional if optional is None else optional,
3790 def escape_control_unicode(c):
3791 if unicat(c).startswith("C"):
3792 c = repr(c).lstrip("u").strip("'")
3796 class CommonString(OctetString):
3797 """Common class for all strings
3799 Everything resembles :py:class:`pyderasn.OctetString`, except
3800 ability to deal with unicode text strings.
3802 >>> hexenc("привет мир".encode("utf-8"))
3803 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3804 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3806 >>> s = UTF8String("привет мир")
3807 UTF8String UTF8String привет мир
3809 'привет мир'
3810 >>> hexenc(bytes(s))
3811 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3813 >>> PrintableString("привет мир")
3814 Traceback (most recent call last):
3815 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3817 >>> BMPString("ада", bounds=(2, 2))
3818 Traceback (most recent call last):
3819 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3820 >>> s = BMPString("ад", bounds=(2, 2))
3823 >>> hexenc(bytes(s))
3831 * - :py:class:`pyderasn.UTF8String`
3833 * - :py:class:`pyderasn.NumericString`
3835 * - :py:class:`pyderasn.PrintableString`
3837 * - :py:class:`pyderasn.TeletexString`
3839 * - :py:class:`pyderasn.T61String`
3841 * - :py:class:`pyderasn.VideotexString`
3843 * - :py:class:`pyderasn.IA5String`
3845 * - :py:class:`pyderasn.GraphicString`
3847 * - :py:class:`pyderasn.VisibleString`
3849 * - :py:class:`pyderasn.ISO646String`
3851 * - :py:class:`pyderasn.GeneralString`
3853 * - :py:class:`pyderasn.UniversalString`
3855 * - :py:class:`pyderasn.BMPString`
3860 def _value_sanitize(self, value):
3862 value_decoded = None
3863 if isinstance(value, self.__class__):
3864 value_raw = value._value
3865 elif isinstance(value, text_type):
3866 value_decoded = value
3867 elif isinstance(value, binary_type):
3870 raise InvalidValueType((self.__class__, text_type, binary_type))
3873 value_decoded.encode(self.encoding)
3874 if value_raw is None else value_raw
3877 value_raw.decode(self.encoding)
3878 if value_decoded is None else value_decoded
3880 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3881 raise DecodeError(str(err))
3882 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3890 def __eq__(self, their):
3891 if isinstance(their, binary_type):
3892 return self._value == their
3893 if isinstance(their, text_type):
3894 return self._value == their.encode(self.encoding)
3895 if not isinstance(their, self.__class__):
3898 self._value == their._value and
3899 self.tag == their.tag and
3900 self._expl == their._expl
3903 def __unicode__(self):
3905 return self._value.decode(self.encoding)
3906 return text_type(self._value)
3909 return pp_console_row(next(self.pps(no_unicode=PY2)))
3911 def pps(self, decode_path=(), no_unicode=False):
3915 hexenc(bytes(self)) if no_unicode else
3916 "".join(escape_control_unicode(c) for c in self.__unicode__())
3920 asn1_type_name=self.asn1_type_name,
3921 obj_name=self.__class__.__name__,
3922 decode_path=decode_path,
3924 optional=self.optional,
3925 default=self == self.default,
3926 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3927 expl=None if self._expl is None else tag_decode(self._expl),
3932 expl_offset=self.expl_offset if self.expled else None,
3933 expl_tlen=self.expl_tlen if self.expled else None,
3934 expl_llen=self.expl_llen if self.expled else None,
3935 expl_vlen=self.expl_vlen if self.expled else None,
3936 expl_lenindef=self.expl_lenindef,
3937 ber_encoded=self.ber_encoded,
3940 for pp in self.pps_lenindef(decode_path):
3944 class UTF8String(CommonString):
3946 tag_default = tag_encode(12)
3948 asn1_type_name = "UTF8String"
3951 class AllowableCharsMixin(object):
3953 def allowable_chars(self):
3955 return self._allowable_chars
3956 return frozenset(six_unichr(c) for c in self._allowable_chars)
3959 class NumericString(AllowableCharsMixin, CommonString):
3962 Its value is properly sanitized: only ASCII digits with spaces can
3965 >>> NumericString().allowable_chars
3966 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3969 tag_default = tag_encode(18)
3971 asn1_type_name = "NumericString"
3972 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3974 def _value_sanitize(self, value):
3975 value = super(NumericString, self)._value_sanitize(value)
3976 if not frozenset(value) <= self._allowable_chars:
3977 raise DecodeError("non-numeric value")
3981 PrintableStringState = namedtuple(
3982 "PrintableStringState",
3983 OctetStringState._fields + ("allowable_chars",),
3987 class PrintableString(AllowableCharsMixin, CommonString):
3990 Its value is properly sanitized: see X.680 41.4 table 10.
3992 >>> PrintableString().allowable_chars
3993 frozenset([' ', "'", ..., 'z'])
3994 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
3995 PrintableString PrintableString foo*bar
3996 >>> obj.allow_asterisk, obj.allow_ampersand
4000 tag_default = tag_encode(19)
4002 asn1_type_name = "PrintableString"
4003 _allowable_chars = frozenset(
4004 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4006 _asterisk = frozenset("*".encode("ascii"))
4007 _ampersand = frozenset("&".encode("ascii"))
4018 allow_asterisk=False,
4019 allow_ampersand=False,
4022 :param allow_asterisk: allow asterisk character
4023 :param allow_ampersand: allow ampersand character
4026 self._allowable_chars |= self._asterisk
4028 self._allowable_chars |= self._ampersand
4029 super(PrintableString, self).__init__(
4030 value, bounds, impl, expl, default, optional, _decoded,
4034 def allow_asterisk(self):
4035 """Is asterisk character allowed?
4037 return self._asterisk <= self._allowable_chars
4040 def allow_ampersand(self):
4041 """Is ampersand character allowed?
4043 return self._ampersand <= self._allowable_chars
4045 def _value_sanitize(self, value):
4046 value = super(PrintableString, self)._value_sanitize(value)
4047 if not frozenset(value) <= self._allowable_chars:
4048 raise DecodeError("non-printable value")
4051 def __getstate__(self):
4052 return PrintableStringState(
4053 *super(PrintableString, self).__getstate__(),
4054 **{"allowable_chars": self._allowable_chars}
4057 def __setstate__(self, state):
4058 super(PrintableString, self).__setstate__(state)
4059 self._allowable_chars = state.allowable_chars
4070 return self.__class__(
4073 (self._bound_min, self._bound_max)
4074 if bounds is None else bounds
4076 impl=self.tag if impl is None else impl,
4077 expl=self._expl if expl is None else expl,
4078 default=self.default if default is None else default,
4079 optional=self.optional if optional is None else optional,
4080 allow_asterisk=self.allow_asterisk,
4081 allow_ampersand=self.allow_ampersand,
4085 class TeletexString(CommonString):
4087 tag_default = tag_encode(20)
4089 asn1_type_name = "TeletexString"
4092 class T61String(TeletexString):
4094 asn1_type_name = "T61String"
4097 class VideotexString(CommonString):
4099 tag_default = tag_encode(21)
4100 encoding = "iso-8859-1"
4101 asn1_type_name = "VideotexString"
4104 class IA5String(CommonString):
4106 tag_default = tag_encode(22)
4108 asn1_type_name = "IA5"
4111 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4112 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4113 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4116 class UTCTime(CommonString):
4117 """``UTCTime`` datetime type
4119 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4120 UTCTime UTCTime 2017-09-30T22:07:50
4126 datetime.datetime(2017, 9, 30, 22, 7, 50)
4127 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4128 datetime.datetime(1957, 9, 30, 22, 7, 50)
4132 BER encoding is unsupported.
4135 tag_default = tag_encode(23)
4137 asn1_type_name = "UTCTime"
4147 bounds=None, # dummy argument, workability for OctetString.decode
4150 :param value: set the value. Either datetime type, or
4151 :py:class:`pyderasn.UTCTime` object
4152 :param bytes impl: override default tag with ``IMPLICIT`` one
4153 :param bytes expl: override default tag with ``EXPLICIT`` one
4154 :param default: set default value. Type same as in ``value``
4155 :param bool optional: is object ``OPTIONAL`` in sequence
4157 super(UTCTime, self).__init__(
4158 None, None, impl, expl, default, optional, _decoded,
4161 if value is not None:
4162 self._value = self._value_sanitize(value)
4163 if default is not None:
4164 default = self._value_sanitize(default)
4165 self.default = self.__class__(
4170 if self._value is None:
4171 self._value = default
4173 def _strptime(self, value):
4174 # datetime.strptime's format: %y%m%d%H%M%SZ
4175 if len(value) != LEN_YYMMDDHHMMSSZ:
4176 raise ValueError("invalid UTCTime length")
4177 if value[-1] != "Z":
4178 raise ValueError("non UTC timezone")
4180 2000 + int(value[:2]), # %y
4181 int(value[2:4]), # %m
4182 int(value[4:6]), # %d
4183 int(value[6:8]), # %H
4184 int(value[8:10]), # %M
4185 int(value[10:12]), # %S
4188 def _value_sanitize(self, value):
4189 if isinstance(value, binary_type):
4191 value_decoded = value.decode("ascii")
4192 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4193 raise DecodeError("invalid UTCTime encoding: %r" % err)
4195 self._strptime(value_decoded)
4196 except (TypeError, ValueError) as err:
4197 raise DecodeError("invalid UTCTime format: %r" % err)
4199 if isinstance(value, self.__class__):
4201 if isinstance(value, datetime):
4202 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4203 raise InvalidValueType((self.__class__, datetime))
4205 def __eq__(self, their):
4206 if isinstance(their, binary_type):
4207 return self._value == their
4208 if isinstance(their, datetime):
4209 return self.todatetime() == their
4210 if not isinstance(their, self.__class__):
4213 self._value == their._value and
4214 self.tag == their.tag and
4215 self._expl == their._expl
4218 def todatetime(self):
4219 """Convert to datetime
4223 Pay attention that UTCTime can not hold full year, so all years
4224 having < 50 years are treated as 20xx, 19xx otherwise, according
4225 to X.509 recomendation.
4227 value = self._strptime(self._value.decode("ascii"))
4228 year = value.year % 100
4230 year=(2000 + year) if year < 50 else (1900 + year),
4234 minute=value.minute,
4235 second=value.second,
4239 return pp_console_row(next(self.pps()))
4241 def pps(self, decode_path=()):
4244 asn1_type_name=self.asn1_type_name,
4245 obj_name=self.__class__.__name__,
4246 decode_path=decode_path,
4247 value=self.todatetime().isoformat() if self.ready else None,
4248 optional=self.optional,
4249 default=self == self.default,
4250 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4251 expl=None if self._expl is None else tag_decode(self._expl),
4256 expl_offset=self.expl_offset if self.expled else None,
4257 expl_tlen=self.expl_tlen if self.expled else None,
4258 expl_llen=self.expl_llen if self.expled else None,
4259 expl_vlen=self.expl_vlen if self.expled else None,
4260 expl_lenindef=self.expl_lenindef,
4261 ber_encoded=self.ber_encoded,
4264 for pp in self.pps_lenindef(decode_path):
4268 class GeneralizedTime(UTCTime):
4269 """``GeneralizedTime`` datetime type
4271 This type is similar to :py:class:`pyderasn.UTCTime`.
4273 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4274 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4276 '20170930220750.000123Z'
4277 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4278 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4282 BER encoding is unsupported.
4286 Only microsecond fractions are supported.
4287 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4288 higher precision values.
4291 tag_default = tag_encode(24)
4292 asn1_type_name = "GeneralizedTime"
4294 def _strptime(self, value):
4296 if l == LEN_YYYYMMDDHHMMSSZ:
4297 # datetime.strptime's format: %y%m%d%H%M%SZ
4298 if value[-1] != "Z":
4299 raise ValueError("non UTC timezone")
4301 int(value[:4]), # %Y
4302 int(value[4:6]), # %m
4303 int(value[6:8]), # %d
4304 int(value[8:10]), # %H
4305 int(value[10:12]), # %M
4306 int(value[12:14]), # %S
4308 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4309 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4310 if value[-1] != "Z":
4311 raise ValueError("non UTC timezone")
4312 if value[14] != ".":
4313 raise ValueError("no fractions separator")
4316 raise ValueError("trailing zero")
4319 raise ValueError("only microsecond fractions are supported")
4320 us = int(us + ("0" * (6 - us_len)))
4322 int(value[:4]), # %Y
4323 int(value[4:6]), # %m
4324 int(value[6:8]), # %d
4325 int(value[8:10]), # %H
4326 int(value[10:12]), # %M
4327 int(value[12:14]), # %S
4331 raise ValueError("invalid GeneralizedTime length")
4333 def _value_sanitize(self, value):
4334 if isinstance(value, binary_type):
4336 value_decoded = value.decode("ascii")
4337 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4338 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4340 self._strptime(value_decoded)
4341 except (TypeError, ValueError) as err:
4343 "invalid GeneralizedTime format: %r" % err,
4344 klass=self.__class__,
4347 if isinstance(value, self.__class__):
4349 if isinstance(value, datetime):
4350 encoded = value.strftime("%Y%m%d%H%M%S")
4351 if value.microsecond > 0:
4352 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4353 return (encoded + "Z").encode("ascii")
4354 raise InvalidValueType((self.__class__, datetime))
4356 def todatetime(self):
4357 return self._strptime(self._value.decode("ascii"))
4360 class GraphicString(CommonString):
4362 tag_default = tag_encode(25)
4363 encoding = "iso-8859-1"
4364 asn1_type_name = "GraphicString"
4367 class VisibleString(CommonString):
4369 tag_default = tag_encode(26)
4371 asn1_type_name = "VisibleString"
4374 class ISO646String(VisibleString):
4376 asn1_type_name = "ISO646String"
4379 class GeneralString(CommonString):
4381 tag_default = tag_encode(27)
4382 encoding = "iso-8859-1"
4383 asn1_type_name = "GeneralString"
4386 class UniversalString(CommonString):
4388 tag_default = tag_encode(28)
4389 encoding = "utf-32-be"
4390 asn1_type_name = "UniversalString"
4393 class BMPString(CommonString):
4395 tag_default = tag_encode(30)
4396 encoding = "utf-16-be"
4397 asn1_type_name = "BMPString"
4400 ChoiceState = namedtuple("ChoiceState", (
4418 """``CHOICE`` special type
4422 class GeneralName(Choice):
4424 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4425 ("dNSName", IA5String(impl=tag_ctxp(2))),
4428 >>> gn = GeneralName()
4430 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4431 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4432 >>> gn["dNSName"] = IA5String("bar.baz")
4433 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4434 >>> gn["rfc822Name"]
4437 [2] IA5String IA5 bar.baz
4440 >>> gn.value == gn["dNSName"]
4443 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4445 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4446 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4448 __slots__ = ("specs",)
4450 asn1_type_name = "CHOICE"
4463 :param value: set the value. Either ``(choice, value)`` tuple, or
4464 :py:class:`pyderasn.Choice` object
4465 :param bytes impl: can not be set, do **not** use it
4466 :param bytes expl: override default tag with ``EXPLICIT`` one
4467 :param default: set default value. Type same as in ``value``
4468 :param bool optional: is object ``OPTIONAL`` in sequence
4470 if impl is not None:
4471 raise ValueError("no implicit tag allowed for CHOICE")
4472 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4474 schema = getattr(self, "schema", ())
4475 if len(schema) == 0:
4476 raise ValueError("schema must be specified")
4478 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4481 if value is not None:
4482 self._value = self._value_sanitize(value)
4483 if default is not None:
4484 default_value = self._value_sanitize(default)
4485 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4486 default_obj.specs = self.specs
4487 default_obj._value = default_value
4488 self.default = default_obj
4490 self._value = copy(default_obj._value)
4492 def _value_sanitize(self, value):
4493 if isinstance(value, tuple) and len(value) == 2:
4495 spec = self.specs.get(choice)
4497 raise ObjUnknown(choice)
4498 if not isinstance(obj, spec.__class__):
4499 raise InvalidValueType((spec,))
4500 return (choice, spec(obj))
4501 if isinstance(value, self.__class__):
4503 raise InvalidValueType((self.__class__, tuple))
4507 return self._value is not None and self._value[1].ready
4511 return self.expl_lenindef or (
4512 (self._value is not None) and
4513 self._value[1].bered
4516 def __getstate__(self):
4533 def __setstate__(self, state):
4534 super(Choice, self).__setstate__(state)
4535 self.specs = state.specs
4536 self._value = state.value
4537 self._expl = state.expl
4538 self.default = state.default
4539 self.optional = state.optional
4540 self.offset = state.offset
4541 self.llen = state.llen
4542 self.vlen = state.vlen
4543 self.expl_lenindef = state.expl_lenindef
4544 self.lenindef = state.lenindef
4545 self.ber_encoded = state.ber_encoded
4547 def __eq__(self, their):
4548 if isinstance(their, tuple) and len(their) == 2:
4549 return self._value == their
4550 if not isinstance(their, self.__class__):
4553 self.specs == their.specs and
4554 self._value == their._value
4564 return self.__class__(
4567 expl=self._expl if expl is None else expl,
4568 default=self.default if default is None else default,
4569 optional=self.optional if optional is None else optional,
4574 self._assert_ready()
4575 return self._value[0]
4579 self._assert_ready()
4580 return self._value[1]
4582 def __getitem__(self, key):
4583 if key not in self.specs:
4584 raise ObjUnknown(key)
4585 if self._value is None:
4587 choice, value = self._value
4592 def __setitem__(self, key, value):
4593 spec = self.specs.get(key)
4595 raise ObjUnknown(key)
4596 if not isinstance(value, spec.__class__):
4597 raise InvalidValueType((spec.__class__,))
4598 self._value = (key, spec(value))
4606 return self._value[1].decoded if self.ready else False
4609 self._assert_ready()
4610 return self._value[1].encode()
4612 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4613 for choice, spec in iteritems(self.specs):
4614 sub_decode_path = decode_path + (choice,)
4620 decode_path=sub_decode_path,
4623 _ctx_immutable=False,
4630 klass=self.__class__,
4631 decode_path=decode_path,
4634 if tag_only: # pragma: no cover
4636 value, tail = spec.decode(
4640 decode_path=sub_decode_path,
4642 _ctx_immutable=False,
4644 obj = self.__class__(
4647 default=self.default,
4648 optional=self.optional,
4649 _decoded=(offset, 0, value.fulllen),
4651 obj._value = (choice, value)
4655 value = pp_console_row(next(self.pps()))
4657 value = "%s[%r]" % (value, self.value)
4660 def pps(self, decode_path=()):
4663 asn1_type_name=self.asn1_type_name,
4664 obj_name=self.__class__.__name__,
4665 decode_path=decode_path,
4666 value=self.choice if self.ready else None,
4667 optional=self.optional,
4668 default=self == self.default,
4669 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4670 expl=None if self._expl is None else tag_decode(self._expl),
4675 expl_lenindef=self.expl_lenindef,
4679 yield self.value.pps(decode_path=decode_path + (self.choice,))
4680 for pp in self.pps_lenindef(decode_path):
4684 class PrimitiveTypes(Choice):
4685 """Predefined ``CHOICE`` for all generic primitive types
4687 It could be useful for general decoding of some unspecified values:
4689 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4690 OCTET STRING 3 bytes 666f6f
4691 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4695 schema = tuple((klass.__name__, klass()) for klass in (
4719 AnyState = namedtuple("AnyState", (
4736 """``ANY`` special type
4738 >>> Any(Integer(-123))
4740 >>> a = Any(OctetString(b"hello world").encode())
4741 ANY 040b68656c6c6f20776f726c64
4742 >>> hexenc(bytes(a))
4743 b'0x040x0bhello world'
4745 __slots__ = ("defined",)
4746 tag_default = tag_encode(0)
4747 asn1_type_name = "ANY"
4757 :param value: set the value. Either any kind of pyderasn's
4758 **ready** object, or bytes. Pay attention that
4759 **no** validation is performed is raw binary value
4761 :param bytes expl: override default tag with ``EXPLICIT`` one
4762 :param bool optional: is object ``OPTIONAL`` in sequence
4764 super(Any, self).__init__(None, expl, None, optional, _decoded)
4765 self._value = None if value is None else self._value_sanitize(value)
4768 def _value_sanitize(self, value):
4769 if isinstance(value, binary_type):
4771 if isinstance(value, self.__class__):
4773 if isinstance(value, Obj):
4774 return value.encode()
4775 raise InvalidValueType((self.__class__, Obj, binary_type))
4779 return self._value is not None
4783 if self.expl_lenindef or self.lenindef:
4785 if self.defined is None:
4787 return self.defined[1].bered
4789 def __getstate__(self):
4805 def __setstate__(self, state):
4806 super(Any, self).__setstate__(state)
4807 self._value = state.value
4808 self.tag = state.tag
4809 self._expl = state.expl
4810 self.optional = state.optional
4811 self.offset = state.offset
4812 self.llen = state.llen
4813 self.vlen = state.vlen
4814 self.expl_lenindef = state.expl_lenindef
4815 self.lenindef = state.lenindef
4816 self.ber_encoded = state.ber_encoded
4817 self.defined = state.defined
4819 def __eq__(self, their):
4820 if isinstance(their, binary_type):
4821 return self._value == their
4822 if issubclass(their.__class__, Any):
4823 return self._value == their._value
4832 return self.__class__(
4834 expl=self._expl if expl is None else expl,
4835 optional=self.optional if optional is None else optional,
4838 def __bytes__(self):
4839 self._assert_ready()
4847 self._assert_ready()
4850 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4852 t, tlen, lv = tag_strip(tlv)
4853 except DecodeError as err:
4854 raise err.__class__(
4856 klass=self.__class__,
4857 decode_path=decode_path,
4861 l, llen, v = len_decode(lv)
4862 except LenIndefForm as err:
4863 if not ctx.get("bered", False):
4864 raise err.__class__(
4866 klass=self.__class__,
4867 decode_path=decode_path,
4870 llen, vlen, v = 1, 0, lv[1:]
4871 sub_offset = offset + tlen + llen
4873 while v[:EOC_LEN].tobytes() != EOC:
4874 chunk, v = Any().decode(
4877 decode_path=decode_path + (str(chunk_i),),
4880 _ctx_immutable=False,
4882 vlen += chunk.tlvlen
4883 sub_offset += chunk.tlvlen
4885 tlvlen = tlen + llen + vlen + EOC_LEN
4886 obj = self.__class__(
4887 value=tlv[:tlvlen].tobytes(),
4889 optional=self.optional,
4890 _decoded=(offset, 0, tlvlen),
4893 obj.tag = t.tobytes()
4894 return obj, v[EOC_LEN:]
4895 except DecodeError as err:
4896 raise err.__class__(
4898 klass=self.__class__,
4899 decode_path=decode_path,
4903 raise NotEnoughData(
4904 "encoded length is longer than data",
4905 klass=self.__class__,
4906 decode_path=decode_path,
4909 tlvlen = tlen + llen + l
4910 v, tail = tlv[:tlvlen], v[l:]
4911 obj = self.__class__(
4914 optional=self.optional,
4915 _decoded=(offset, 0, tlvlen),
4917 obj.tag = t.tobytes()
4921 return pp_console_row(next(self.pps()))
4923 def pps(self, decode_path=()):
4926 asn1_type_name=self.asn1_type_name,
4927 obj_name=self.__class__.__name__,
4928 decode_path=decode_path,
4929 blob=self._value if self.ready else None,
4930 optional=self.optional,
4931 default=self == self.default,
4932 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4933 expl=None if self._expl is None else tag_decode(self._expl),
4938 expl_offset=self.expl_offset if self.expled else None,
4939 expl_tlen=self.expl_tlen if self.expled else None,
4940 expl_llen=self.expl_llen if self.expled else None,
4941 expl_vlen=self.expl_vlen if self.expled else None,
4942 expl_lenindef=self.expl_lenindef,
4943 lenindef=self.lenindef,
4946 defined_by, defined = self.defined or (None, None)
4947 if defined_by is not None:
4949 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4951 for pp in self.pps_lenindef(decode_path):
4955 ########################################################################
4956 # ASN.1 constructed types
4957 ########################################################################
4959 def get_def_by_path(defines_by_path, sub_decode_path):
4960 """Get define by decode path
4962 for path, define in defines_by_path:
4963 if len(path) != len(sub_decode_path):
4965 for p1, p2 in zip(path, sub_decode_path):
4966 if (p1 != any) and (p1 != p2):
4972 def abs_decode_path(decode_path, rel_path):
4973 """Create an absolute decode path from current and relative ones
4975 :param decode_path: current decode path, starting point. Tuple of strings
4976 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4977 If first tuple's element is "/", then treat it as
4978 an absolute path, ignoring ``decode_path`` as
4979 starting point. Also this tuple can contain ".."
4980 elements, stripping the leading element from
4983 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4984 ("foo", "bar", "baz", "whatever")
4985 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4987 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4990 if rel_path[0] == "/":
4992 if rel_path[0] == "..":
4993 return abs_decode_path(decode_path[:-1], rel_path[1:])
4994 return decode_path + rel_path
4997 SequenceState = namedtuple("SequenceState", (
5014 class Sequence(Obj):
5015 """``SEQUENCE`` structure type
5017 You have to make specification of sequence::
5019 class Extension(Sequence):
5021 ("extnID", ObjectIdentifier()),
5022 ("critical", Boolean(default=False)),
5023 ("extnValue", OctetString()),
5026 Then, you can work with it as with dictionary.
5028 >>> ext = Extension()
5029 >>> Extension().specs
5031 ('extnID', OBJECT IDENTIFIER),
5032 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5033 ('extnValue', OCTET STRING),
5035 >>> ext["extnID"] = "1.2.3"
5036 Traceback (most recent call last):
5037 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5038 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5040 You can determine if sequence is ready to be encoded:
5045 Traceback (most recent call last):
5046 pyderasn.ObjNotReady: object is not ready: extnValue
5047 >>> ext["extnValue"] = OctetString(b"foobar")
5051 Value you want to assign, must have the same **type** as in
5052 corresponding specification, but it can have different tags,
5053 optional/default attributes -- they will be taken from specification
5056 class TBSCertificate(Sequence):
5058 ("version", Version(expl=tag_ctxc(0), default="v1")),
5061 >>> tbs = TBSCertificate()
5062 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5064 Assign ``None`` to remove value from sequence.
5066 You can set values in Sequence during its initialization:
5068 >>> AlgorithmIdentifier((
5069 ("algorithm", ObjectIdentifier("1.2.3")),
5070 ("parameters", Any(Null()))
5072 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5074 You can determine if value exists/set in the sequence and take its value:
5076 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5079 OBJECT IDENTIFIER 1.2.3
5081 But pay attention that if value has default, then it won't be (not
5082 in) in the sequence (because ``DEFAULT`` must not be encoded in
5083 DER), but you can read its value:
5085 >>> "critical" in ext, ext["critical"]
5086 (False, BOOLEAN False)
5087 >>> ext["critical"] = Boolean(True)
5088 >>> "critical" in ext, ext["critical"]
5089 (True, BOOLEAN True)
5091 All defaulted values are always optional.
5093 .. _allow_default_values_ctx:
5095 DER prohibits default value encoding and will raise an error if
5096 default value is unexpectedly met during decode.
5097 If :ref:`bered <bered_ctx>` context option is set, then no error
5098 will be raised, but ``bered`` attribute set. You can disable strict
5099 defaulted values existence validation by setting
5100 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5102 Two sequences are equal if they have equal specification (schema),
5103 implicit/explicit tagging and the same values.
5105 __slots__ = ("specs",)
5106 tag_default = tag_encode(form=TagFormConstructed, num=16)
5107 asn1_type_name = "SEQUENCE"
5119 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5121 schema = getattr(self, "schema", ())
5123 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5126 if value is not None:
5127 if issubclass(value.__class__, Sequence):
5128 self._value = value._value
5129 elif hasattr(value, "__iter__"):
5130 for seq_key, seq_value in value:
5131 self[seq_key] = seq_value
5133 raise InvalidValueType((Sequence,))
5134 if default is not None:
5135 if not issubclass(default.__class__, Sequence):
5136 raise InvalidValueType((Sequence,))
5137 default_value = default._value
5138 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5139 default_obj.specs = self.specs
5140 default_obj._value = default_value
5141 self.default = default_obj
5143 self._value = copy(default_obj._value)
5147 for name, spec in iteritems(self.specs):
5148 value = self._value.get(name)
5159 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5161 return any(value.bered for value in itervalues(self._value))
5163 def __getstate__(self):
5164 return SequenceState(
5167 {k: copy(v) for k, v in iteritems(self._value)},
5180 def __setstate__(self, state):
5181 super(Sequence, self).__setstate__(state)
5182 self.specs = state.specs
5183 self._value = state.value
5184 self.tag = state.tag
5185 self._expl = state.expl
5186 self.default = state.default
5187 self.optional = state.optional
5188 self.offset = state.offset
5189 self.llen = state.llen
5190 self.vlen = state.vlen
5191 self.expl_lenindef = state.expl_lenindef
5192 self.lenindef = state.lenindef
5193 self.ber_encoded = state.ber_encoded
5195 def __eq__(self, their):
5196 if not isinstance(their, self.__class__):
5199 self.specs == their.specs and
5200 self.tag == their.tag and
5201 self._expl == their._expl and
5202 self._value == their._value
5213 return self.__class__(
5216 impl=self.tag if impl is None else impl,
5217 expl=self._expl if expl is None else expl,
5218 default=self.default if default is None else default,
5219 optional=self.optional if optional is None else optional,
5222 def __contains__(self, key):
5223 return key in self._value
5225 def __setitem__(self, key, value):
5226 spec = self.specs.get(key)
5228 raise ObjUnknown(key)
5230 self._value.pop(key, None)
5232 if not isinstance(value, spec.__class__):
5233 raise InvalidValueType((spec.__class__,))
5234 value = spec(value=value)
5235 if spec.default is not None and value == spec.default:
5236 self._value.pop(key, None)
5238 self._value[key] = value
5240 def __getitem__(self, key):
5241 value = self._value.get(key)
5242 if value is not None:
5244 spec = self.specs.get(key)
5246 raise ObjUnknown(key)
5247 if spec.default is not None:
5251 def _encoded_values(self):
5253 for name, spec in iteritems(self.specs):
5254 value = self._value.get(name)
5258 raise ObjNotReady(name)
5259 raws.append(value.encode())
5263 v = b"".join(self._encoded_values())
5264 return b"".join((self.tag, len_encode(len(v)), v))
5266 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5268 t, tlen, lv = tag_strip(tlv)
5269 except DecodeError as err:
5270 raise err.__class__(
5272 klass=self.__class__,
5273 decode_path=decode_path,
5278 klass=self.__class__,
5279 decode_path=decode_path,
5282 if tag_only: # pragma: no cover
5285 ctx_bered = ctx.get("bered", False)
5287 l, llen, v = len_decode(lv)
5288 except LenIndefForm as err:
5290 raise err.__class__(
5292 klass=self.__class__,
5293 decode_path=decode_path,
5296 l, llen, v = 0, 1, lv[1:]
5298 except DecodeError as err:
5299 raise err.__class__(
5301 klass=self.__class__,
5302 decode_path=decode_path,
5306 raise NotEnoughData(
5307 "encoded length is longer than data",
5308 klass=self.__class__,
5309 decode_path=decode_path,
5313 v, tail = v[:l], v[l:]
5315 sub_offset = offset + tlen + llen
5318 ctx_allow_default_values = ctx.get("allow_default_values", False)
5319 for name, spec in iteritems(self.specs):
5320 if spec.optional and (
5321 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5325 sub_decode_path = decode_path + (name,)
5327 value, v_tail = spec.decode(
5331 decode_path=sub_decode_path,
5333 _ctx_immutable=False,
5335 except TagMismatch as err:
5336 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5340 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5341 if defined is not None:
5342 defined_by, defined_spec = defined
5343 if issubclass(value.__class__, SequenceOf):
5344 for i, _value in enumerate(value):
5345 sub_sub_decode_path = sub_decode_path + (
5347 DecodePathDefBy(defined_by),
5349 defined_value, defined_tail = defined_spec.decode(
5350 memoryview(bytes(_value)),
5352 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5353 if value.expled else (value.tlen + value.llen)
5356 decode_path=sub_sub_decode_path,
5358 _ctx_immutable=False,
5360 if len(defined_tail) > 0:
5363 klass=self.__class__,
5364 decode_path=sub_sub_decode_path,
5367 _value.defined = (defined_by, defined_value)
5369 defined_value, defined_tail = defined_spec.decode(
5370 memoryview(bytes(value)),
5372 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5373 if value.expled else (value.tlen + value.llen)
5376 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5378 _ctx_immutable=False,
5380 if len(defined_tail) > 0:
5383 klass=self.__class__,
5384 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5387 value.defined = (defined_by, defined_value)
5389 value_len = value.fulllen
5391 sub_offset += value_len
5393 if spec.default is not None and value == spec.default:
5394 if ctx_bered or ctx_allow_default_values:
5398 "DEFAULT value met",
5399 klass=self.__class__,
5400 decode_path=sub_decode_path,
5403 values[name] = value
5405 spec_defines = getattr(spec, "defines", ())
5406 if len(spec_defines) == 0:
5407 defines_by_path = ctx.get("defines_by_path", ())
5408 if len(defines_by_path) > 0:
5409 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5410 if spec_defines is not None and len(spec_defines) > 0:
5411 for rel_path, schema in spec_defines:
5412 defined = schema.get(value, None)
5413 if defined is not None:
5414 ctx.setdefault("_defines", []).append((
5415 abs_decode_path(sub_decode_path[:-1], rel_path),
5419 if v[:EOC_LEN].tobytes() != EOC:
5422 klass=self.__class__,
5423 decode_path=decode_path,
5431 klass=self.__class__,
5432 decode_path=decode_path,
5435 obj = self.__class__(
5439 default=self.default,
5440 optional=self.optional,
5441 _decoded=(offset, llen, vlen),
5444 obj.lenindef = lenindef
5445 obj.ber_encoded = ber_encoded
5449 value = pp_console_row(next(self.pps()))
5451 for name in self.specs:
5452 _value = self._value.get(name)
5455 cols.append("%s: %s" % (name, repr(_value)))
5456 return "%s[%s]" % (value, "; ".join(cols))
5458 def pps(self, decode_path=()):
5461 asn1_type_name=self.asn1_type_name,
5462 obj_name=self.__class__.__name__,
5463 decode_path=decode_path,
5464 optional=self.optional,
5465 default=self == self.default,
5466 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5467 expl=None if self._expl is None else tag_decode(self._expl),
5472 expl_offset=self.expl_offset if self.expled else None,
5473 expl_tlen=self.expl_tlen if self.expled else None,
5474 expl_llen=self.expl_llen if self.expled else None,
5475 expl_vlen=self.expl_vlen if self.expled else None,
5476 expl_lenindef=self.expl_lenindef,
5477 lenindef=self.lenindef,
5478 ber_encoded=self.ber_encoded,
5481 for name in self.specs:
5482 value = self._value.get(name)
5485 yield value.pps(decode_path=decode_path + (name,))
5486 for pp in self.pps_lenindef(decode_path):
5490 class Set(Sequence):
5491 """``SET`` structure type
5493 Its usage is identical to :py:class:`pyderasn.Sequence`.
5495 .. _allow_unordered_set_ctx:
5497 DER prohibits unordered values encoding and will raise an error
5498 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5499 then no error will occure. Also you can disable strict values
5500 ordering check by setting ``"allow_unordered_set": True``
5501 :ref:`context <ctx>` option.
5504 tag_default = tag_encode(form=TagFormConstructed, num=17)
5505 asn1_type_name = "SET"
5508 raws = self._encoded_values()
5511 return b"".join((self.tag, len_encode(len(v)), v))
5513 def _specs_items(self):
5514 return iteritems(self.specs)
5516 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5518 t, tlen, lv = tag_strip(tlv)
5519 except DecodeError as err:
5520 raise err.__class__(
5522 klass=self.__class__,
5523 decode_path=decode_path,
5528 klass=self.__class__,
5529 decode_path=decode_path,
5535 ctx_bered = ctx.get("bered", False)
5537 l, llen, v = len_decode(lv)
5538 except LenIndefForm as err:
5540 raise err.__class__(
5542 klass=self.__class__,
5543 decode_path=decode_path,
5546 l, llen, v = 0, 1, lv[1:]
5548 except DecodeError as err:
5549 raise err.__class__(
5551 klass=self.__class__,
5552 decode_path=decode_path,
5556 raise NotEnoughData(
5557 "encoded length is longer than data",
5558 klass=self.__class__,
5562 v, tail = v[:l], v[l:]
5564 sub_offset = offset + tlen + llen
5567 ctx_allow_default_values = ctx.get("allow_default_values", False)
5568 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5569 value_prev = memoryview(v[:0])
5572 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5574 for name, spec in self._specs_items():
5575 sub_decode_path = decode_path + (name,)
5581 decode_path=sub_decode_path,
5584 _ctx_immutable=False,
5591 klass=self.__class__,
5592 decode_path=decode_path,
5595 value, v_tail = spec.decode(
5599 decode_path=sub_decode_path,
5601 _ctx_immutable=False,
5603 value_len = value.fulllen
5604 if value_prev.tobytes() > v[:value_len].tobytes():
5605 if ctx_bered or ctx_allow_unordered_set:
5609 "unordered " + self.asn1_type_name,
5610 klass=self.__class__,
5611 decode_path=sub_decode_path,
5614 if spec.default is None or value != spec.default:
5616 elif ctx_bered or ctx_allow_default_values:
5620 "DEFAULT value met",
5621 klass=self.__class__,
5622 decode_path=sub_decode_path,
5625 values[name] = value
5626 value_prev = v[:value_len]
5627 sub_offset += value_len
5630 obj = self.__class__(
5634 default=self.default,
5635 optional=self.optional,
5636 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5639 if v[:EOC_LEN].tobytes() != EOC:
5642 klass=self.__class__,
5643 decode_path=decode_path,
5651 "not all values are ready",
5652 klass=self.__class__,
5653 decode_path=decode_path,
5656 obj.ber_encoded = ber_encoded
5660 SequenceOfState = namedtuple("SequenceOfState", (
5679 class SequenceOf(Obj):
5680 """``SEQUENCE OF`` sequence type
5682 For that kind of type you must specify the object it will carry on
5683 (bounds are for example here, not required)::
5685 class Ints(SequenceOf):
5690 >>> ints.append(Integer(123))
5691 >>> ints.append(Integer(234))
5693 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5694 >>> [int(i) for i in ints]
5696 >>> ints.append(Integer(345))
5697 Traceback (most recent call last):
5698 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5701 >>> ints[1] = Integer(345)
5703 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5705 Also you can initialize sequence with preinitialized values:
5707 >>> ints = Ints([Integer(123), Integer(234)])
5709 __slots__ = ("spec", "_bound_min", "_bound_max")
5710 tag_default = tag_encode(form=TagFormConstructed, num=16)
5711 asn1_type_name = "SEQUENCE OF"
5724 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5726 schema = getattr(self, "schema", None)
5728 raise ValueError("schema must be specified")
5730 self._bound_min, self._bound_max = getattr(
5734 ) if bounds is None else bounds
5736 if value is not None:
5737 self._value = self._value_sanitize(value)
5738 if default is not None:
5739 default_value = self._value_sanitize(default)
5740 default_obj = self.__class__(
5745 default_obj._value = default_value
5746 self.default = default_obj
5748 self._value = copy(default_obj._value)
5750 def _value_sanitize(self, value):
5751 if issubclass(value.__class__, SequenceOf):
5752 value = value._value
5753 elif hasattr(value, "__iter__"):
5756 raise InvalidValueType((self.__class__, iter))
5757 if not self._bound_min <= len(value) <= self._bound_max:
5758 raise BoundsError(self._bound_min, len(value), self._bound_max)
5760 if not isinstance(v, self.spec.__class__):
5761 raise InvalidValueType((self.spec.__class__,))
5766 return all(v.ready for v in self._value)
5770 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5772 return any(v.bered for v in self._value)
5774 def __getstate__(self):
5775 return SequenceOfState(
5778 [copy(v) for v in self._value],
5793 def __setstate__(self, state):
5794 super(SequenceOf, self).__setstate__(state)
5795 self.spec = state.spec
5796 self._value = state.value
5797 self._bound_min = state.bound_min
5798 self._bound_max = state.bound_max
5799 self.tag = state.tag
5800 self._expl = state.expl
5801 self.default = state.default
5802 self.optional = state.optional
5803 self.offset = state.offset
5804 self.llen = state.llen
5805 self.vlen = state.vlen
5806 self.expl_lenindef = state.expl_lenindef
5807 self.lenindef = state.lenindef
5808 self.ber_encoded = state.ber_encoded
5810 def __eq__(self, their):
5811 if isinstance(their, self.__class__):
5813 self.spec == their.spec and
5814 self.tag == their.tag and
5815 self._expl == their._expl and
5816 self._value == their._value
5818 if hasattr(their, "__iter__"):
5819 return self._value == list(their)
5831 return self.__class__(
5835 (self._bound_min, self._bound_max)
5836 if bounds is None else bounds
5838 impl=self.tag if impl is None else impl,
5839 expl=self._expl if expl is None else expl,
5840 default=self.default if default is None else default,
5841 optional=self.optional if optional is None else optional,
5844 def __contains__(self, key):
5845 return key in self._value
5847 def append(self, value):
5848 if not isinstance(value, self.spec.__class__):
5849 raise InvalidValueType((self.spec.__class__,))
5850 if len(self._value) + 1 > self._bound_max:
5853 len(self._value) + 1,
5856 self._value.append(value)
5859 self._assert_ready()
5860 return iter(self._value)
5863 self._assert_ready()
5864 return len(self._value)
5866 def __setitem__(self, key, value):
5867 if not isinstance(value, self.spec.__class__):
5868 raise InvalidValueType((self.spec.__class__,))
5869 self._value[key] = self.spec(value=value)
5871 def __getitem__(self, key):
5872 return self._value[key]
5874 def _encoded_values(self):
5875 return [v.encode() for v in self._value]
5878 v = b"".join(self._encoded_values())
5879 return b"".join((self.tag, len_encode(len(v)), v))
5881 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5883 t, tlen, lv = tag_strip(tlv)
5884 except DecodeError as err:
5885 raise err.__class__(
5887 klass=self.__class__,
5888 decode_path=decode_path,
5893 klass=self.__class__,
5894 decode_path=decode_path,
5900 ctx_bered = ctx.get("bered", False)
5902 l, llen, v = len_decode(lv)
5903 except LenIndefForm as err:
5905 raise err.__class__(
5907 klass=self.__class__,
5908 decode_path=decode_path,
5911 l, llen, v = 0, 1, lv[1:]
5913 except DecodeError as err:
5914 raise err.__class__(
5916 klass=self.__class__,
5917 decode_path=decode_path,
5921 raise NotEnoughData(
5922 "encoded length is longer than data",
5923 klass=self.__class__,
5924 decode_path=decode_path,
5928 v, tail = v[:l], v[l:]
5930 sub_offset = offset + tlen + llen
5932 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5933 value_prev = memoryview(v[:0])
5937 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5939 sub_decode_path = decode_path + (str(len(_value)),)
5940 value, v_tail = spec.decode(
5944 decode_path=sub_decode_path,
5946 _ctx_immutable=False,
5948 value_len = value.fulllen
5950 if value_prev.tobytes() > v[:value_len].tobytes():
5951 if ctx_bered or ctx_allow_unordered_set:
5955 "unordered " + self.asn1_type_name,
5956 klass=self.__class__,
5957 decode_path=sub_decode_path,
5960 value_prev = v[:value_len]
5961 _value.append(value)
5962 sub_offset += value_len
5966 obj = self.__class__(
5969 bounds=(self._bound_min, self._bound_max),
5972 default=self.default,
5973 optional=self.optional,
5974 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5976 except BoundsError as err:
5979 klass=self.__class__,
5980 decode_path=decode_path,
5984 if v[:EOC_LEN].tobytes() != EOC:
5987 klass=self.__class__,
5988 decode_path=decode_path,
5993 obj.ber_encoded = ber_encoded
5998 pp_console_row(next(self.pps())),
5999 ", ".join(repr(v) for v in self._value),
6002 def pps(self, decode_path=()):
6005 asn1_type_name=self.asn1_type_name,
6006 obj_name=self.__class__.__name__,
6007 decode_path=decode_path,
6008 optional=self.optional,
6009 default=self == self.default,
6010 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6011 expl=None if self._expl is None else tag_decode(self._expl),
6016 expl_offset=self.expl_offset if self.expled else None,
6017 expl_tlen=self.expl_tlen if self.expled else None,
6018 expl_llen=self.expl_llen if self.expled else None,
6019 expl_vlen=self.expl_vlen if self.expled else None,
6020 expl_lenindef=self.expl_lenindef,
6021 lenindef=self.lenindef,
6022 ber_encoded=self.ber_encoded,
6025 for i, value in enumerate(self._value):
6026 yield value.pps(decode_path=decode_path + (str(i),))
6027 for pp in self.pps_lenindef(decode_path):
6031 class SetOf(SequenceOf):
6032 """``SET OF`` sequence type
6034 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6037 tag_default = tag_encode(form=TagFormConstructed, num=17)
6038 asn1_type_name = "SET OF"
6041 raws = self._encoded_values()
6044 return b"".join((self.tag, len_encode(len(v)), v))
6046 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6047 return super(SetOf, self)._decode(
6053 ordering_check=True,
6057 def obj_by_path(pypath): # pragma: no cover
6058 """Import object specified as string Python path
6060 Modules must be separated from classes/functions with ``:``.
6062 >>> obj_by_path("foo.bar:Baz")
6063 <class 'foo.bar.Baz'>
6064 >>> obj_by_path("foo.bar:Baz.boo")
6065 <classmethod 'foo.bar.Baz.boo'>
6067 mod, objs = pypath.rsplit(":", 1)
6068 from importlib import import_module
6069 obj = import_module(mod)
6070 for obj_name in objs.split("."):
6071 obj = getattr(obj, obj_name)
6075 def generic_decoder(): # pragma: no cover
6076 # All of this below is a big hack with self references
6077 choice = PrimitiveTypes()
6078 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6079 choice.specs["SetOf"] = SetOf(schema=choice)
6080 for i in six_xrange(31):
6081 choice.specs["SequenceOf%d" % i] = SequenceOf(
6085 choice.specs["Any"] = Any()
6087 # Class name equals to type name, to omit it from output
6088 class SEQUENCEOF(SequenceOf):
6096 with_decode_path=False,
6097 decode_path_only=(),
6099 def _pprint_pps(pps):
6101 if hasattr(pp, "_fields"):
6103 decode_path_only != () and
6104 pp.decode_path[:len(decode_path_only)] != decode_path_only
6107 if pp.asn1_type_name == Choice.asn1_type_name:
6109 pp_kwargs = pp._asdict()
6110 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6111 pp = _pp(**pp_kwargs)
6112 yield pp_console_row(
6117 with_colours=with_colours,
6118 with_decode_path=with_decode_path,
6119 decode_path_len_decrease=len(decode_path_only),
6121 for row in pp_console_blob(
6123 decode_path_len_decrease=len(decode_path_only),
6127 for row in _pprint_pps(pp):
6129 return "\n".join(_pprint_pps(obj.pps()))
6130 return SEQUENCEOF(), pprint_any
6133 def main(): # pragma: no cover
6135 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6136 parser.add_argument(
6140 help="Skip that number of bytes from the beginning",
6142 parser.add_argument(
6144 help="Python paths to dictionary with OIDs, comma separated",
6146 parser.add_argument(
6148 help="Python path to schema definition to use",
6150 parser.add_argument(
6151 "--defines-by-path",
6152 help="Python path to decoder's defines_by_path",
6154 parser.add_argument(
6156 action="store_true",
6157 help="Disallow BER encoding",
6159 parser.add_argument(
6160 "--print-decode-path",
6161 action="store_true",
6162 help="Print decode paths",
6164 parser.add_argument(
6165 "--decode-path-only",
6166 help="Print only specified decode path",
6168 parser.add_argument(
6170 action="store_true",
6171 help="Allow explicit tag out-of-bound",
6173 parser.add_argument(
6175 type=argparse.FileType("rb"),
6176 help="Path to DER file you want to decode",
6178 args = parser.parse_args()
6179 args.DERFile.seek(args.skip)
6180 der = memoryview(args.DERFile.read())
6181 args.DERFile.close()
6183 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6184 if args.oids else ()
6187 schema = obj_by_path(args.schema)
6188 from functools import partial
6189 pprinter = partial(pprint, big_blobs=True)
6191 schema, pprinter = generic_decoder()
6193 "bered": not args.nobered,
6194 "allow_expl_oob": args.allow_expl_oob,
6196 if args.defines_by_path is not None:
6197 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6198 obj, tail = schema().decode(der, ctx=ctx)
6202 with_colours=environ.get("NO_COLOR") is None,
6203 with_decode_path=args.print_decode_path,
6205 () if args.decode_path_only is None else
6206 tuple(args.decode_path_only.split(":"))
6210 print("\nTrailing data: %s" % hexenc(tail))
6213 if __name__ == "__main__":