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'])
3996 tag_default = tag_encode(19)
3998 asn1_type_name = "PrintableString"
3999 _allowable_chars = frozenset(
4000 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4002 _asterisk = frozenset("*".encode("ascii"))
4003 _ampersand = frozenset("&".encode("ascii"))
4014 allow_asterisk=False,
4015 allow_ampersand=False,
4018 :param allow_asterisk: allow asterisk character
4019 :param allow_ampersand: allow ampersand character
4022 self._allowable_chars |= self._asterisk
4024 self._allowable_chars |= self._ampersand
4025 super(PrintableString, self).__init__(
4026 value, bounds, impl, expl, default, optional, _decoded,
4029 def _value_sanitize(self, value):
4030 value = super(PrintableString, self)._value_sanitize(value)
4031 if not frozenset(value) <= self._allowable_chars:
4032 raise DecodeError("non-printable value")
4035 def __getstate__(self):
4036 return PrintableStringState(
4037 *super(PrintableString, self).__getstate__(),
4038 **{"allowable_chars": self._allowable_chars}
4041 def __setstate__(self, state):
4042 super(PrintableString, self).__setstate__(state)
4043 self._allowable_chars = state.allowable_chars
4054 return self.__class__(
4057 (self._bound_min, self._bound_max)
4058 if bounds is None else bounds
4060 impl=self.tag if impl is None else impl,
4061 expl=self._expl if expl is None else expl,
4062 default=self.default if default is None else default,
4063 optional=self.optional if optional is None else optional,
4064 allow_asterisk=self._asterisk <= self._allowable_chars,
4065 allow_ampersand=self._ampersand <= self._allowable_chars,
4069 class TeletexString(CommonString):
4071 tag_default = tag_encode(20)
4073 asn1_type_name = "TeletexString"
4076 class T61String(TeletexString):
4078 asn1_type_name = "T61String"
4081 class VideotexString(CommonString):
4083 tag_default = tag_encode(21)
4084 encoding = "iso-8859-1"
4085 asn1_type_name = "VideotexString"
4088 class IA5String(CommonString):
4090 tag_default = tag_encode(22)
4092 asn1_type_name = "IA5"
4095 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4096 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4097 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4100 class UTCTime(CommonString):
4101 """``UTCTime`` datetime type
4103 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4104 UTCTime UTCTime 2017-09-30T22:07:50
4110 datetime.datetime(2017, 9, 30, 22, 7, 50)
4111 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4112 datetime.datetime(1957, 9, 30, 22, 7, 50)
4116 BER encoding is unsupported.
4119 tag_default = tag_encode(23)
4121 asn1_type_name = "UTCTime"
4131 bounds=None, # dummy argument, workability for OctetString.decode
4134 :param value: set the value. Either datetime type, or
4135 :py:class:`pyderasn.UTCTime` object
4136 :param bytes impl: override default tag with ``IMPLICIT`` one
4137 :param bytes expl: override default tag with ``EXPLICIT`` one
4138 :param default: set default value. Type same as in ``value``
4139 :param bool optional: is object ``OPTIONAL`` in sequence
4141 super(UTCTime, self).__init__(
4142 None, None, impl, expl, default, optional, _decoded,
4145 if value is not None:
4146 self._value = self._value_sanitize(value)
4147 if default is not None:
4148 default = self._value_sanitize(default)
4149 self.default = self.__class__(
4154 if self._value is None:
4155 self._value = default
4157 def _strptime(self, value):
4158 # datetime.strptime's format: %y%m%d%H%M%SZ
4159 if len(value) != LEN_YYMMDDHHMMSSZ:
4160 raise ValueError("invalid UTCTime length")
4161 if value[-1] != "Z":
4162 raise ValueError("non UTC timezone")
4164 2000 + int(value[:2]), # %y
4165 int(value[2:4]), # %m
4166 int(value[4:6]), # %d
4167 int(value[6:8]), # %H
4168 int(value[8:10]), # %M
4169 int(value[10:12]), # %S
4172 def _value_sanitize(self, value):
4173 if isinstance(value, binary_type):
4175 value_decoded = value.decode("ascii")
4176 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4177 raise DecodeError("invalid UTCTime encoding: %r" % err)
4179 self._strptime(value_decoded)
4180 except (TypeError, ValueError) as err:
4181 raise DecodeError("invalid UTCTime format: %r" % err)
4183 if isinstance(value, self.__class__):
4185 if isinstance(value, datetime):
4186 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4187 raise InvalidValueType((self.__class__, datetime))
4189 def __eq__(self, their):
4190 if isinstance(their, binary_type):
4191 return self._value == their
4192 if isinstance(their, datetime):
4193 return self.todatetime() == their
4194 if not isinstance(their, self.__class__):
4197 self._value == their._value and
4198 self.tag == their.tag and
4199 self._expl == their._expl
4202 def todatetime(self):
4203 """Convert to datetime
4207 Pay attention that UTCTime can not hold full year, so all years
4208 having < 50 years are treated as 20xx, 19xx otherwise, according
4209 to X.509 recomendation.
4211 value = self._strptime(self._value.decode("ascii"))
4212 year = value.year % 100
4214 year=(2000 + year) if year < 50 else (1900 + year),
4218 minute=value.minute,
4219 second=value.second,
4223 return pp_console_row(next(self.pps()))
4225 def pps(self, decode_path=()):
4228 asn1_type_name=self.asn1_type_name,
4229 obj_name=self.__class__.__name__,
4230 decode_path=decode_path,
4231 value=self.todatetime().isoformat() if self.ready else None,
4232 optional=self.optional,
4233 default=self == self.default,
4234 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4235 expl=None if self._expl is None else tag_decode(self._expl),
4240 expl_offset=self.expl_offset if self.expled else None,
4241 expl_tlen=self.expl_tlen if self.expled else None,
4242 expl_llen=self.expl_llen if self.expled else None,
4243 expl_vlen=self.expl_vlen if self.expled else None,
4244 expl_lenindef=self.expl_lenindef,
4245 ber_encoded=self.ber_encoded,
4248 for pp in self.pps_lenindef(decode_path):
4252 class GeneralizedTime(UTCTime):
4253 """``GeneralizedTime`` datetime type
4255 This type is similar to :py:class:`pyderasn.UTCTime`.
4257 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4258 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4260 '20170930220750.000123Z'
4261 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4262 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4266 BER encoding is unsupported.
4270 Only microsecond fractions are supported.
4271 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4272 higher precision values.
4275 tag_default = tag_encode(24)
4276 asn1_type_name = "GeneralizedTime"
4278 def _strptime(self, value):
4280 if l == LEN_YYYYMMDDHHMMSSZ:
4281 # datetime.strptime's format: %y%m%d%H%M%SZ
4282 if value[-1] != "Z":
4283 raise ValueError("non UTC timezone")
4285 int(value[:4]), # %Y
4286 int(value[4:6]), # %m
4287 int(value[6:8]), # %d
4288 int(value[8:10]), # %H
4289 int(value[10:12]), # %M
4290 int(value[12:14]), # %S
4292 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4293 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4294 if value[-1] != "Z":
4295 raise ValueError("non UTC timezone")
4296 if value[14] != ".":
4297 raise ValueError("no fractions separator")
4300 raise ValueError("trailing zero")
4303 raise ValueError("only microsecond fractions are supported")
4304 us = int(us + ("0" * (6 - us_len)))
4306 int(value[:4]), # %Y
4307 int(value[4:6]), # %m
4308 int(value[6:8]), # %d
4309 int(value[8:10]), # %H
4310 int(value[10:12]), # %M
4311 int(value[12:14]), # %S
4315 raise ValueError("invalid GeneralizedTime length")
4317 def _value_sanitize(self, value):
4318 if isinstance(value, binary_type):
4320 value_decoded = value.decode("ascii")
4321 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4322 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4324 self._strptime(value_decoded)
4325 except (TypeError, ValueError) as err:
4327 "invalid GeneralizedTime format: %r" % err,
4328 klass=self.__class__,
4331 if isinstance(value, self.__class__):
4333 if isinstance(value, datetime):
4334 encoded = value.strftime("%Y%m%d%H%M%S")
4335 if value.microsecond > 0:
4336 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4337 return (encoded + "Z").encode("ascii")
4338 raise InvalidValueType((self.__class__, datetime))
4340 def todatetime(self):
4341 return self._strptime(self._value.decode("ascii"))
4344 class GraphicString(CommonString):
4346 tag_default = tag_encode(25)
4347 encoding = "iso-8859-1"
4348 asn1_type_name = "GraphicString"
4351 class VisibleString(CommonString):
4353 tag_default = tag_encode(26)
4355 asn1_type_name = "VisibleString"
4358 class ISO646String(VisibleString):
4360 asn1_type_name = "ISO646String"
4363 class GeneralString(CommonString):
4365 tag_default = tag_encode(27)
4366 encoding = "iso-8859-1"
4367 asn1_type_name = "GeneralString"
4370 class UniversalString(CommonString):
4372 tag_default = tag_encode(28)
4373 encoding = "utf-32-be"
4374 asn1_type_name = "UniversalString"
4377 class BMPString(CommonString):
4379 tag_default = tag_encode(30)
4380 encoding = "utf-16-be"
4381 asn1_type_name = "BMPString"
4384 ChoiceState = namedtuple("ChoiceState", (
4402 """``CHOICE`` special type
4406 class GeneralName(Choice):
4408 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4409 ("dNSName", IA5String(impl=tag_ctxp(2))),
4412 >>> gn = GeneralName()
4414 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4415 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4416 >>> gn["dNSName"] = IA5String("bar.baz")
4417 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4418 >>> gn["rfc822Name"]
4421 [2] IA5String IA5 bar.baz
4424 >>> gn.value == gn["dNSName"]
4427 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4429 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4430 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4432 __slots__ = ("specs",)
4434 asn1_type_name = "CHOICE"
4447 :param value: set the value. Either ``(choice, value)`` tuple, or
4448 :py:class:`pyderasn.Choice` object
4449 :param bytes impl: can not be set, do **not** use it
4450 :param bytes expl: override default tag with ``EXPLICIT`` one
4451 :param default: set default value. Type same as in ``value``
4452 :param bool optional: is object ``OPTIONAL`` in sequence
4454 if impl is not None:
4455 raise ValueError("no implicit tag allowed for CHOICE")
4456 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4458 schema = getattr(self, "schema", ())
4459 if len(schema) == 0:
4460 raise ValueError("schema must be specified")
4462 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4465 if value is not None:
4466 self._value = self._value_sanitize(value)
4467 if default is not None:
4468 default_value = self._value_sanitize(default)
4469 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4470 default_obj.specs = self.specs
4471 default_obj._value = default_value
4472 self.default = default_obj
4474 self._value = copy(default_obj._value)
4476 def _value_sanitize(self, value):
4477 if isinstance(value, tuple) and len(value) == 2:
4479 spec = self.specs.get(choice)
4481 raise ObjUnknown(choice)
4482 if not isinstance(obj, spec.__class__):
4483 raise InvalidValueType((spec,))
4484 return (choice, spec(obj))
4485 if isinstance(value, self.__class__):
4487 raise InvalidValueType((self.__class__, tuple))
4491 return self._value is not None and self._value[1].ready
4495 return self.expl_lenindef or (
4496 (self._value is not None) and
4497 self._value[1].bered
4500 def __getstate__(self):
4517 def __setstate__(self, state):
4518 super(Choice, self).__setstate__(state)
4519 self.specs = state.specs
4520 self._value = state.value
4521 self._expl = state.expl
4522 self.default = state.default
4523 self.optional = state.optional
4524 self.offset = state.offset
4525 self.llen = state.llen
4526 self.vlen = state.vlen
4527 self.expl_lenindef = state.expl_lenindef
4528 self.lenindef = state.lenindef
4529 self.ber_encoded = state.ber_encoded
4531 def __eq__(self, their):
4532 if isinstance(their, tuple) and len(their) == 2:
4533 return self._value == their
4534 if not isinstance(their, self.__class__):
4537 self.specs == their.specs and
4538 self._value == their._value
4548 return self.__class__(
4551 expl=self._expl if expl is None else expl,
4552 default=self.default if default is None else default,
4553 optional=self.optional if optional is None else optional,
4558 self._assert_ready()
4559 return self._value[0]
4563 self._assert_ready()
4564 return self._value[1]
4566 def __getitem__(self, key):
4567 if key not in self.specs:
4568 raise ObjUnknown(key)
4569 if self._value is None:
4571 choice, value = self._value
4576 def __setitem__(self, key, value):
4577 spec = self.specs.get(key)
4579 raise ObjUnknown(key)
4580 if not isinstance(value, spec.__class__):
4581 raise InvalidValueType((spec.__class__,))
4582 self._value = (key, spec(value))
4590 return self._value[1].decoded if self.ready else False
4593 self._assert_ready()
4594 return self._value[1].encode()
4596 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4597 for choice, spec in iteritems(self.specs):
4598 sub_decode_path = decode_path + (choice,)
4604 decode_path=sub_decode_path,
4607 _ctx_immutable=False,
4614 klass=self.__class__,
4615 decode_path=decode_path,
4618 if tag_only: # pragma: no cover
4620 value, tail = spec.decode(
4624 decode_path=sub_decode_path,
4626 _ctx_immutable=False,
4628 obj = self.__class__(
4631 default=self.default,
4632 optional=self.optional,
4633 _decoded=(offset, 0, value.fulllen),
4635 obj._value = (choice, value)
4639 value = pp_console_row(next(self.pps()))
4641 value = "%s[%r]" % (value, self.value)
4644 def pps(self, decode_path=()):
4647 asn1_type_name=self.asn1_type_name,
4648 obj_name=self.__class__.__name__,
4649 decode_path=decode_path,
4650 value=self.choice if self.ready else None,
4651 optional=self.optional,
4652 default=self == self.default,
4653 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4654 expl=None if self._expl is None else tag_decode(self._expl),
4659 expl_lenindef=self.expl_lenindef,
4663 yield self.value.pps(decode_path=decode_path + (self.choice,))
4664 for pp in self.pps_lenindef(decode_path):
4668 class PrimitiveTypes(Choice):
4669 """Predefined ``CHOICE`` for all generic primitive types
4671 It could be useful for general decoding of some unspecified values:
4673 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4674 OCTET STRING 3 bytes 666f6f
4675 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4679 schema = tuple((klass.__name__, klass()) for klass in (
4703 AnyState = namedtuple("AnyState", (
4720 """``ANY`` special type
4722 >>> Any(Integer(-123))
4724 >>> a = Any(OctetString(b"hello world").encode())
4725 ANY 040b68656c6c6f20776f726c64
4726 >>> hexenc(bytes(a))
4727 b'0x040x0bhello world'
4729 __slots__ = ("defined",)
4730 tag_default = tag_encode(0)
4731 asn1_type_name = "ANY"
4741 :param value: set the value. Either any kind of pyderasn's
4742 **ready** object, or bytes. Pay attention that
4743 **no** validation is performed is raw binary value
4745 :param bytes expl: override default tag with ``EXPLICIT`` one
4746 :param bool optional: is object ``OPTIONAL`` in sequence
4748 super(Any, self).__init__(None, expl, None, optional, _decoded)
4749 self._value = None if value is None else self._value_sanitize(value)
4752 def _value_sanitize(self, value):
4753 if isinstance(value, binary_type):
4755 if isinstance(value, self.__class__):
4757 if isinstance(value, Obj):
4758 return value.encode()
4759 raise InvalidValueType((self.__class__, Obj, binary_type))
4763 return self._value is not None
4767 if self.expl_lenindef or self.lenindef:
4769 if self.defined is None:
4771 return self.defined[1].bered
4773 def __getstate__(self):
4789 def __setstate__(self, state):
4790 super(Any, self).__setstate__(state)
4791 self._value = state.value
4792 self.tag = state.tag
4793 self._expl = state.expl
4794 self.optional = state.optional
4795 self.offset = state.offset
4796 self.llen = state.llen
4797 self.vlen = state.vlen
4798 self.expl_lenindef = state.expl_lenindef
4799 self.lenindef = state.lenindef
4800 self.ber_encoded = state.ber_encoded
4801 self.defined = state.defined
4803 def __eq__(self, their):
4804 if isinstance(their, binary_type):
4805 return self._value == their
4806 if issubclass(their.__class__, Any):
4807 return self._value == their._value
4816 return self.__class__(
4818 expl=self._expl if expl is None else expl,
4819 optional=self.optional if optional is None else optional,
4822 def __bytes__(self):
4823 self._assert_ready()
4831 self._assert_ready()
4834 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4836 t, tlen, lv = tag_strip(tlv)
4837 except DecodeError as err:
4838 raise err.__class__(
4840 klass=self.__class__,
4841 decode_path=decode_path,
4845 l, llen, v = len_decode(lv)
4846 except LenIndefForm as err:
4847 if not ctx.get("bered", False):
4848 raise err.__class__(
4850 klass=self.__class__,
4851 decode_path=decode_path,
4854 llen, vlen, v = 1, 0, lv[1:]
4855 sub_offset = offset + tlen + llen
4857 while v[:EOC_LEN].tobytes() != EOC:
4858 chunk, v = Any().decode(
4861 decode_path=decode_path + (str(chunk_i),),
4864 _ctx_immutable=False,
4866 vlen += chunk.tlvlen
4867 sub_offset += chunk.tlvlen
4869 tlvlen = tlen + llen + vlen + EOC_LEN
4870 obj = self.__class__(
4871 value=tlv[:tlvlen].tobytes(),
4873 optional=self.optional,
4874 _decoded=(offset, 0, tlvlen),
4877 obj.tag = t.tobytes()
4878 return obj, v[EOC_LEN:]
4879 except DecodeError as err:
4880 raise err.__class__(
4882 klass=self.__class__,
4883 decode_path=decode_path,
4887 raise NotEnoughData(
4888 "encoded length is longer than data",
4889 klass=self.__class__,
4890 decode_path=decode_path,
4893 tlvlen = tlen + llen + l
4894 v, tail = tlv[:tlvlen], v[l:]
4895 obj = self.__class__(
4898 optional=self.optional,
4899 _decoded=(offset, 0, tlvlen),
4901 obj.tag = t.tobytes()
4905 return pp_console_row(next(self.pps()))
4907 def pps(self, decode_path=()):
4910 asn1_type_name=self.asn1_type_name,
4911 obj_name=self.__class__.__name__,
4912 decode_path=decode_path,
4913 blob=self._value if self.ready else None,
4914 optional=self.optional,
4915 default=self == self.default,
4916 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4917 expl=None if self._expl is None else tag_decode(self._expl),
4922 expl_offset=self.expl_offset if self.expled else None,
4923 expl_tlen=self.expl_tlen if self.expled else None,
4924 expl_llen=self.expl_llen if self.expled else None,
4925 expl_vlen=self.expl_vlen if self.expled else None,
4926 expl_lenindef=self.expl_lenindef,
4927 lenindef=self.lenindef,
4930 defined_by, defined = self.defined or (None, None)
4931 if defined_by is not None:
4933 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4935 for pp in self.pps_lenindef(decode_path):
4939 ########################################################################
4940 # ASN.1 constructed types
4941 ########################################################################
4943 def get_def_by_path(defines_by_path, sub_decode_path):
4944 """Get define by decode path
4946 for path, define in defines_by_path:
4947 if len(path) != len(sub_decode_path):
4949 for p1, p2 in zip(path, sub_decode_path):
4950 if (p1 != any) and (p1 != p2):
4956 def abs_decode_path(decode_path, rel_path):
4957 """Create an absolute decode path from current and relative ones
4959 :param decode_path: current decode path, starting point. Tuple of strings
4960 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4961 If first tuple's element is "/", then treat it as
4962 an absolute path, ignoring ``decode_path`` as
4963 starting point. Also this tuple can contain ".."
4964 elements, stripping the leading element from
4967 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4968 ("foo", "bar", "baz", "whatever")
4969 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4971 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4974 if rel_path[0] == "/":
4976 if rel_path[0] == "..":
4977 return abs_decode_path(decode_path[:-1], rel_path[1:])
4978 return decode_path + rel_path
4981 SequenceState = namedtuple("SequenceState", (
4998 class Sequence(Obj):
4999 """``SEQUENCE`` structure type
5001 You have to make specification of sequence::
5003 class Extension(Sequence):
5005 ("extnID", ObjectIdentifier()),
5006 ("critical", Boolean(default=False)),
5007 ("extnValue", OctetString()),
5010 Then, you can work with it as with dictionary.
5012 >>> ext = Extension()
5013 >>> Extension().specs
5015 ('extnID', OBJECT IDENTIFIER),
5016 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5017 ('extnValue', OCTET STRING),
5019 >>> ext["extnID"] = "1.2.3"
5020 Traceback (most recent call last):
5021 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5022 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5024 You can determine if sequence is ready to be encoded:
5029 Traceback (most recent call last):
5030 pyderasn.ObjNotReady: object is not ready: extnValue
5031 >>> ext["extnValue"] = OctetString(b"foobar")
5035 Value you want to assign, must have the same **type** as in
5036 corresponding specification, but it can have different tags,
5037 optional/default attributes -- they will be taken from specification
5040 class TBSCertificate(Sequence):
5042 ("version", Version(expl=tag_ctxc(0), default="v1")),
5045 >>> tbs = TBSCertificate()
5046 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5048 Assign ``None`` to remove value from sequence.
5050 You can set values in Sequence during its initialization:
5052 >>> AlgorithmIdentifier((
5053 ("algorithm", ObjectIdentifier("1.2.3")),
5054 ("parameters", Any(Null()))
5056 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5058 You can determine if value exists/set in the sequence and take its value:
5060 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5063 OBJECT IDENTIFIER 1.2.3
5065 But pay attention that if value has default, then it won't be (not
5066 in) in the sequence (because ``DEFAULT`` must not be encoded in
5067 DER), but you can read its value:
5069 >>> "critical" in ext, ext["critical"]
5070 (False, BOOLEAN False)
5071 >>> ext["critical"] = Boolean(True)
5072 >>> "critical" in ext, ext["critical"]
5073 (True, BOOLEAN True)
5075 All defaulted values are always optional.
5077 .. _allow_default_values_ctx:
5079 DER prohibits default value encoding and will raise an error if
5080 default value is unexpectedly met during decode.
5081 If :ref:`bered <bered_ctx>` context option is set, then no error
5082 will be raised, but ``bered`` attribute set. You can disable strict
5083 defaulted values existence validation by setting
5084 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5086 Two sequences are equal if they have equal specification (schema),
5087 implicit/explicit tagging and the same values.
5089 __slots__ = ("specs",)
5090 tag_default = tag_encode(form=TagFormConstructed, num=16)
5091 asn1_type_name = "SEQUENCE"
5103 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5105 schema = getattr(self, "schema", ())
5107 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5110 if value is not None:
5111 if issubclass(value.__class__, Sequence):
5112 self._value = value._value
5113 elif hasattr(value, "__iter__"):
5114 for seq_key, seq_value in value:
5115 self[seq_key] = seq_value
5117 raise InvalidValueType((Sequence,))
5118 if default is not None:
5119 if not issubclass(default.__class__, Sequence):
5120 raise InvalidValueType((Sequence,))
5121 default_value = default._value
5122 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5123 default_obj.specs = self.specs
5124 default_obj._value = default_value
5125 self.default = default_obj
5127 self._value = copy(default_obj._value)
5131 for name, spec in iteritems(self.specs):
5132 value = self._value.get(name)
5143 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5145 return any(value.bered for value in itervalues(self._value))
5147 def __getstate__(self):
5148 return SequenceState(
5151 {k: copy(v) for k, v in iteritems(self._value)},
5164 def __setstate__(self, state):
5165 super(Sequence, self).__setstate__(state)
5166 self.specs = state.specs
5167 self._value = state.value
5168 self.tag = state.tag
5169 self._expl = state.expl
5170 self.default = state.default
5171 self.optional = state.optional
5172 self.offset = state.offset
5173 self.llen = state.llen
5174 self.vlen = state.vlen
5175 self.expl_lenindef = state.expl_lenindef
5176 self.lenindef = state.lenindef
5177 self.ber_encoded = state.ber_encoded
5179 def __eq__(self, their):
5180 if not isinstance(their, self.__class__):
5183 self.specs == their.specs and
5184 self.tag == their.tag and
5185 self._expl == their._expl and
5186 self._value == their._value
5197 return self.__class__(
5200 impl=self.tag if impl is None else impl,
5201 expl=self._expl if expl is None else expl,
5202 default=self.default if default is None else default,
5203 optional=self.optional if optional is None else optional,
5206 def __contains__(self, key):
5207 return key in self._value
5209 def __setitem__(self, key, value):
5210 spec = self.specs.get(key)
5212 raise ObjUnknown(key)
5214 self._value.pop(key, None)
5216 if not isinstance(value, spec.__class__):
5217 raise InvalidValueType((spec.__class__,))
5218 value = spec(value=value)
5219 if spec.default is not None and value == spec.default:
5220 self._value.pop(key, None)
5222 self._value[key] = value
5224 def __getitem__(self, key):
5225 value = self._value.get(key)
5226 if value is not None:
5228 spec = self.specs.get(key)
5230 raise ObjUnknown(key)
5231 if spec.default is not None:
5235 def _encoded_values(self):
5237 for name, spec in iteritems(self.specs):
5238 value = self._value.get(name)
5242 raise ObjNotReady(name)
5243 raws.append(value.encode())
5247 v = b"".join(self._encoded_values())
5248 return b"".join((self.tag, len_encode(len(v)), v))
5250 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5252 t, tlen, lv = tag_strip(tlv)
5253 except DecodeError as err:
5254 raise err.__class__(
5256 klass=self.__class__,
5257 decode_path=decode_path,
5262 klass=self.__class__,
5263 decode_path=decode_path,
5266 if tag_only: # pragma: no cover
5269 ctx_bered = ctx.get("bered", False)
5271 l, llen, v = len_decode(lv)
5272 except LenIndefForm as err:
5274 raise err.__class__(
5276 klass=self.__class__,
5277 decode_path=decode_path,
5280 l, llen, v = 0, 1, lv[1:]
5282 except DecodeError as err:
5283 raise err.__class__(
5285 klass=self.__class__,
5286 decode_path=decode_path,
5290 raise NotEnoughData(
5291 "encoded length is longer than data",
5292 klass=self.__class__,
5293 decode_path=decode_path,
5297 v, tail = v[:l], v[l:]
5299 sub_offset = offset + tlen + llen
5302 ctx_allow_default_values = ctx.get("allow_default_values", False)
5303 for name, spec in iteritems(self.specs):
5304 if spec.optional and (
5305 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5309 sub_decode_path = decode_path + (name,)
5311 value, v_tail = spec.decode(
5315 decode_path=sub_decode_path,
5317 _ctx_immutable=False,
5319 except TagMismatch as err:
5320 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5324 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5325 if defined is not None:
5326 defined_by, defined_spec = defined
5327 if issubclass(value.__class__, SequenceOf):
5328 for i, _value in enumerate(value):
5329 sub_sub_decode_path = sub_decode_path + (
5331 DecodePathDefBy(defined_by),
5333 defined_value, defined_tail = defined_spec.decode(
5334 memoryview(bytes(_value)),
5336 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5337 if value.expled else (value.tlen + value.llen)
5340 decode_path=sub_sub_decode_path,
5342 _ctx_immutable=False,
5344 if len(defined_tail) > 0:
5347 klass=self.__class__,
5348 decode_path=sub_sub_decode_path,
5351 _value.defined = (defined_by, defined_value)
5353 defined_value, defined_tail = defined_spec.decode(
5354 memoryview(bytes(value)),
5356 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5357 if value.expled else (value.tlen + value.llen)
5360 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5362 _ctx_immutable=False,
5364 if len(defined_tail) > 0:
5367 klass=self.__class__,
5368 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5371 value.defined = (defined_by, defined_value)
5373 value_len = value.fulllen
5375 sub_offset += value_len
5377 if spec.default is not None and value == spec.default:
5378 if ctx_bered or ctx_allow_default_values:
5382 "DEFAULT value met",
5383 klass=self.__class__,
5384 decode_path=sub_decode_path,
5387 values[name] = value
5389 spec_defines = getattr(spec, "defines", ())
5390 if len(spec_defines) == 0:
5391 defines_by_path = ctx.get("defines_by_path", ())
5392 if len(defines_by_path) > 0:
5393 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5394 if spec_defines is not None and len(spec_defines) > 0:
5395 for rel_path, schema in spec_defines:
5396 defined = schema.get(value, None)
5397 if defined is not None:
5398 ctx.setdefault("_defines", []).append((
5399 abs_decode_path(sub_decode_path[:-1], rel_path),
5403 if v[:EOC_LEN].tobytes() != EOC:
5406 klass=self.__class__,
5407 decode_path=decode_path,
5415 klass=self.__class__,
5416 decode_path=decode_path,
5419 obj = self.__class__(
5423 default=self.default,
5424 optional=self.optional,
5425 _decoded=(offset, llen, vlen),
5428 obj.lenindef = lenindef
5429 obj.ber_encoded = ber_encoded
5433 value = pp_console_row(next(self.pps()))
5435 for name in self.specs:
5436 _value = self._value.get(name)
5439 cols.append("%s: %s" % (name, repr(_value)))
5440 return "%s[%s]" % (value, "; ".join(cols))
5442 def pps(self, decode_path=()):
5445 asn1_type_name=self.asn1_type_name,
5446 obj_name=self.__class__.__name__,
5447 decode_path=decode_path,
5448 optional=self.optional,
5449 default=self == self.default,
5450 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5451 expl=None if self._expl is None else tag_decode(self._expl),
5456 expl_offset=self.expl_offset if self.expled else None,
5457 expl_tlen=self.expl_tlen if self.expled else None,
5458 expl_llen=self.expl_llen if self.expled else None,
5459 expl_vlen=self.expl_vlen if self.expled else None,
5460 expl_lenindef=self.expl_lenindef,
5461 lenindef=self.lenindef,
5462 ber_encoded=self.ber_encoded,
5465 for name in self.specs:
5466 value = self._value.get(name)
5469 yield value.pps(decode_path=decode_path + (name,))
5470 for pp in self.pps_lenindef(decode_path):
5474 class Set(Sequence):
5475 """``SET`` structure type
5477 Its usage is identical to :py:class:`pyderasn.Sequence`.
5479 .. _allow_unordered_set_ctx:
5481 DER prohibits unordered values encoding and will raise an error
5482 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5483 then no error will occure. Also you can disable strict values
5484 ordering check by setting ``"allow_unordered_set": True``
5485 :ref:`context <ctx>` option.
5488 tag_default = tag_encode(form=TagFormConstructed, num=17)
5489 asn1_type_name = "SET"
5492 raws = self._encoded_values()
5495 return b"".join((self.tag, len_encode(len(v)), v))
5497 def _specs_items(self):
5498 return iteritems(self.specs)
5500 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5502 t, tlen, lv = tag_strip(tlv)
5503 except DecodeError as err:
5504 raise err.__class__(
5506 klass=self.__class__,
5507 decode_path=decode_path,
5512 klass=self.__class__,
5513 decode_path=decode_path,
5519 ctx_bered = ctx.get("bered", False)
5521 l, llen, v = len_decode(lv)
5522 except LenIndefForm as err:
5524 raise err.__class__(
5526 klass=self.__class__,
5527 decode_path=decode_path,
5530 l, llen, v = 0, 1, lv[1:]
5532 except DecodeError as err:
5533 raise err.__class__(
5535 klass=self.__class__,
5536 decode_path=decode_path,
5540 raise NotEnoughData(
5541 "encoded length is longer than data",
5542 klass=self.__class__,
5546 v, tail = v[:l], v[l:]
5548 sub_offset = offset + tlen + llen
5551 ctx_allow_default_values = ctx.get("allow_default_values", False)
5552 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5553 value_prev = memoryview(v[:0])
5556 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5558 for name, spec in self._specs_items():
5559 sub_decode_path = decode_path + (name,)
5565 decode_path=sub_decode_path,
5568 _ctx_immutable=False,
5575 klass=self.__class__,
5576 decode_path=decode_path,
5579 value, v_tail = spec.decode(
5583 decode_path=sub_decode_path,
5585 _ctx_immutable=False,
5587 value_len = value.fulllen
5588 if value_prev.tobytes() > v[:value_len].tobytes():
5589 if ctx_bered or ctx_allow_unordered_set:
5593 "unordered " + self.asn1_type_name,
5594 klass=self.__class__,
5595 decode_path=sub_decode_path,
5598 if spec.default is None or value != spec.default:
5600 elif ctx_bered or ctx_allow_default_values:
5604 "DEFAULT value met",
5605 klass=self.__class__,
5606 decode_path=sub_decode_path,
5609 values[name] = value
5610 value_prev = v[:value_len]
5611 sub_offset += value_len
5614 obj = self.__class__(
5618 default=self.default,
5619 optional=self.optional,
5620 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5623 if v[:EOC_LEN].tobytes() != EOC:
5626 klass=self.__class__,
5627 decode_path=decode_path,
5635 "not all values are ready",
5636 klass=self.__class__,
5637 decode_path=decode_path,
5640 obj.ber_encoded = ber_encoded
5644 SequenceOfState = namedtuple("SequenceOfState", (
5663 class SequenceOf(Obj):
5664 """``SEQUENCE OF`` sequence type
5666 For that kind of type you must specify the object it will carry on
5667 (bounds are for example here, not required)::
5669 class Ints(SequenceOf):
5674 >>> ints.append(Integer(123))
5675 >>> ints.append(Integer(234))
5677 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5678 >>> [int(i) for i in ints]
5680 >>> ints.append(Integer(345))
5681 Traceback (most recent call last):
5682 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5685 >>> ints[1] = Integer(345)
5687 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5689 Also you can initialize sequence with preinitialized values:
5691 >>> ints = Ints([Integer(123), Integer(234)])
5693 __slots__ = ("spec", "_bound_min", "_bound_max")
5694 tag_default = tag_encode(form=TagFormConstructed, num=16)
5695 asn1_type_name = "SEQUENCE OF"
5708 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5710 schema = getattr(self, "schema", None)
5712 raise ValueError("schema must be specified")
5714 self._bound_min, self._bound_max = getattr(
5718 ) if bounds is None else bounds
5720 if value is not None:
5721 self._value = self._value_sanitize(value)
5722 if default is not None:
5723 default_value = self._value_sanitize(default)
5724 default_obj = self.__class__(
5729 default_obj._value = default_value
5730 self.default = default_obj
5732 self._value = copy(default_obj._value)
5734 def _value_sanitize(self, value):
5735 if issubclass(value.__class__, SequenceOf):
5736 value = value._value
5737 elif hasattr(value, "__iter__"):
5740 raise InvalidValueType((self.__class__, iter))
5741 if not self._bound_min <= len(value) <= self._bound_max:
5742 raise BoundsError(self._bound_min, len(value), self._bound_max)
5744 if not isinstance(v, self.spec.__class__):
5745 raise InvalidValueType((self.spec.__class__,))
5750 return all(v.ready for v in self._value)
5754 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5756 return any(v.bered for v in self._value)
5758 def __getstate__(self):
5759 return SequenceOfState(
5762 [copy(v) for v in self._value],
5777 def __setstate__(self, state):
5778 super(SequenceOf, self).__setstate__(state)
5779 self.spec = state.spec
5780 self._value = state.value
5781 self._bound_min = state.bound_min
5782 self._bound_max = state.bound_max
5783 self.tag = state.tag
5784 self._expl = state.expl
5785 self.default = state.default
5786 self.optional = state.optional
5787 self.offset = state.offset
5788 self.llen = state.llen
5789 self.vlen = state.vlen
5790 self.expl_lenindef = state.expl_lenindef
5791 self.lenindef = state.lenindef
5792 self.ber_encoded = state.ber_encoded
5794 def __eq__(self, their):
5795 if isinstance(their, self.__class__):
5797 self.spec == their.spec and
5798 self.tag == their.tag and
5799 self._expl == their._expl and
5800 self._value == their._value
5802 if hasattr(their, "__iter__"):
5803 return self._value == list(their)
5815 return self.__class__(
5819 (self._bound_min, self._bound_max)
5820 if bounds is None else bounds
5822 impl=self.tag if impl is None else impl,
5823 expl=self._expl if expl is None else expl,
5824 default=self.default if default is None else default,
5825 optional=self.optional if optional is None else optional,
5828 def __contains__(self, key):
5829 return key in self._value
5831 def append(self, value):
5832 if not isinstance(value, self.spec.__class__):
5833 raise InvalidValueType((self.spec.__class__,))
5834 if len(self._value) + 1 > self._bound_max:
5837 len(self._value) + 1,
5840 self._value.append(value)
5843 self._assert_ready()
5844 return iter(self._value)
5847 self._assert_ready()
5848 return len(self._value)
5850 def __setitem__(self, key, value):
5851 if not isinstance(value, self.spec.__class__):
5852 raise InvalidValueType((self.spec.__class__,))
5853 self._value[key] = self.spec(value=value)
5855 def __getitem__(self, key):
5856 return self._value[key]
5858 def _encoded_values(self):
5859 return [v.encode() for v in self._value]
5862 v = b"".join(self._encoded_values())
5863 return b"".join((self.tag, len_encode(len(v)), v))
5865 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5867 t, tlen, lv = tag_strip(tlv)
5868 except DecodeError as err:
5869 raise err.__class__(
5871 klass=self.__class__,
5872 decode_path=decode_path,
5877 klass=self.__class__,
5878 decode_path=decode_path,
5884 ctx_bered = ctx.get("bered", False)
5886 l, llen, v = len_decode(lv)
5887 except LenIndefForm as err:
5889 raise err.__class__(
5891 klass=self.__class__,
5892 decode_path=decode_path,
5895 l, llen, v = 0, 1, lv[1:]
5897 except DecodeError as err:
5898 raise err.__class__(
5900 klass=self.__class__,
5901 decode_path=decode_path,
5905 raise NotEnoughData(
5906 "encoded length is longer than data",
5907 klass=self.__class__,
5908 decode_path=decode_path,
5912 v, tail = v[:l], v[l:]
5914 sub_offset = offset + tlen + llen
5916 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5917 value_prev = memoryview(v[:0])
5921 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5923 sub_decode_path = decode_path + (str(len(_value)),)
5924 value, v_tail = spec.decode(
5928 decode_path=sub_decode_path,
5930 _ctx_immutable=False,
5932 value_len = value.fulllen
5934 if value_prev.tobytes() > v[:value_len].tobytes():
5935 if ctx_bered or ctx_allow_unordered_set:
5939 "unordered " + self.asn1_type_name,
5940 klass=self.__class__,
5941 decode_path=sub_decode_path,
5944 value_prev = v[:value_len]
5945 _value.append(value)
5946 sub_offset += value_len
5950 obj = self.__class__(
5953 bounds=(self._bound_min, self._bound_max),
5956 default=self.default,
5957 optional=self.optional,
5958 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5960 except BoundsError as err:
5963 klass=self.__class__,
5964 decode_path=decode_path,
5968 if v[:EOC_LEN].tobytes() != EOC:
5971 klass=self.__class__,
5972 decode_path=decode_path,
5977 obj.ber_encoded = ber_encoded
5982 pp_console_row(next(self.pps())),
5983 ", ".join(repr(v) for v in self._value),
5986 def pps(self, decode_path=()):
5989 asn1_type_name=self.asn1_type_name,
5990 obj_name=self.__class__.__name__,
5991 decode_path=decode_path,
5992 optional=self.optional,
5993 default=self == self.default,
5994 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5995 expl=None if self._expl is None else tag_decode(self._expl),
6000 expl_offset=self.expl_offset if self.expled else None,
6001 expl_tlen=self.expl_tlen if self.expled else None,
6002 expl_llen=self.expl_llen if self.expled else None,
6003 expl_vlen=self.expl_vlen if self.expled else None,
6004 expl_lenindef=self.expl_lenindef,
6005 lenindef=self.lenindef,
6006 ber_encoded=self.ber_encoded,
6009 for i, value in enumerate(self._value):
6010 yield value.pps(decode_path=decode_path + (str(i),))
6011 for pp in self.pps_lenindef(decode_path):
6015 class SetOf(SequenceOf):
6016 """``SET OF`` sequence type
6018 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6021 tag_default = tag_encode(form=TagFormConstructed, num=17)
6022 asn1_type_name = "SET OF"
6025 raws = self._encoded_values()
6028 return b"".join((self.tag, len_encode(len(v)), v))
6030 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6031 return super(SetOf, self)._decode(
6037 ordering_check=True,
6041 def obj_by_path(pypath): # pragma: no cover
6042 """Import object specified as string Python path
6044 Modules must be separated from classes/functions with ``:``.
6046 >>> obj_by_path("foo.bar:Baz")
6047 <class 'foo.bar.Baz'>
6048 >>> obj_by_path("foo.bar:Baz.boo")
6049 <classmethod 'foo.bar.Baz.boo'>
6051 mod, objs = pypath.rsplit(":", 1)
6052 from importlib import import_module
6053 obj = import_module(mod)
6054 for obj_name in objs.split("."):
6055 obj = getattr(obj, obj_name)
6059 def generic_decoder(): # pragma: no cover
6060 # All of this below is a big hack with self references
6061 choice = PrimitiveTypes()
6062 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6063 choice.specs["SetOf"] = SetOf(schema=choice)
6064 for i in six_xrange(31):
6065 choice.specs["SequenceOf%d" % i] = SequenceOf(
6069 choice.specs["Any"] = Any()
6071 # Class name equals to type name, to omit it from output
6072 class SEQUENCEOF(SequenceOf):
6080 with_decode_path=False,
6081 decode_path_only=(),
6083 def _pprint_pps(pps):
6085 if hasattr(pp, "_fields"):
6087 decode_path_only != () and
6088 pp.decode_path[:len(decode_path_only)] != decode_path_only
6091 if pp.asn1_type_name == Choice.asn1_type_name:
6093 pp_kwargs = pp._asdict()
6094 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6095 pp = _pp(**pp_kwargs)
6096 yield pp_console_row(
6101 with_colours=with_colours,
6102 with_decode_path=with_decode_path,
6103 decode_path_len_decrease=len(decode_path_only),
6105 for row in pp_console_blob(
6107 decode_path_len_decrease=len(decode_path_only),
6111 for row in _pprint_pps(pp):
6113 return "\n".join(_pprint_pps(obj.pps()))
6114 return SEQUENCEOF(), pprint_any
6117 def main(): # pragma: no cover
6119 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6120 parser.add_argument(
6124 help="Skip that number of bytes from the beginning",
6126 parser.add_argument(
6128 help="Python paths to dictionary with OIDs, comma separated",
6130 parser.add_argument(
6132 help="Python path to schema definition to use",
6134 parser.add_argument(
6135 "--defines-by-path",
6136 help="Python path to decoder's defines_by_path",
6138 parser.add_argument(
6140 action="store_true",
6141 help="Disallow BER encoding",
6143 parser.add_argument(
6144 "--print-decode-path",
6145 action="store_true",
6146 help="Print decode paths",
6148 parser.add_argument(
6149 "--decode-path-only",
6150 help="Print only specified decode path",
6152 parser.add_argument(
6154 action="store_true",
6155 help="Allow explicit tag out-of-bound",
6157 parser.add_argument(
6159 type=argparse.FileType("rb"),
6160 help="Path to DER file you want to decode",
6162 args = parser.parse_args()
6163 args.DERFile.seek(args.skip)
6164 der = memoryview(args.DERFile.read())
6165 args.DERFile.close()
6167 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6168 if args.oids else ()
6171 schema = obj_by_path(args.schema)
6172 from functools import partial
6173 pprinter = partial(pprint, big_blobs=True)
6175 schema, pprinter = generic_decoder()
6177 "bered": not args.nobered,
6178 "allow_expl_oob": args.allow_expl_oob,
6180 if args.defines_by_path is not None:
6181 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6182 obj, tail = schema().decode(der, ctx=ctx)
6186 with_colours=environ.get("NO_COLOR") is None,
6187 with_decode_path=args.print_decode_path,
6189 () if args.decode_path_only is None else
6190 tuple(args.decode_path_only.split(":"))
6194 print("\nTrailing data: %s" % hexenc(tail))
6197 if __name__ == "__main__":