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