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 ``str(OID) <-> human readable string`` dictionary.
1673 Its human readable form is printed when OID is met
1674 :param big_blobs: if large binary objects are met (like OctetString
1675 values), do we need to print them too, on separate
1677 :param with_colours: colourize output, if ``termcolor`` library
1679 :param with_decode_path: print decode path
1680 :param decode_path_only: print only that specified decode path
1682 def _pprint_pps(pps):
1684 if hasattr(pp, "_fields"):
1686 decode_path_only != () and
1688 str(p) for p in pp.decode_path[:len(decode_path_only)]
1689 ) != decode_path_only
1693 yield pp_console_row(
1698 with_colours=with_colours,
1699 with_decode_path=with_decode_path,
1700 decode_path_len_decrease=len(decode_path_only),
1702 for row in pp_console_blob(
1704 decode_path_len_decrease=len(decode_path_only),
1708 yield pp_console_row(
1713 with_colours=with_colours,
1714 with_decode_path=with_decode_path,
1715 decode_path_len_decrease=len(decode_path_only),
1718 for row in _pprint_pps(pp):
1720 return "\n".join(_pprint_pps(obj.pps()))
1723 ########################################################################
1724 # ASN.1 primitive types
1725 ########################################################################
1727 BooleanState = namedtuple("BooleanState", (
1744 """``BOOLEAN`` boolean type
1746 >>> b = Boolean(True)
1748 >>> b == Boolean(True)
1754 tag_default = tag_encode(1)
1755 asn1_type_name = "BOOLEAN"
1767 :param value: set the value. Either boolean type, or
1768 :py:class:`pyderasn.Boolean` object
1769 :param bytes impl: override default tag with ``IMPLICIT`` one
1770 :param bytes expl: override default tag with ``EXPLICIT`` one
1771 :param default: set default value. Type same as in ``value``
1772 :param bool optional: is object ``OPTIONAL`` in sequence
1774 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1775 self._value = None if value is None else self._value_sanitize(value)
1776 if default is not None:
1777 default = self._value_sanitize(default)
1778 self.default = self.__class__(
1784 self._value = default
1786 def _value_sanitize(self, value):
1787 if isinstance(value, bool):
1789 if issubclass(value.__class__, Boolean):
1791 raise InvalidValueType((self.__class__, bool))
1795 return self._value is not None
1797 def __getstate__(self):
1798 return BooleanState(
1813 def __setstate__(self, state):
1814 super(Boolean, self).__setstate__(state)
1815 self._value = state.value
1816 self.tag = state.tag
1817 self._expl = state.expl
1818 self.default = state.default
1819 self.optional = state.optional
1820 self.offset = state.offset
1821 self.llen = state.llen
1822 self.vlen = state.vlen
1823 self.expl_lenindef = state.expl_lenindef
1824 self.lenindef = state.lenindef
1825 self.ber_encoded = state.ber_encoded
1827 def __nonzero__(self):
1828 self._assert_ready()
1832 self._assert_ready()
1835 def __eq__(self, their):
1836 if isinstance(their, bool):
1837 return self._value == their
1838 if not issubclass(their.__class__, Boolean):
1841 self._value == their._value and
1842 self.tag == their.tag and
1843 self._expl == their._expl
1854 return self.__class__(
1856 impl=self.tag if impl is None else impl,
1857 expl=self._expl if expl is None else expl,
1858 default=self.default if default is None else default,
1859 optional=self.optional if optional is None else optional,
1863 self._assert_ready()
1867 (b"\xFF" if self._value else b"\x00"),
1870 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1872 t, _, lv = tag_strip(tlv)
1873 except DecodeError as err:
1874 raise err.__class__(
1876 klass=self.__class__,
1877 decode_path=decode_path,
1882 klass=self.__class__,
1883 decode_path=decode_path,
1889 l, _, v = len_decode(lv)
1890 except DecodeError as err:
1891 raise err.__class__(
1893 klass=self.__class__,
1894 decode_path=decode_path,
1898 raise InvalidLength(
1899 "Boolean's length must be equal to 1",
1900 klass=self.__class__,
1901 decode_path=decode_path,
1905 raise NotEnoughData(
1906 "encoded length is longer than data",
1907 klass=self.__class__,
1908 decode_path=decode_path,
1911 first_octet = byte2int(v)
1913 if first_octet == 0:
1915 elif first_octet == 0xFF:
1917 elif ctx.get("bered", False):
1922 "unacceptable Boolean value",
1923 klass=self.__class__,
1924 decode_path=decode_path,
1927 obj = self.__class__(
1931 default=self.default,
1932 optional=self.optional,
1933 _decoded=(offset, 1, 1),
1935 obj.ber_encoded = ber_encoded
1939 return pp_console_row(next(self.pps()))
1941 def pps(self, decode_path=()):
1944 asn1_type_name=self.asn1_type_name,
1945 obj_name=self.__class__.__name__,
1946 decode_path=decode_path,
1947 value=str(self._value) if self.ready else None,
1948 optional=self.optional,
1949 default=self == self.default,
1950 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1951 expl=None if self._expl is None else tag_decode(self._expl),
1956 expl_offset=self.expl_offset if self.expled else None,
1957 expl_tlen=self.expl_tlen if self.expled else None,
1958 expl_llen=self.expl_llen if self.expled else None,
1959 expl_vlen=self.expl_vlen if self.expled else None,
1960 expl_lenindef=self.expl_lenindef,
1961 ber_encoded=self.ber_encoded,
1964 for pp in self.pps_lenindef(decode_path):
1968 IntegerState = namedtuple("IntegerState", (
1988 """``INTEGER`` integer type
1990 >>> b = Integer(-123)
1992 >>> b == Integer(-123)
1997 >>> Integer(2, bounds=(1, 3))
1999 >>> Integer(5, bounds=(1, 3))
2000 Traceback (most recent call last):
2001 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
2005 class Version(Integer):
2012 >>> v = Version("v1")
2019 {'v3': 2, 'v1': 0, 'v2': 1}
2021 __slots__ = ("specs", "_bound_min", "_bound_max")
2022 tag_default = tag_encode(2)
2023 asn1_type_name = "INTEGER"
2037 :param value: set the value. Either integer type, named value
2038 (if ``schema`` is specified in the class), or
2039 :py:class:`pyderasn.Integer` object
2040 :param bounds: set ``(MIN, MAX)`` value constraint.
2041 (-inf, +inf) by default
2042 :param bytes impl: override default tag with ``IMPLICIT`` one
2043 :param bytes expl: override default tag with ``EXPLICIT`` one
2044 :param default: set default value. Type same as in ``value``
2045 :param bool optional: is object ``OPTIONAL`` in sequence
2047 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
2049 specs = getattr(self, "schema", {}) if _specs is None else _specs
2050 self.specs = specs if isinstance(specs, dict) else dict(specs)
2051 self._bound_min, self._bound_max = getattr(
2054 (float("-inf"), float("+inf")),
2055 ) if bounds is None else bounds
2056 if value is not None:
2057 self._value = self._value_sanitize(value)
2058 if default is not None:
2059 default = self._value_sanitize(default)
2060 self.default = self.__class__(
2066 if self._value is None:
2067 self._value = default
2069 def _value_sanitize(self, value):
2070 if isinstance(value, integer_types):
2072 elif issubclass(value.__class__, Integer):
2073 value = value._value
2074 elif isinstance(value, str):
2075 value = self.specs.get(value)
2077 raise ObjUnknown("integer value: %s" % value)
2079 raise InvalidValueType((self.__class__, int, str))
2080 if not self._bound_min <= value <= self._bound_max:
2081 raise BoundsError(self._bound_min, value, self._bound_max)
2086 return self._value is not None
2088 def __getstate__(self):
2089 return IntegerState(
2107 def __setstate__(self, state):
2108 super(Integer, self).__setstate__(state)
2109 self.specs = state.specs
2110 self._value = state.value
2111 self._bound_min = state.bound_min
2112 self._bound_max = state.bound_max
2113 self.tag = state.tag
2114 self._expl = state.expl
2115 self.default = state.default
2116 self.optional = state.optional
2117 self.offset = state.offset
2118 self.llen = state.llen
2119 self.vlen = state.vlen
2120 self.expl_lenindef = state.expl_lenindef
2121 self.lenindef = state.lenindef
2122 self.ber_encoded = state.ber_encoded
2125 self._assert_ready()
2126 return int(self._value)
2129 self._assert_ready()
2132 bytes(self._expl or b"") +
2133 str(self._value).encode("ascii"),
2136 def __eq__(self, their):
2137 if isinstance(their, integer_types):
2138 return self._value == their
2139 if not issubclass(their.__class__, Integer):
2142 self._value == their._value and
2143 self.tag == their.tag and
2144 self._expl == their._expl
2147 def __lt__(self, their):
2148 return self._value < their._value
2152 for name, value in iteritems(self.specs):
2153 if value == self._value:
2166 return self.__class__(
2169 (self._bound_min, self._bound_max)
2170 if bounds is None else bounds
2172 impl=self.tag if impl is None else impl,
2173 expl=self._expl if expl is None else expl,
2174 default=self.default if default is None else default,
2175 optional=self.optional if optional is None else optional,
2180 self._assert_ready()
2184 octets = bytearray([0])
2188 octets = bytearray()
2190 octets.append((value & 0xFF) ^ 0xFF)
2192 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2195 octets = bytearray()
2197 octets.append(value & 0xFF)
2199 if octets[-1] & 0x80 > 0:
2202 octets = bytes(octets)
2204 bytes_len = ceil(value.bit_length() / 8) or 1
2207 octets = value.to_bytes(
2212 except OverflowError:
2216 return b"".join((self.tag, len_encode(len(octets)), octets))
2218 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2220 t, _, lv = tag_strip(tlv)
2221 except DecodeError as err:
2222 raise err.__class__(
2224 klass=self.__class__,
2225 decode_path=decode_path,
2230 klass=self.__class__,
2231 decode_path=decode_path,
2237 l, llen, v = len_decode(lv)
2238 except DecodeError as err:
2239 raise err.__class__(
2241 klass=self.__class__,
2242 decode_path=decode_path,
2246 raise NotEnoughData(
2247 "encoded length is longer than data",
2248 klass=self.__class__,
2249 decode_path=decode_path,
2253 raise NotEnoughData(
2255 klass=self.__class__,
2256 decode_path=decode_path,
2259 v, tail = v[:l], v[l:]
2260 first_octet = byte2int(v)
2262 second_octet = byte2int(v[1:])
2264 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2265 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2268 "non normalized integer",
2269 klass=self.__class__,
2270 decode_path=decode_path,
2275 if first_octet & 0x80 > 0:
2276 octets = bytearray()
2277 for octet in bytearray(v):
2278 octets.append(octet ^ 0xFF)
2279 for octet in octets:
2280 value = (value << 8) | octet
2284 for octet in bytearray(v):
2285 value = (value << 8) | octet
2287 value = int.from_bytes(v, byteorder="big", signed=True)
2289 obj = self.__class__(
2291 bounds=(self._bound_min, self._bound_max),
2294 default=self.default,
2295 optional=self.optional,
2297 _decoded=(offset, llen, l),
2299 except BoundsError as err:
2302 klass=self.__class__,
2303 decode_path=decode_path,
2309 return pp_console_row(next(self.pps()))
2311 def pps(self, decode_path=()):
2314 asn1_type_name=self.asn1_type_name,
2315 obj_name=self.__class__.__name__,
2316 decode_path=decode_path,
2317 value=(self.named or str(self._value)) if self.ready else None,
2318 optional=self.optional,
2319 default=self == self.default,
2320 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2321 expl=None if self._expl is None else tag_decode(self._expl),
2326 expl_offset=self.expl_offset if self.expled else None,
2327 expl_tlen=self.expl_tlen if self.expled else None,
2328 expl_llen=self.expl_llen if self.expled else None,
2329 expl_vlen=self.expl_vlen if self.expled else None,
2330 expl_lenindef=self.expl_lenindef,
2333 for pp in self.pps_lenindef(decode_path):
2337 SET01 = frozenset(("0", "1"))
2338 BitStringState = namedtuple("BitStringState", (
2357 class BitString(Obj):
2358 """``BIT STRING`` bit string type
2360 >>> BitString(b"hello world")
2361 BIT STRING 88 bits 68656c6c6f20776f726c64
2364 >>> b == b"hello world"
2369 >>> BitString("'0A3B5F291CD'H")
2370 BIT STRING 44 bits 0a3b5f291cd0
2371 >>> b = BitString("'010110000000'B")
2372 BIT STRING 12 bits 5800
2375 >>> b[0], b[1], b[2], b[3]
2376 (False, True, False, True)
2380 [False, True, False, True, True, False, False, False, False, False, False, False]
2384 class KeyUsage(BitString):
2386 ("digitalSignature", 0),
2387 ("nonRepudiation", 1),
2388 ("keyEncipherment", 2),
2391 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2392 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2394 ['nonRepudiation', 'keyEncipherment']
2396 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2400 Pay attention that BIT STRING can be encoded both in primitive
2401 and constructed forms. Decoder always checks constructed form tag
2402 additionally to specified primitive one. If BER decoding is
2403 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2404 of DER restrictions.
2406 __slots__ = ("tag_constructed", "specs", "defined")
2407 tag_default = tag_encode(3)
2408 asn1_type_name = "BIT STRING"
2421 :param value: set the value. Either binary type, tuple of named
2422 values (if ``schema`` is specified in the class),
2423 string in ``'XXX...'B`` form, or
2424 :py:class:`pyderasn.BitString` object
2425 :param bytes impl: override default tag with ``IMPLICIT`` one
2426 :param bytes expl: override default tag with ``EXPLICIT`` one
2427 :param default: set default value. Type same as in ``value``
2428 :param bool optional: is object ``OPTIONAL`` in sequence
2430 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2431 specs = getattr(self, "schema", {}) if _specs is None else _specs
2432 self.specs = specs if isinstance(specs, dict) else dict(specs)
2433 self._value = None if value is None else self._value_sanitize(value)
2434 if default is not None:
2435 default = self._value_sanitize(default)
2436 self.default = self.__class__(
2442 self._value = default
2444 tag_klass, _, tag_num = tag_decode(self.tag)
2445 self.tag_constructed = tag_encode(
2447 form=TagFormConstructed,
2451 def _bits2octets(self, bits):
2452 if len(self.specs) > 0:
2453 bits = bits.rstrip("0")
2455 bits += "0" * ((8 - (bit_len % 8)) % 8)
2456 octets = bytearray(len(bits) // 8)
2457 for i in six_xrange(len(octets)):
2458 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2459 return bit_len, bytes(octets)
2461 def _value_sanitize(self, value):
2462 if isinstance(value, (string_types, binary_type)):
2464 isinstance(value, string_types) and
2465 value.startswith("'")
2467 if value.endswith("'B"):
2469 if not frozenset(value) <= SET01:
2470 raise ValueError("B's coding contains unacceptable chars")
2471 return self._bits2octets(value)
2472 if value.endswith("'H"):
2476 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2478 if isinstance(value, binary_type):
2479 return (len(value) * 8, value)
2480 raise InvalidValueType((self.__class__, string_types, binary_type))
2481 if isinstance(value, tuple):
2484 isinstance(value[0], integer_types) and
2485 isinstance(value[1], binary_type)
2490 bit = self.specs.get(name)
2492 raise ObjUnknown("BitString value: %s" % name)
2495 return self._bits2octets("")
2496 bits = frozenset(bits)
2497 return self._bits2octets("".join(
2498 ("1" if bit in bits else "0")
2499 for bit in six_xrange(max(bits) + 1)
2501 if issubclass(value.__class__, BitString):
2503 raise InvalidValueType((self.__class__, binary_type, string_types))
2507 return self._value is not None
2509 def __getstate__(self):
2510 return BitStringState(
2524 self.tag_constructed,
2528 def __setstate__(self, state):
2529 super(BitString, self).__setstate__(state)
2530 self.specs = state.specs
2531 self._value = state.value
2532 self.tag = state.tag
2533 self._expl = state.expl
2534 self.default = state.default
2535 self.optional = state.optional
2536 self.offset = state.offset
2537 self.llen = state.llen
2538 self.vlen = state.vlen
2539 self.expl_lenindef = state.expl_lenindef
2540 self.lenindef = state.lenindef
2541 self.ber_encoded = state.ber_encoded
2542 self.tag_constructed = state.tag_constructed
2543 self.defined = state.defined
2546 self._assert_ready()
2547 for i in six_xrange(self._value[0]):
2552 self._assert_ready()
2553 return self._value[0]
2555 def __bytes__(self):
2556 self._assert_ready()
2557 return self._value[1]
2559 def __eq__(self, their):
2560 if isinstance(their, bytes):
2561 return self._value[1] == their
2562 if not issubclass(their.__class__, BitString):
2565 self._value == their._value and
2566 self.tag == their.tag and
2567 self._expl == their._expl
2572 return [name for name, bit in iteritems(self.specs) if self[bit]]
2582 return self.__class__(
2584 impl=self.tag if impl is None else impl,
2585 expl=self._expl if expl is None else expl,
2586 default=self.default if default is None else default,
2587 optional=self.optional if optional is None else optional,
2591 def __getitem__(self, key):
2592 if isinstance(key, int):
2593 bit_len, octets = self._value
2597 byte2int(memoryview(octets)[key // 8:]) >>
2600 if isinstance(key, string_types):
2601 value = self.specs.get(key)
2603 raise ObjUnknown("BitString value: %s" % key)
2605 raise InvalidValueType((int, str))
2608 self._assert_ready()
2609 bit_len, octets = self._value
2612 len_encode(len(octets) + 1),
2613 int2byte((8 - bit_len % 8) % 8),
2617 def _decode_chunk(self, lv, offset, decode_path):
2619 l, llen, v = len_decode(lv)
2620 except DecodeError as err:
2621 raise err.__class__(
2623 klass=self.__class__,
2624 decode_path=decode_path,
2628 raise NotEnoughData(
2629 "encoded length is longer than data",
2630 klass=self.__class__,
2631 decode_path=decode_path,
2635 raise NotEnoughData(
2637 klass=self.__class__,
2638 decode_path=decode_path,
2641 pad_size = byte2int(v)
2642 if l == 1 and pad_size != 0:
2644 "invalid empty value",
2645 klass=self.__class__,
2646 decode_path=decode_path,
2652 klass=self.__class__,
2653 decode_path=decode_path,
2656 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2659 klass=self.__class__,
2660 decode_path=decode_path,
2663 v, tail = v[:l], v[l:]
2664 obj = self.__class__(
2665 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2668 default=self.default,
2669 optional=self.optional,
2671 _decoded=(offset, llen, l),
2675 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2677 t, tlen, lv = tag_strip(tlv)
2678 except DecodeError as err:
2679 raise err.__class__(
2681 klass=self.__class__,
2682 decode_path=decode_path,
2686 if tag_only: # pragma: no cover
2688 return self._decode_chunk(lv, offset, decode_path)
2689 if t == self.tag_constructed:
2690 if not ctx.get("bered", False):
2692 "unallowed BER constructed encoding",
2693 klass=self.__class__,
2694 decode_path=decode_path,
2697 if tag_only: # pragma: no cover
2701 l, llen, v = len_decode(lv)
2702 except LenIndefForm:
2703 llen, l, v = 1, 0, lv[1:]
2705 except DecodeError as err:
2706 raise err.__class__(
2708 klass=self.__class__,
2709 decode_path=decode_path,
2713 raise NotEnoughData(
2714 "encoded length is longer than data",
2715 klass=self.__class__,
2716 decode_path=decode_path,
2719 if not lenindef and l == 0:
2720 raise NotEnoughData(
2722 klass=self.__class__,
2723 decode_path=decode_path,
2727 sub_offset = offset + tlen + llen
2731 if v[:EOC_LEN].tobytes() == EOC:
2738 "chunk out of bounds",
2739 klass=self.__class__,
2740 decode_path=decode_path + (str(len(chunks) - 1),),
2741 offset=chunks[-1].offset,
2743 sub_decode_path = decode_path + (str(len(chunks)),)
2745 chunk, v_tail = BitString().decode(
2748 decode_path=sub_decode_path,
2751 _ctx_immutable=False,
2755 "expected BitString encoded chunk",
2756 klass=self.__class__,
2757 decode_path=sub_decode_path,
2760 chunks.append(chunk)
2761 sub_offset += chunk.tlvlen
2762 vlen += chunk.tlvlen
2764 if len(chunks) == 0:
2767 klass=self.__class__,
2768 decode_path=decode_path,
2773 for chunk_i, chunk in enumerate(chunks[:-1]):
2774 if chunk.bit_len % 8 != 0:
2776 "BitString chunk is not multiple of 8 bits",
2777 klass=self.__class__,
2778 decode_path=decode_path + (str(chunk_i),),
2779 offset=chunk.offset,
2781 values.append(bytes(chunk))
2782 bit_len += chunk.bit_len
2783 chunk_last = chunks[-1]
2784 values.append(bytes(chunk_last))
2785 bit_len += chunk_last.bit_len
2786 obj = self.__class__(
2787 value=(bit_len, b"".join(values)),
2790 default=self.default,
2791 optional=self.optional,
2793 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2795 obj.lenindef = lenindef
2796 obj.ber_encoded = True
2797 return obj, (v[EOC_LEN:] if lenindef else v)
2799 klass=self.__class__,
2800 decode_path=decode_path,
2805 return pp_console_row(next(self.pps()))
2807 def pps(self, decode_path=()):
2811 bit_len, blob = self._value
2812 value = "%d bits" % bit_len
2813 if len(self.specs) > 0:
2814 blob = tuple(self.named)
2817 asn1_type_name=self.asn1_type_name,
2818 obj_name=self.__class__.__name__,
2819 decode_path=decode_path,
2822 optional=self.optional,
2823 default=self == self.default,
2824 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2825 expl=None if self._expl is None else tag_decode(self._expl),
2830 expl_offset=self.expl_offset if self.expled else None,
2831 expl_tlen=self.expl_tlen if self.expled else None,
2832 expl_llen=self.expl_llen if self.expled else None,
2833 expl_vlen=self.expl_vlen if self.expled else None,
2834 expl_lenindef=self.expl_lenindef,
2835 lenindef=self.lenindef,
2836 ber_encoded=self.ber_encoded,
2839 defined_by, defined = self.defined or (None, None)
2840 if defined_by is not None:
2842 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2844 for pp in self.pps_lenindef(decode_path):
2848 OctetStringState = namedtuple("OctetStringState", (
2868 class OctetString(Obj):
2869 """``OCTET STRING`` binary string type
2871 >>> s = OctetString(b"hello world")
2872 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2873 >>> s == OctetString(b"hello world")
2878 >>> OctetString(b"hello", bounds=(4, 4))
2879 Traceback (most recent call last):
2880 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2881 >>> OctetString(b"hell", bounds=(4, 4))
2882 OCTET STRING 4 bytes 68656c6c
2886 Pay attention that OCTET STRING can be encoded both in primitive
2887 and constructed forms. Decoder always checks constructed form tag
2888 additionally to specified primitive one. If BER decoding is
2889 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2890 of DER restrictions.
2892 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2893 tag_default = tag_encode(4)
2894 asn1_type_name = "OCTET STRING"
2907 :param value: set the value. Either binary type, or
2908 :py:class:`pyderasn.OctetString` object
2909 :param bounds: set ``(MIN, MAX)`` value size constraint.
2910 (-inf, +inf) by default
2911 :param bytes impl: override default tag with ``IMPLICIT`` one
2912 :param bytes expl: override default tag with ``EXPLICIT`` one
2913 :param default: set default value. Type same as in ``value``
2914 :param bool optional: is object ``OPTIONAL`` in sequence
2916 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2918 self._bound_min, self._bound_max = getattr(
2922 ) if bounds is None else bounds
2923 if value is not None:
2924 self._value = self._value_sanitize(value)
2925 if default is not None:
2926 default = self._value_sanitize(default)
2927 self.default = self.__class__(
2932 if self._value is None:
2933 self._value = default
2935 tag_klass, _, tag_num = tag_decode(self.tag)
2936 self.tag_constructed = tag_encode(
2938 form=TagFormConstructed,
2942 def _value_sanitize(self, value):
2943 if isinstance(value, binary_type):
2945 elif issubclass(value.__class__, OctetString):
2946 value = value._value
2948 raise InvalidValueType((self.__class__, bytes))
2949 if not self._bound_min <= len(value) <= self._bound_max:
2950 raise BoundsError(self._bound_min, len(value), self._bound_max)
2955 return self._value is not None
2957 def __getstate__(self):
2958 return OctetStringState(
2973 self.tag_constructed,
2977 def __setstate__(self, state):
2978 super(OctetString, self).__setstate__(state)
2979 self._value = state.value
2980 self._bound_min = state.bound_min
2981 self._bound_max = state.bound_max
2982 self.tag = state.tag
2983 self._expl = state.expl
2984 self.default = state.default
2985 self.optional = state.optional
2986 self.offset = state.offset
2987 self.llen = state.llen
2988 self.vlen = state.vlen
2989 self.expl_lenindef = state.expl_lenindef
2990 self.lenindef = state.lenindef
2991 self.ber_encoded = state.ber_encoded
2992 self.tag_constructed = state.tag_constructed
2993 self.defined = state.defined
2995 def __bytes__(self):
2996 self._assert_ready()
2999 def __eq__(self, their):
3000 if isinstance(their, binary_type):
3001 return self._value == their
3002 if not issubclass(their.__class__, OctetString):
3005 self._value == their._value and
3006 self.tag == their.tag and
3007 self._expl == their._expl
3010 def __lt__(self, their):
3011 return self._value < their._value
3022 return self.__class__(
3025 (self._bound_min, self._bound_max)
3026 if bounds is None else bounds
3028 impl=self.tag if impl is None else impl,
3029 expl=self._expl if expl is None else expl,
3030 default=self.default if default is None else default,
3031 optional=self.optional if optional is None else optional,
3035 self._assert_ready()
3038 len_encode(len(self._value)),
3042 def _decode_chunk(self, lv, offset, decode_path):
3044 l, llen, v = len_decode(lv)
3045 except DecodeError as err:
3046 raise err.__class__(
3048 klass=self.__class__,
3049 decode_path=decode_path,
3053 raise NotEnoughData(
3054 "encoded length is longer than data",
3055 klass=self.__class__,
3056 decode_path=decode_path,
3059 v, tail = v[:l], v[l:]
3061 obj = self.__class__(
3063 bounds=(self._bound_min, self._bound_max),
3066 default=self.default,
3067 optional=self.optional,
3068 _decoded=(offset, llen, l),
3070 except DecodeError as err:
3073 klass=self.__class__,
3074 decode_path=decode_path,
3077 except BoundsError as err:
3080 klass=self.__class__,
3081 decode_path=decode_path,
3086 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3088 t, tlen, lv = tag_strip(tlv)
3089 except DecodeError as err:
3090 raise err.__class__(
3092 klass=self.__class__,
3093 decode_path=decode_path,
3099 return self._decode_chunk(lv, offset, decode_path)
3100 if t == self.tag_constructed:
3101 if not ctx.get("bered", False):
3103 "unallowed BER constructed encoding",
3104 klass=self.__class__,
3105 decode_path=decode_path,
3112 l, llen, v = len_decode(lv)
3113 except LenIndefForm:
3114 llen, l, v = 1, 0, lv[1:]
3116 except DecodeError as err:
3117 raise err.__class__(
3119 klass=self.__class__,
3120 decode_path=decode_path,
3124 raise NotEnoughData(
3125 "encoded length is longer than data",
3126 klass=self.__class__,
3127 decode_path=decode_path,
3131 sub_offset = offset + tlen + llen
3135 if v[:EOC_LEN].tobytes() == EOC:
3142 "chunk out of bounds",
3143 klass=self.__class__,
3144 decode_path=decode_path + (str(len(chunks) - 1),),
3145 offset=chunks[-1].offset,
3147 sub_decode_path = decode_path + (str(len(chunks)),)
3149 chunk, v_tail = OctetString().decode(
3152 decode_path=sub_decode_path,
3155 _ctx_immutable=False,
3159 "expected OctetString encoded chunk",
3160 klass=self.__class__,
3161 decode_path=sub_decode_path,
3164 chunks.append(chunk)
3165 sub_offset += chunk.tlvlen
3166 vlen += chunk.tlvlen
3169 obj = self.__class__(
3170 value=b"".join(bytes(chunk) for chunk in chunks),
3171 bounds=(self._bound_min, self._bound_max),
3174 default=self.default,
3175 optional=self.optional,
3176 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3178 except DecodeError as err:
3181 klass=self.__class__,
3182 decode_path=decode_path,
3185 except BoundsError as err:
3188 klass=self.__class__,
3189 decode_path=decode_path,
3192 obj.lenindef = lenindef
3193 obj.ber_encoded = True
3194 return obj, (v[EOC_LEN:] if lenindef else v)
3196 klass=self.__class__,
3197 decode_path=decode_path,
3202 return pp_console_row(next(self.pps()))
3204 def pps(self, decode_path=()):
3207 asn1_type_name=self.asn1_type_name,
3208 obj_name=self.__class__.__name__,
3209 decode_path=decode_path,
3210 value=("%d bytes" % len(self._value)) if self.ready else None,
3211 blob=self._value if self.ready else None,
3212 optional=self.optional,
3213 default=self == self.default,
3214 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3215 expl=None if self._expl is None else tag_decode(self._expl),
3220 expl_offset=self.expl_offset if self.expled else None,
3221 expl_tlen=self.expl_tlen if self.expled else None,
3222 expl_llen=self.expl_llen if self.expled else None,
3223 expl_vlen=self.expl_vlen if self.expled else None,
3224 expl_lenindef=self.expl_lenindef,
3225 lenindef=self.lenindef,
3226 ber_encoded=self.ber_encoded,
3229 defined_by, defined = self.defined or (None, None)
3230 if defined_by is not None:
3232 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3234 for pp in self.pps_lenindef(decode_path):
3238 NullState = namedtuple("NullState", (
3254 """``NULL`` null object
3262 tag_default = tag_encode(5)
3263 asn1_type_name = "NULL"
3267 value=None, # unused, but Sequence passes it
3274 :param bytes impl: override default tag with ``IMPLICIT`` one
3275 :param bytes expl: override default tag with ``EXPLICIT`` one
3276 :param bool optional: is object ``OPTIONAL`` in sequence
3278 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3285 def __getstate__(self):
3300 def __setstate__(self, state):
3301 super(Null, self).__setstate__(state)
3302 self.tag = state.tag
3303 self._expl = state.expl
3304 self.default = state.default
3305 self.optional = state.optional
3306 self.offset = state.offset
3307 self.llen = state.llen
3308 self.vlen = state.vlen
3309 self.expl_lenindef = state.expl_lenindef
3310 self.lenindef = state.lenindef
3311 self.ber_encoded = state.ber_encoded
3313 def __eq__(self, their):
3314 if not issubclass(their.__class__, Null):
3317 self.tag == their.tag and
3318 self._expl == their._expl
3328 return self.__class__(
3329 impl=self.tag if impl is None else impl,
3330 expl=self._expl if expl is None else expl,
3331 optional=self.optional if optional is None else optional,
3335 return self.tag + len_encode(0)
3337 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3339 t, _, lv = tag_strip(tlv)
3340 except DecodeError as err:
3341 raise err.__class__(
3343 klass=self.__class__,
3344 decode_path=decode_path,
3349 klass=self.__class__,
3350 decode_path=decode_path,
3353 if tag_only: # pragma: no cover
3356 l, _, v = len_decode(lv)
3357 except DecodeError as err:
3358 raise err.__class__(
3360 klass=self.__class__,
3361 decode_path=decode_path,
3365 raise InvalidLength(
3366 "Null must have zero length",
3367 klass=self.__class__,
3368 decode_path=decode_path,
3371 obj = self.__class__(
3374 optional=self.optional,
3375 _decoded=(offset, 1, 0),
3380 return pp_console_row(next(self.pps()))
3382 def pps(self, decode_path=()):
3385 asn1_type_name=self.asn1_type_name,
3386 obj_name=self.__class__.__name__,
3387 decode_path=decode_path,
3388 optional=self.optional,
3389 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3390 expl=None if self._expl is None else tag_decode(self._expl),
3395 expl_offset=self.expl_offset if self.expled else None,
3396 expl_tlen=self.expl_tlen if self.expled else None,
3397 expl_llen=self.expl_llen if self.expled else None,
3398 expl_vlen=self.expl_vlen if self.expled else None,
3399 expl_lenindef=self.expl_lenindef,
3402 for pp in self.pps_lenindef(decode_path):
3406 ObjectIdentifierState = namedtuple("ObjectIdentifierState", (
3423 class ObjectIdentifier(Obj):
3424 """``OBJECT IDENTIFIER`` OID type
3426 >>> oid = ObjectIdentifier((1, 2, 3))
3427 OBJECT IDENTIFIER 1.2.3
3428 >>> oid == ObjectIdentifier("1.2.3")
3434 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3435 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3437 >>> str(ObjectIdentifier((3, 1)))
3438 Traceback (most recent call last):
3439 pyderasn.InvalidOID: unacceptable first arc value
3441 __slots__ = ("defines",)
3442 tag_default = tag_encode(6)
3443 asn1_type_name = "OBJECT IDENTIFIER"
3456 :param value: set the value. Either tuples of integers,
3457 string of "."-concatenated integers, or
3458 :py:class:`pyderasn.ObjectIdentifier` object
3459 :param defines: sequence of tuples. Each tuple has two elements.
3460 First one is relative to current one decode
3461 path, aiming to the field defined by that OID.
3462 Read about relative path in
3463 :py:func:`pyderasn.abs_decode_path`. Second
3464 tuple element is ``{OID: pyderasn.Obj()}``
3465 dictionary, mapping between current OID value
3466 and structure applied to defined field.
3467 :ref:`Read about DEFINED BY <definedby>`
3468 :param bytes impl: override default tag with ``IMPLICIT`` one
3469 :param bytes expl: override default tag with ``EXPLICIT`` one
3470 :param default: set default value. Type same as in ``value``
3471 :param bool optional: is object ``OPTIONAL`` in sequence
3473 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3475 if value is not None:
3476 self._value = self._value_sanitize(value)
3477 if default is not None:
3478 default = self._value_sanitize(default)
3479 self.default = self.__class__(
3484 if self._value is None:
3485 self._value = default
3486 self.defines = defines
3488 def __add__(self, their):
3489 if isinstance(their, self.__class__):
3490 return self.__class__(self._value + their._value)
3491 if isinstance(their, tuple):
3492 return self.__class__(self._value + their)
3493 raise InvalidValueType((self.__class__, tuple))
3495 def _value_sanitize(self, value):
3496 if issubclass(value.__class__, ObjectIdentifier):
3498 if isinstance(value, string_types):
3500 value = tuple(int(arc) for arc in value.split("."))
3502 raise InvalidOID("unacceptable arcs values")
3503 if isinstance(value, tuple):
3505 raise InvalidOID("less than 2 arcs")
3506 first_arc = value[0]
3507 if first_arc in (0, 1):
3508 if not (0 <= value[1] <= 39):
3509 raise InvalidOID("second arc is too wide")
3510 elif first_arc == 2:
3513 raise InvalidOID("unacceptable first arc value")
3515 raise InvalidValueType((self.__class__, str, tuple))
3519 return self._value is not None
3521 def __getstate__(self):
3522 return ObjectIdentifierState(
3538 def __setstate__(self, state):
3539 super(ObjectIdentifier, self).__setstate__(state)
3540 self._value = state.value
3541 self.tag = state.tag
3542 self._expl = state.expl
3543 self.default = state.default
3544 self.optional = state.optional
3545 self.offset = state.offset
3546 self.llen = state.llen
3547 self.vlen = state.vlen
3548 self.expl_lenindef = state.expl_lenindef
3549 self.lenindef = state.lenindef
3550 self.ber_encoded = state.ber_encoded
3551 self.defines = state.defines
3554 self._assert_ready()
3555 return iter(self._value)
3558 return ".".join(str(arc) for arc in self._value or ())
3561 self._assert_ready()
3564 bytes(self._expl or b"") +
3565 str(self._value).encode("ascii"),
3568 def __eq__(self, their):
3569 if isinstance(their, tuple):
3570 return self._value == their
3571 if not issubclass(their.__class__, ObjectIdentifier):
3574 self.tag == their.tag and
3575 self._expl == their._expl and
3576 self._value == their._value
3579 def __lt__(self, their):
3580 return self._value < their._value
3591 return self.__class__(
3593 defines=self.defines if defines is None else defines,
3594 impl=self.tag if impl is None else impl,
3595 expl=self._expl if expl is None else expl,
3596 default=self.default if default is None else default,
3597 optional=self.optional if optional is None else optional,
3601 self._assert_ready()
3603 first_value = value[1]
3604 first_arc = value[0]
3607 elif first_arc == 1:
3609 elif first_arc == 2:
3611 else: # pragma: no cover
3612 raise RuntimeError("invalid arc is stored")
3613 octets = [zero_ended_encode(first_value)]
3614 for arc in value[2:]:
3615 octets.append(zero_ended_encode(arc))
3616 v = b"".join(octets)
3617 return b"".join((self.tag, len_encode(len(v)), v))
3619 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3621 t, _, lv = tag_strip(tlv)
3622 except DecodeError as err:
3623 raise err.__class__(
3625 klass=self.__class__,
3626 decode_path=decode_path,
3631 klass=self.__class__,
3632 decode_path=decode_path,
3635 if tag_only: # pragma: no cover
3638 l, llen, v = len_decode(lv)
3639 except DecodeError as err:
3640 raise err.__class__(
3642 klass=self.__class__,
3643 decode_path=decode_path,
3647 raise NotEnoughData(
3648 "encoded length is longer than data",
3649 klass=self.__class__,
3650 decode_path=decode_path,
3654 raise NotEnoughData(
3656 klass=self.__class__,
3657 decode_path=decode_path,
3660 v, tail = v[:l], v[l:]
3667 octet = indexbytes(v, i)
3668 if i == 0 and octet == 0x80:
3669 if ctx.get("bered", False):
3672 raise DecodeError("non normalized arc encoding")
3673 arc = (arc << 7) | (octet & 0x7F)
3674 if octet & 0x80 == 0:
3682 klass=self.__class__,
3683 decode_path=decode_path,
3687 second_arc = arcs[0]
3688 if 0 <= second_arc <= 39:
3690 elif 40 <= second_arc <= 79:
3696 obj = self.__class__(
3697 value=tuple([first_arc, second_arc] + arcs[1:]),
3700 default=self.default,
3701 optional=self.optional,
3702 _decoded=(offset, llen, l),
3705 obj.ber_encoded = True
3709 return pp_console_row(next(self.pps()))
3711 def pps(self, decode_path=()):
3714 asn1_type_name=self.asn1_type_name,
3715 obj_name=self.__class__.__name__,
3716 decode_path=decode_path,
3717 value=str(self) if self.ready else None,
3718 optional=self.optional,
3719 default=self == self.default,
3720 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3721 expl=None if self._expl is None else tag_decode(self._expl),
3726 expl_offset=self.expl_offset if self.expled else None,
3727 expl_tlen=self.expl_tlen if self.expled else None,
3728 expl_llen=self.expl_llen if self.expled else None,
3729 expl_vlen=self.expl_vlen if self.expled else None,
3730 expl_lenindef=self.expl_lenindef,
3731 ber_encoded=self.ber_encoded,
3734 for pp in self.pps_lenindef(decode_path):
3738 class Enumerated(Integer):
3739 """``ENUMERATED`` integer type
3741 This type is identical to :py:class:`pyderasn.Integer`, but requires
3742 schema to be specified and does not accept values missing from it.
3745 tag_default = tag_encode(10)
3746 asn1_type_name = "ENUMERATED"
3757 bounds=None, # dummy argument, workability for Integer.decode
3759 super(Enumerated, self).__init__(
3760 value, bounds, impl, expl, default, optional, _specs, _decoded,
3762 if len(self.specs) == 0:
3763 raise ValueError("schema must be specified")
3765 def _value_sanitize(self, value):
3766 if isinstance(value, self.__class__):
3767 value = value._value
3768 elif isinstance(value, integer_types):
3769 for _value in itervalues(self.specs):
3774 "unknown integer value: %s" % value,
3775 klass=self.__class__,
3777 elif isinstance(value, string_types):
3778 value = self.specs.get(value)
3780 raise ObjUnknown("integer value: %s" % value)
3782 raise InvalidValueType((self.__class__, int, str))
3794 return self.__class__(
3796 impl=self.tag if impl is None else impl,
3797 expl=self._expl if expl is None else expl,
3798 default=self.default if default is None else default,
3799 optional=self.optional if optional is None else optional,
3804 def escape_control_unicode(c):
3805 if unicat(c).startswith("C"):
3806 c = repr(c).lstrip("u").strip("'")
3810 class CommonString(OctetString):
3811 """Common class for all strings
3813 Everything resembles :py:class:`pyderasn.OctetString`, except
3814 ability to deal with unicode text strings.
3816 >>> hexenc("привет мир".encode("utf-8"))
3817 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3818 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3820 >>> s = UTF8String("привет мир")
3821 UTF8String UTF8String привет мир
3823 'привет мир'
3824 >>> hexenc(bytes(s))
3825 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3827 >>> PrintableString("привет мир")
3828 Traceback (most recent call last):
3829 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3831 >>> BMPString("ада", bounds=(2, 2))
3832 Traceback (most recent call last):
3833 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3834 >>> s = BMPString("ад", bounds=(2, 2))
3837 >>> hexenc(bytes(s))
3845 * - :py:class:`pyderasn.UTF8String`
3847 * - :py:class:`pyderasn.NumericString`
3849 * - :py:class:`pyderasn.PrintableString`
3851 * - :py:class:`pyderasn.TeletexString`
3853 * - :py:class:`pyderasn.T61String`
3855 * - :py:class:`pyderasn.VideotexString`
3857 * - :py:class:`pyderasn.IA5String`
3859 * - :py:class:`pyderasn.GraphicString`
3861 * - :py:class:`pyderasn.VisibleString`
3863 * - :py:class:`pyderasn.ISO646String`
3865 * - :py:class:`pyderasn.GeneralString`
3867 * - :py:class:`pyderasn.UniversalString`
3869 * - :py:class:`pyderasn.BMPString`
3874 def _value_sanitize(self, value):
3876 value_decoded = None
3877 if isinstance(value, self.__class__):
3878 value_raw = value._value
3879 elif isinstance(value, text_type):
3880 value_decoded = value
3881 elif isinstance(value, binary_type):
3884 raise InvalidValueType((self.__class__, text_type, binary_type))
3887 value_decoded.encode(self.encoding)
3888 if value_raw is None else value_raw
3891 value_raw.decode(self.encoding)
3892 if value_decoded is None else value_decoded
3894 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3895 raise DecodeError(str(err))
3896 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3904 def __eq__(self, their):
3905 if isinstance(their, binary_type):
3906 return self._value == their
3907 if isinstance(their, text_type):
3908 return self._value == their.encode(self.encoding)
3909 if not isinstance(their, self.__class__):
3912 self._value == their._value and
3913 self.tag == their.tag and
3914 self._expl == their._expl
3917 def __unicode__(self):
3919 return self._value.decode(self.encoding)
3920 return text_type(self._value)
3923 return pp_console_row(next(self.pps(no_unicode=PY2)))
3925 def pps(self, decode_path=(), no_unicode=False):
3929 hexenc(bytes(self)) if no_unicode else
3930 "".join(escape_control_unicode(c) for c in self.__unicode__())
3934 asn1_type_name=self.asn1_type_name,
3935 obj_name=self.__class__.__name__,
3936 decode_path=decode_path,
3938 optional=self.optional,
3939 default=self == self.default,
3940 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3941 expl=None if self._expl is None else tag_decode(self._expl),
3946 expl_offset=self.expl_offset if self.expled else None,
3947 expl_tlen=self.expl_tlen if self.expled else None,
3948 expl_llen=self.expl_llen if self.expled else None,
3949 expl_vlen=self.expl_vlen if self.expled else None,
3950 expl_lenindef=self.expl_lenindef,
3951 ber_encoded=self.ber_encoded,
3954 for pp in self.pps_lenindef(decode_path):
3958 class UTF8String(CommonString):
3960 tag_default = tag_encode(12)
3962 asn1_type_name = "UTF8String"
3965 class AllowableCharsMixin(object):
3967 def allowable_chars(self):
3969 return self._allowable_chars
3970 return frozenset(six_unichr(c) for c in self._allowable_chars)
3973 class NumericString(AllowableCharsMixin, CommonString):
3976 Its value is properly sanitized: only ASCII digits with spaces can
3979 >>> NumericString().allowable_chars
3980 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3983 tag_default = tag_encode(18)
3985 asn1_type_name = "NumericString"
3986 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3988 def _value_sanitize(self, value):
3989 value = super(NumericString, self)._value_sanitize(value)
3990 if not frozenset(value) <= self._allowable_chars:
3991 raise DecodeError("non-numeric value")
3995 PrintableStringState = namedtuple(
3996 "PrintableStringState",
3997 OctetStringState._fields + ("allowable_chars",),
4001 class PrintableString(AllowableCharsMixin, CommonString):
4004 Its value is properly sanitized: see X.680 41.4 table 10.
4006 >>> PrintableString().allowable_chars
4007 frozenset([' ', "'", ..., 'z'])
4008 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4009 PrintableString PrintableString foo*bar
4010 >>> obj.allow_asterisk, obj.allow_ampersand
4014 tag_default = tag_encode(19)
4016 asn1_type_name = "PrintableString"
4017 _allowable_chars = frozenset(
4018 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4020 _asterisk = frozenset("*".encode("ascii"))
4021 _ampersand = frozenset("&".encode("ascii"))
4032 allow_asterisk=False,
4033 allow_ampersand=False,
4036 :param allow_asterisk: allow asterisk character
4037 :param allow_ampersand: allow ampersand character
4040 self._allowable_chars |= self._asterisk
4042 self._allowable_chars |= self._ampersand
4043 super(PrintableString, self).__init__(
4044 value, bounds, impl, expl, default, optional, _decoded,
4048 def allow_asterisk(self):
4049 """Is asterisk character allowed?
4051 return self._asterisk <= self._allowable_chars
4054 def allow_ampersand(self):
4055 """Is ampersand character allowed?
4057 return self._ampersand <= self._allowable_chars
4059 def _value_sanitize(self, value):
4060 value = super(PrintableString, self)._value_sanitize(value)
4061 if not frozenset(value) <= self._allowable_chars:
4062 raise DecodeError("non-printable value")
4065 def __getstate__(self):
4066 return PrintableStringState(
4067 *super(PrintableString, self).__getstate__(),
4068 **{"allowable_chars": self._allowable_chars}
4071 def __setstate__(self, state):
4072 super(PrintableString, self).__setstate__(state)
4073 self._allowable_chars = state.allowable_chars
4084 return self.__class__(
4087 (self._bound_min, self._bound_max)
4088 if bounds is None else bounds
4090 impl=self.tag if impl is None else impl,
4091 expl=self._expl if expl is None else expl,
4092 default=self.default if default is None else default,
4093 optional=self.optional if optional is None else optional,
4094 allow_asterisk=self.allow_asterisk,
4095 allow_ampersand=self.allow_ampersand,
4099 class TeletexString(CommonString):
4101 tag_default = tag_encode(20)
4103 asn1_type_name = "TeletexString"
4106 class T61String(TeletexString):
4108 asn1_type_name = "T61String"
4111 class VideotexString(CommonString):
4113 tag_default = tag_encode(21)
4114 encoding = "iso-8859-1"
4115 asn1_type_name = "VideotexString"
4118 class IA5String(CommonString):
4120 tag_default = tag_encode(22)
4122 asn1_type_name = "IA5"
4125 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4126 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4127 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4130 class UTCTime(CommonString):
4131 """``UTCTime`` datetime type
4133 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4134 UTCTime UTCTime 2017-09-30T22:07:50
4140 datetime.datetime(2017, 9, 30, 22, 7, 50)
4141 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4142 datetime.datetime(1957, 9, 30, 22, 7, 50)
4146 BER encoding is unsupported.
4149 tag_default = tag_encode(23)
4151 asn1_type_name = "UTCTime"
4161 bounds=None, # dummy argument, workability for OctetString.decode
4164 :param value: set the value. Either datetime type, or
4165 :py:class:`pyderasn.UTCTime` object
4166 :param bytes impl: override default tag with ``IMPLICIT`` one
4167 :param bytes expl: override default tag with ``EXPLICIT`` one
4168 :param default: set default value. Type same as in ``value``
4169 :param bool optional: is object ``OPTIONAL`` in sequence
4171 super(UTCTime, self).__init__(
4172 None, None, impl, expl, default, optional, _decoded,
4175 if value is not None:
4176 self._value = self._value_sanitize(value)
4177 if default is not None:
4178 default = self._value_sanitize(default)
4179 self.default = self.__class__(
4184 if self._value is None:
4185 self._value = default
4187 def _strptime(self, value):
4188 # datetime.strptime's format: %y%m%d%H%M%SZ
4189 if len(value) != LEN_YYMMDDHHMMSSZ:
4190 raise ValueError("invalid UTCTime length")
4191 if value[-1] != "Z":
4192 raise ValueError("non UTC timezone")
4194 2000 + int(value[:2]), # %y
4195 int(value[2:4]), # %m
4196 int(value[4:6]), # %d
4197 int(value[6:8]), # %H
4198 int(value[8:10]), # %M
4199 int(value[10:12]), # %S
4202 def _value_sanitize(self, value):
4203 if isinstance(value, binary_type):
4205 value_decoded = value.decode("ascii")
4206 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4207 raise DecodeError("invalid UTCTime encoding: %r" % err)
4209 self._strptime(value_decoded)
4210 except (TypeError, ValueError) as err:
4211 raise DecodeError("invalid UTCTime format: %r" % err)
4213 if isinstance(value, self.__class__):
4215 if isinstance(value, datetime):
4216 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4217 raise InvalidValueType((self.__class__, datetime))
4219 def __eq__(self, their):
4220 if isinstance(their, binary_type):
4221 return self._value == their
4222 if isinstance(their, datetime):
4223 return self.todatetime() == their
4224 if not isinstance(their, self.__class__):
4227 self._value == their._value and
4228 self.tag == their.tag and
4229 self._expl == their._expl
4232 def todatetime(self):
4233 """Convert to datetime
4237 Pay attention that UTCTime can not hold full year, so all years
4238 having < 50 years are treated as 20xx, 19xx otherwise, according
4239 to X.509 recomendation.
4241 value = self._strptime(self._value.decode("ascii"))
4242 year = value.year % 100
4244 year=(2000 + year) if year < 50 else (1900 + year),
4248 minute=value.minute,
4249 second=value.second,
4253 return pp_console_row(next(self.pps()))
4255 def pps(self, decode_path=()):
4258 asn1_type_name=self.asn1_type_name,
4259 obj_name=self.__class__.__name__,
4260 decode_path=decode_path,
4261 value=self.todatetime().isoformat() if self.ready else None,
4262 optional=self.optional,
4263 default=self == self.default,
4264 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4265 expl=None if self._expl is None else tag_decode(self._expl),
4270 expl_offset=self.expl_offset if self.expled else None,
4271 expl_tlen=self.expl_tlen if self.expled else None,
4272 expl_llen=self.expl_llen if self.expled else None,
4273 expl_vlen=self.expl_vlen if self.expled else None,
4274 expl_lenindef=self.expl_lenindef,
4275 ber_encoded=self.ber_encoded,
4278 for pp in self.pps_lenindef(decode_path):
4282 class GeneralizedTime(UTCTime):
4283 """``GeneralizedTime`` datetime type
4285 This type is similar to :py:class:`pyderasn.UTCTime`.
4287 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4288 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4290 '20170930220750.000123Z'
4291 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4292 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4296 BER encoding is unsupported.
4300 Only microsecond fractions are supported.
4301 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4302 higher precision values.
4306 Zero year is unsupported.
4309 tag_default = tag_encode(24)
4310 asn1_type_name = "GeneralizedTime"
4312 def _strptime(self, value):
4314 if l == LEN_YYYYMMDDHHMMSSZ:
4315 # datetime.strptime's format: %Y%m%d%H%M%SZ
4316 if value[-1] != "Z":
4317 raise ValueError("non UTC timezone")
4319 int(value[:4]), # %Y
4320 int(value[4:6]), # %m
4321 int(value[6:8]), # %d
4322 int(value[8:10]), # %H
4323 int(value[10:12]), # %M
4324 int(value[12:14]), # %S
4326 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4327 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4328 if value[-1] != "Z":
4329 raise ValueError("non UTC timezone")
4330 if value[14] != ".":
4331 raise ValueError("no fractions separator")
4334 raise ValueError("trailing zero")
4337 raise ValueError("only microsecond fractions are supported")
4338 us = int(us + ("0" * (6 - us_len)))
4340 int(value[:4]), # %Y
4341 int(value[4:6]), # %m
4342 int(value[6:8]), # %d
4343 int(value[8:10]), # %H
4344 int(value[10:12]), # %M
4345 int(value[12:14]), # %S
4349 raise ValueError("invalid GeneralizedTime length")
4351 def _value_sanitize(self, value):
4352 if isinstance(value, binary_type):
4354 value_decoded = value.decode("ascii")
4355 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4356 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4358 self._strptime(value_decoded)
4359 except (TypeError, ValueError) as err:
4361 "invalid GeneralizedTime format: %r" % err,
4362 klass=self.__class__,
4365 if isinstance(value, self.__class__):
4367 if isinstance(value, datetime):
4368 encoded = value.strftime("%Y%m%d%H%M%S")
4369 if value.microsecond > 0:
4370 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4371 return (encoded + "Z").encode("ascii")
4372 raise InvalidValueType((self.__class__, datetime))
4374 def todatetime(self):
4375 return self._strptime(self._value.decode("ascii"))
4378 class GraphicString(CommonString):
4380 tag_default = tag_encode(25)
4381 encoding = "iso-8859-1"
4382 asn1_type_name = "GraphicString"
4385 class VisibleString(CommonString):
4387 tag_default = tag_encode(26)
4389 asn1_type_name = "VisibleString"
4392 class ISO646String(VisibleString):
4394 asn1_type_name = "ISO646String"
4397 class GeneralString(CommonString):
4399 tag_default = tag_encode(27)
4400 encoding = "iso-8859-1"
4401 asn1_type_name = "GeneralString"
4404 class UniversalString(CommonString):
4406 tag_default = tag_encode(28)
4407 encoding = "utf-32-be"
4408 asn1_type_name = "UniversalString"
4411 class BMPString(CommonString):
4413 tag_default = tag_encode(30)
4414 encoding = "utf-16-be"
4415 asn1_type_name = "BMPString"
4418 ChoiceState = namedtuple("ChoiceState", (
4436 """``CHOICE`` special type
4440 class GeneralName(Choice):
4442 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4443 ("dNSName", IA5String(impl=tag_ctxp(2))),
4446 >>> gn = GeneralName()
4448 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4449 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4450 >>> gn["dNSName"] = IA5String("bar.baz")
4451 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4452 >>> gn["rfc822Name"]
4455 [2] IA5String IA5 bar.baz
4458 >>> gn.value == gn["dNSName"]
4461 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4463 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4464 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4466 __slots__ = ("specs",)
4468 asn1_type_name = "CHOICE"
4481 :param value: set the value. Either ``(choice, value)`` tuple, or
4482 :py:class:`pyderasn.Choice` object
4483 :param bytes impl: can not be set, do **not** use it
4484 :param bytes expl: override default tag with ``EXPLICIT`` one
4485 :param default: set default value. Type same as in ``value``
4486 :param bool optional: is object ``OPTIONAL`` in sequence
4488 if impl is not None:
4489 raise ValueError("no implicit tag allowed for CHOICE")
4490 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4492 schema = getattr(self, "schema", ())
4493 if len(schema) == 0:
4494 raise ValueError("schema must be specified")
4496 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4499 if value is not None:
4500 self._value = self._value_sanitize(value)
4501 if default is not None:
4502 default_value = self._value_sanitize(default)
4503 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4504 default_obj.specs = self.specs
4505 default_obj._value = default_value
4506 self.default = default_obj
4508 self._value = copy(default_obj._value)
4510 def _value_sanitize(self, value):
4511 if isinstance(value, tuple) and len(value) == 2:
4513 spec = self.specs.get(choice)
4515 raise ObjUnknown(choice)
4516 if not isinstance(obj, spec.__class__):
4517 raise InvalidValueType((spec,))
4518 return (choice, spec(obj))
4519 if isinstance(value, self.__class__):
4521 raise InvalidValueType((self.__class__, tuple))
4525 return self._value is not None and self._value[1].ready
4529 return self.expl_lenindef or (
4530 (self._value is not None) and
4531 self._value[1].bered
4534 def __getstate__(self):
4551 def __setstate__(self, state):
4552 super(Choice, self).__setstate__(state)
4553 self.specs = state.specs
4554 self._value = state.value
4555 self._expl = state.expl
4556 self.default = state.default
4557 self.optional = state.optional
4558 self.offset = state.offset
4559 self.llen = state.llen
4560 self.vlen = state.vlen
4561 self.expl_lenindef = state.expl_lenindef
4562 self.lenindef = state.lenindef
4563 self.ber_encoded = state.ber_encoded
4565 def __eq__(self, their):
4566 if isinstance(their, tuple) and len(their) == 2:
4567 return self._value == their
4568 if not isinstance(their, self.__class__):
4571 self.specs == their.specs and
4572 self._value == their._value
4582 return self.__class__(
4585 expl=self._expl if expl is None else expl,
4586 default=self.default if default is None else default,
4587 optional=self.optional if optional is None else optional,
4592 self._assert_ready()
4593 return self._value[0]
4597 self._assert_ready()
4598 return self._value[1]
4600 def __getitem__(self, key):
4601 if key not in self.specs:
4602 raise ObjUnknown(key)
4603 if self._value is None:
4605 choice, value = self._value
4610 def __setitem__(self, key, value):
4611 spec = self.specs.get(key)
4613 raise ObjUnknown(key)
4614 if not isinstance(value, spec.__class__):
4615 raise InvalidValueType((spec.__class__,))
4616 self._value = (key, spec(value))
4624 return self._value[1].decoded if self.ready else False
4627 self._assert_ready()
4628 return self._value[1].encode()
4630 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4631 for choice, spec in iteritems(self.specs):
4632 sub_decode_path = decode_path + (choice,)
4638 decode_path=sub_decode_path,
4641 _ctx_immutable=False,
4648 klass=self.__class__,
4649 decode_path=decode_path,
4652 if tag_only: # pragma: no cover
4654 value, tail = spec.decode(
4658 decode_path=sub_decode_path,
4660 _ctx_immutable=False,
4662 obj = self.__class__(
4665 default=self.default,
4666 optional=self.optional,
4667 _decoded=(offset, 0, value.fulllen),
4669 obj._value = (choice, value)
4673 value = pp_console_row(next(self.pps()))
4675 value = "%s[%r]" % (value, self.value)
4678 def pps(self, decode_path=()):
4681 asn1_type_name=self.asn1_type_name,
4682 obj_name=self.__class__.__name__,
4683 decode_path=decode_path,
4684 value=self.choice if self.ready else None,
4685 optional=self.optional,
4686 default=self == self.default,
4687 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4688 expl=None if self._expl is None else tag_decode(self._expl),
4693 expl_lenindef=self.expl_lenindef,
4697 yield self.value.pps(decode_path=decode_path + (self.choice,))
4698 for pp in self.pps_lenindef(decode_path):
4702 class PrimitiveTypes(Choice):
4703 """Predefined ``CHOICE`` for all generic primitive types
4705 It could be useful for general decoding of some unspecified values:
4707 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4708 OCTET STRING 3 bytes 666f6f
4709 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4713 schema = tuple((klass.__name__, klass()) for klass in (
4737 AnyState = namedtuple("AnyState", (
4754 """``ANY`` special type
4756 >>> Any(Integer(-123))
4758 >>> a = Any(OctetString(b"hello world").encode())
4759 ANY 040b68656c6c6f20776f726c64
4760 >>> hexenc(bytes(a))
4761 b'0x040x0bhello world'
4763 __slots__ = ("defined",)
4764 tag_default = tag_encode(0)
4765 asn1_type_name = "ANY"
4775 :param value: set the value. Either any kind of pyderasn's
4776 **ready** object, or bytes. Pay attention that
4777 **no** validation is performed is raw binary value
4779 :param bytes expl: override default tag with ``EXPLICIT`` one
4780 :param bool optional: is object ``OPTIONAL`` in sequence
4782 super(Any, self).__init__(None, expl, None, optional, _decoded)
4783 self._value = None if value is None else self._value_sanitize(value)
4786 def _value_sanitize(self, value):
4787 if isinstance(value, binary_type):
4789 if isinstance(value, self.__class__):
4791 if isinstance(value, Obj):
4792 return value.encode()
4793 raise InvalidValueType((self.__class__, Obj, binary_type))
4797 return self._value is not None
4801 if self.expl_lenindef or self.lenindef:
4803 if self.defined is None:
4805 return self.defined[1].bered
4807 def __getstate__(self):
4823 def __setstate__(self, state):
4824 super(Any, self).__setstate__(state)
4825 self._value = state.value
4826 self.tag = state.tag
4827 self._expl = state.expl
4828 self.optional = state.optional
4829 self.offset = state.offset
4830 self.llen = state.llen
4831 self.vlen = state.vlen
4832 self.expl_lenindef = state.expl_lenindef
4833 self.lenindef = state.lenindef
4834 self.ber_encoded = state.ber_encoded
4835 self.defined = state.defined
4837 def __eq__(self, their):
4838 if isinstance(their, binary_type):
4839 return self._value == their
4840 if issubclass(their.__class__, Any):
4841 return self._value == their._value
4850 return self.__class__(
4852 expl=self._expl if expl is None else expl,
4853 optional=self.optional if optional is None else optional,
4856 def __bytes__(self):
4857 self._assert_ready()
4865 self._assert_ready()
4868 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4870 t, tlen, lv = tag_strip(tlv)
4871 except DecodeError as err:
4872 raise err.__class__(
4874 klass=self.__class__,
4875 decode_path=decode_path,
4879 l, llen, v = len_decode(lv)
4880 except LenIndefForm as err:
4881 if not ctx.get("bered", False):
4882 raise err.__class__(
4884 klass=self.__class__,
4885 decode_path=decode_path,
4888 llen, vlen, v = 1, 0, lv[1:]
4889 sub_offset = offset + tlen + llen
4891 while v[:EOC_LEN].tobytes() != EOC:
4892 chunk, v = Any().decode(
4895 decode_path=decode_path + (str(chunk_i),),
4898 _ctx_immutable=False,
4900 vlen += chunk.tlvlen
4901 sub_offset += chunk.tlvlen
4903 tlvlen = tlen + llen + vlen + EOC_LEN
4904 obj = self.__class__(
4905 value=tlv[:tlvlen].tobytes(),
4907 optional=self.optional,
4908 _decoded=(offset, 0, tlvlen),
4911 obj.tag = t.tobytes()
4912 return obj, v[EOC_LEN:]
4913 except DecodeError as err:
4914 raise err.__class__(
4916 klass=self.__class__,
4917 decode_path=decode_path,
4921 raise NotEnoughData(
4922 "encoded length is longer than data",
4923 klass=self.__class__,
4924 decode_path=decode_path,
4927 tlvlen = tlen + llen + l
4928 v, tail = tlv[:tlvlen], v[l:]
4929 obj = self.__class__(
4932 optional=self.optional,
4933 _decoded=(offset, 0, tlvlen),
4935 obj.tag = t.tobytes()
4939 return pp_console_row(next(self.pps()))
4941 def pps(self, decode_path=()):
4944 asn1_type_name=self.asn1_type_name,
4945 obj_name=self.__class__.__name__,
4946 decode_path=decode_path,
4947 blob=self._value if self.ready else None,
4948 optional=self.optional,
4949 default=self == self.default,
4950 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4951 expl=None if self._expl is None else tag_decode(self._expl),
4956 expl_offset=self.expl_offset if self.expled else None,
4957 expl_tlen=self.expl_tlen if self.expled else None,
4958 expl_llen=self.expl_llen if self.expled else None,
4959 expl_vlen=self.expl_vlen if self.expled else None,
4960 expl_lenindef=self.expl_lenindef,
4961 lenindef=self.lenindef,
4964 defined_by, defined = self.defined or (None, None)
4965 if defined_by is not None:
4967 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4969 for pp in self.pps_lenindef(decode_path):
4973 ########################################################################
4974 # ASN.1 constructed types
4975 ########################################################################
4977 def get_def_by_path(defines_by_path, sub_decode_path):
4978 """Get define by decode path
4980 for path, define in defines_by_path:
4981 if len(path) != len(sub_decode_path):
4983 for p1, p2 in zip(path, sub_decode_path):
4984 if (p1 != any) and (p1 != p2):
4990 def abs_decode_path(decode_path, rel_path):
4991 """Create an absolute decode path from current and relative ones
4993 :param decode_path: current decode path, starting point. Tuple of strings
4994 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4995 If first tuple's element is "/", then treat it as
4996 an absolute path, ignoring ``decode_path`` as
4997 starting point. Also this tuple can contain ".."
4998 elements, stripping the leading element from
5001 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5002 ("foo", "bar", "baz", "whatever")
5003 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5005 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5008 if rel_path[0] == "/":
5010 if rel_path[0] == "..":
5011 return abs_decode_path(decode_path[:-1], rel_path[1:])
5012 return decode_path + rel_path
5015 SequenceState = namedtuple("SequenceState", (
5032 class Sequence(Obj):
5033 """``SEQUENCE`` structure type
5035 You have to make specification of sequence::
5037 class Extension(Sequence):
5039 ("extnID", ObjectIdentifier()),
5040 ("critical", Boolean(default=False)),
5041 ("extnValue", OctetString()),
5044 Then, you can work with it as with dictionary.
5046 >>> ext = Extension()
5047 >>> Extension().specs
5049 ('extnID', OBJECT IDENTIFIER),
5050 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5051 ('extnValue', OCTET STRING),
5053 >>> ext["extnID"] = "1.2.3"
5054 Traceback (most recent call last):
5055 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5056 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5058 You can determine if sequence is ready to be encoded:
5063 Traceback (most recent call last):
5064 pyderasn.ObjNotReady: object is not ready: extnValue
5065 >>> ext["extnValue"] = OctetString(b"foobar")
5069 Value you want to assign, must have the same **type** as in
5070 corresponding specification, but it can have different tags,
5071 optional/default attributes -- they will be taken from specification
5074 class TBSCertificate(Sequence):
5076 ("version", Version(expl=tag_ctxc(0), default="v1")),
5079 >>> tbs = TBSCertificate()
5080 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5082 Assign ``None`` to remove value from sequence.
5084 You can set values in Sequence during its initialization:
5086 >>> AlgorithmIdentifier((
5087 ("algorithm", ObjectIdentifier("1.2.3")),
5088 ("parameters", Any(Null()))
5090 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5092 You can determine if value exists/set in the sequence and take its value:
5094 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5097 OBJECT IDENTIFIER 1.2.3
5099 But pay attention that if value has default, then it won't be (not
5100 in) in the sequence (because ``DEFAULT`` must not be encoded in
5101 DER), but you can read its value:
5103 >>> "critical" in ext, ext["critical"]
5104 (False, BOOLEAN False)
5105 >>> ext["critical"] = Boolean(True)
5106 >>> "critical" in ext, ext["critical"]
5107 (True, BOOLEAN True)
5109 All defaulted values are always optional.
5111 .. _allow_default_values_ctx:
5113 DER prohibits default value encoding and will raise an error if
5114 default value is unexpectedly met during decode.
5115 If :ref:`bered <bered_ctx>` context option is set, then no error
5116 will be raised, but ``bered`` attribute set. You can disable strict
5117 defaulted values existence validation by setting
5118 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5120 Two sequences are equal if they have equal specification (schema),
5121 implicit/explicit tagging and the same values.
5123 __slots__ = ("specs",)
5124 tag_default = tag_encode(form=TagFormConstructed, num=16)
5125 asn1_type_name = "SEQUENCE"
5137 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5139 schema = getattr(self, "schema", ())
5141 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5144 if value is not None:
5145 if issubclass(value.__class__, Sequence):
5146 self._value = value._value
5147 elif hasattr(value, "__iter__"):
5148 for seq_key, seq_value in value:
5149 self[seq_key] = seq_value
5151 raise InvalidValueType((Sequence,))
5152 if default is not None:
5153 if not issubclass(default.__class__, Sequence):
5154 raise InvalidValueType((Sequence,))
5155 default_value = default._value
5156 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5157 default_obj.specs = self.specs
5158 default_obj._value = default_value
5159 self.default = default_obj
5161 self._value = copy(default_obj._value)
5165 for name, spec in iteritems(self.specs):
5166 value = self._value.get(name)
5177 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5179 return any(value.bered for value in itervalues(self._value))
5181 def __getstate__(self):
5182 return SequenceState(
5185 {k: copy(v) for k, v in iteritems(self._value)},
5198 def __setstate__(self, state):
5199 super(Sequence, self).__setstate__(state)
5200 self.specs = state.specs
5201 self._value = state.value
5202 self.tag = state.tag
5203 self._expl = state.expl
5204 self.default = state.default
5205 self.optional = state.optional
5206 self.offset = state.offset
5207 self.llen = state.llen
5208 self.vlen = state.vlen
5209 self.expl_lenindef = state.expl_lenindef
5210 self.lenindef = state.lenindef
5211 self.ber_encoded = state.ber_encoded
5213 def __eq__(self, their):
5214 if not isinstance(their, self.__class__):
5217 self.specs == their.specs and
5218 self.tag == their.tag and
5219 self._expl == their._expl and
5220 self._value == their._value
5231 return self.__class__(
5234 impl=self.tag if impl is None else impl,
5235 expl=self._expl if expl is None else expl,
5236 default=self.default if default is None else default,
5237 optional=self.optional if optional is None else optional,
5240 def __contains__(self, key):
5241 return key in self._value
5243 def __setitem__(self, key, value):
5244 spec = self.specs.get(key)
5246 raise ObjUnknown(key)
5248 self._value.pop(key, None)
5250 if not isinstance(value, spec.__class__):
5251 raise InvalidValueType((spec.__class__,))
5252 value = spec(value=value)
5253 if spec.default is not None and value == spec.default:
5254 self._value.pop(key, None)
5256 self._value[key] = value
5258 def __getitem__(self, key):
5259 value = self._value.get(key)
5260 if value is not None:
5262 spec = self.specs.get(key)
5264 raise ObjUnknown(key)
5265 if spec.default is not None:
5269 def _encoded_values(self):
5271 for name, spec in iteritems(self.specs):
5272 value = self._value.get(name)
5276 raise ObjNotReady(name)
5277 raws.append(value.encode())
5281 v = b"".join(self._encoded_values())
5282 return b"".join((self.tag, len_encode(len(v)), v))
5284 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5286 t, tlen, lv = tag_strip(tlv)
5287 except DecodeError as err:
5288 raise err.__class__(
5290 klass=self.__class__,
5291 decode_path=decode_path,
5296 klass=self.__class__,
5297 decode_path=decode_path,
5300 if tag_only: # pragma: no cover
5303 ctx_bered = ctx.get("bered", False)
5305 l, llen, v = len_decode(lv)
5306 except LenIndefForm as err:
5308 raise err.__class__(
5310 klass=self.__class__,
5311 decode_path=decode_path,
5314 l, llen, v = 0, 1, lv[1:]
5316 except DecodeError as err:
5317 raise err.__class__(
5319 klass=self.__class__,
5320 decode_path=decode_path,
5324 raise NotEnoughData(
5325 "encoded length is longer than data",
5326 klass=self.__class__,
5327 decode_path=decode_path,
5331 v, tail = v[:l], v[l:]
5333 sub_offset = offset + tlen + llen
5336 ctx_allow_default_values = ctx.get("allow_default_values", False)
5337 for name, spec in iteritems(self.specs):
5338 if spec.optional and (
5339 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5343 sub_decode_path = decode_path + (name,)
5345 value, v_tail = spec.decode(
5349 decode_path=sub_decode_path,
5351 _ctx_immutable=False,
5353 except TagMismatch as err:
5354 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5358 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5359 if defined is not None:
5360 defined_by, defined_spec = defined
5361 if issubclass(value.__class__, SequenceOf):
5362 for i, _value in enumerate(value):
5363 sub_sub_decode_path = sub_decode_path + (
5365 DecodePathDefBy(defined_by),
5367 defined_value, defined_tail = defined_spec.decode(
5368 memoryview(bytes(_value)),
5370 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5371 if value.expled else (value.tlen + value.llen)
5374 decode_path=sub_sub_decode_path,
5376 _ctx_immutable=False,
5378 if len(defined_tail) > 0:
5381 klass=self.__class__,
5382 decode_path=sub_sub_decode_path,
5385 _value.defined = (defined_by, defined_value)
5387 defined_value, defined_tail = defined_spec.decode(
5388 memoryview(bytes(value)),
5390 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5391 if value.expled else (value.tlen + value.llen)
5394 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5396 _ctx_immutable=False,
5398 if len(defined_tail) > 0:
5401 klass=self.__class__,
5402 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5405 value.defined = (defined_by, defined_value)
5407 value_len = value.fulllen
5409 sub_offset += value_len
5411 if spec.default is not None and value == spec.default:
5412 if ctx_bered or ctx_allow_default_values:
5416 "DEFAULT value met",
5417 klass=self.__class__,
5418 decode_path=sub_decode_path,
5421 values[name] = value
5423 spec_defines = getattr(spec, "defines", ())
5424 if len(spec_defines) == 0:
5425 defines_by_path = ctx.get("defines_by_path", ())
5426 if len(defines_by_path) > 0:
5427 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5428 if spec_defines is not None and len(spec_defines) > 0:
5429 for rel_path, schema in spec_defines:
5430 defined = schema.get(value, None)
5431 if defined is not None:
5432 ctx.setdefault("_defines", []).append((
5433 abs_decode_path(sub_decode_path[:-1], rel_path),
5437 if v[:EOC_LEN].tobytes() != EOC:
5440 klass=self.__class__,
5441 decode_path=decode_path,
5449 klass=self.__class__,
5450 decode_path=decode_path,
5453 obj = self.__class__(
5457 default=self.default,
5458 optional=self.optional,
5459 _decoded=(offset, llen, vlen),
5462 obj.lenindef = lenindef
5463 obj.ber_encoded = ber_encoded
5467 value = pp_console_row(next(self.pps()))
5469 for name in self.specs:
5470 _value = self._value.get(name)
5473 cols.append("%s: %s" % (name, repr(_value)))
5474 return "%s[%s]" % (value, "; ".join(cols))
5476 def pps(self, decode_path=()):
5479 asn1_type_name=self.asn1_type_name,
5480 obj_name=self.__class__.__name__,
5481 decode_path=decode_path,
5482 optional=self.optional,
5483 default=self == self.default,
5484 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5485 expl=None if self._expl is None else tag_decode(self._expl),
5490 expl_offset=self.expl_offset if self.expled else None,
5491 expl_tlen=self.expl_tlen if self.expled else None,
5492 expl_llen=self.expl_llen if self.expled else None,
5493 expl_vlen=self.expl_vlen if self.expled else None,
5494 expl_lenindef=self.expl_lenindef,
5495 lenindef=self.lenindef,
5496 ber_encoded=self.ber_encoded,
5499 for name in self.specs:
5500 value = self._value.get(name)
5503 yield value.pps(decode_path=decode_path + (name,))
5504 for pp in self.pps_lenindef(decode_path):
5508 class Set(Sequence):
5509 """``SET`` structure type
5511 Its usage is identical to :py:class:`pyderasn.Sequence`.
5513 .. _allow_unordered_set_ctx:
5515 DER prohibits unordered values encoding and will raise an error
5516 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5517 then no error will occure. Also you can disable strict values
5518 ordering check by setting ``"allow_unordered_set": True``
5519 :ref:`context <ctx>` option.
5522 tag_default = tag_encode(form=TagFormConstructed, num=17)
5523 asn1_type_name = "SET"
5526 raws = self._encoded_values()
5529 return b"".join((self.tag, len_encode(len(v)), v))
5531 def _specs_items(self):
5532 return iteritems(self.specs)
5534 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5536 t, tlen, lv = tag_strip(tlv)
5537 except DecodeError as err:
5538 raise err.__class__(
5540 klass=self.__class__,
5541 decode_path=decode_path,
5546 klass=self.__class__,
5547 decode_path=decode_path,
5553 ctx_bered = ctx.get("bered", False)
5555 l, llen, v = len_decode(lv)
5556 except LenIndefForm as err:
5558 raise err.__class__(
5560 klass=self.__class__,
5561 decode_path=decode_path,
5564 l, llen, v = 0, 1, lv[1:]
5566 except DecodeError as err:
5567 raise err.__class__(
5569 klass=self.__class__,
5570 decode_path=decode_path,
5574 raise NotEnoughData(
5575 "encoded length is longer than data",
5576 klass=self.__class__,
5580 v, tail = v[:l], v[l:]
5582 sub_offset = offset + tlen + llen
5585 ctx_allow_default_values = ctx.get("allow_default_values", False)
5586 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5587 value_prev = memoryview(v[:0])
5590 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5592 for name, spec in self._specs_items():
5593 sub_decode_path = decode_path + (name,)
5599 decode_path=sub_decode_path,
5602 _ctx_immutable=False,
5609 klass=self.__class__,
5610 decode_path=decode_path,
5613 value, v_tail = spec.decode(
5617 decode_path=sub_decode_path,
5619 _ctx_immutable=False,
5621 value_len = value.fulllen
5622 if value_prev.tobytes() > v[:value_len].tobytes():
5623 if ctx_bered or ctx_allow_unordered_set:
5627 "unordered " + self.asn1_type_name,
5628 klass=self.__class__,
5629 decode_path=sub_decode_path,
5632 if spec.default is None or value != spec.default:
5634 elif ctx_bered or ctx_allow_default_values:
5638 "DEFAULT value met",
5639 klass=self.__class__,
5640 decode_path=sub_decode_path,
5643 values[name] = value
5644 value_prev = v[:value_len]
5645 sub_offset += value_len
5648 obj = self.__class__(
5652 default=self.default,
5653 optional=self.optional,
5654 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5657 if v[:EOC_LEN].tobytes() != EOC:
5660 klass=self.__class__,
5661 decode_path=decode_path,
5669 "not all values are ready",
5670 klass=self.__class__,
5671 decode_path=decode_path,
5674 obj.ber_encoded = ber_encoded
5678 SequenceOfState = namedtuple("SequenceOfState", (
5697 class SequenceOf(Obj):
5698 """``SEQUENCE OF`` sequence type
5700 For that kind of type you must specify the object it will carry on
5701 (bounds are for example here, not required)::
5703 class Ints(SequenceOf):
5708 >>> ints.append(Integer(123))
5709 >>> ints.append(Integer(234))
5711 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5712 >>> [int(i) for i in ints]
5714 >>> ints.append(Integer(345))
5715 Traceback (most recent call last):
5716 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5719 >>> ints[1] = Integer(345)
5721 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5723 Also you can initialize sequence with preinitialized values:
5725 >>> ints = Ints([Integer(123), Integer(234)])
5727 __slots__ = ("spec", "_bound_min", "_bound_max")
5728 tag_default = tag_encode(form=TagFormConstructed, num=16)
5729 asn1_type_name = "SEQUENCE OF"
5742 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5744 schema = getattr(self, "schema", None)
5746 raise ValueError("schema must be specified")
5748 self._bound_min, self._bound_max = getattr(
5752 ) if bounds is None else bounds
5754 if value is not None:
5755 self._value = self._value_sanitize(value)
5756 if default is not None:
5757 default_value = self._value_sanitize(default)
5758 default_obj = self.__class__(
5763 default_obj._value = default_value
5764 self.default = default_obj
5766 self._value = copy(default_obj._value)
5768 def _value_sanitize(self, value):
5769 if issubclass(value.__class__, SequenceOf):
5770 value = value._value
5771 elif hasattr(value, "__iter__"):
5774 raise InvalidValueType((self.__class__, iter))
5775 if not self._bound_min <= len(value) <= self._bound_max:
5776 raise BoundsError(self._bound_min, len(value), self._bound_max)
5778 if not isinstance(v, self.spec.__class__):
5779 raise InvalidValueType((self.spec.__class__,))
5784 return all(v.ready for v in self._value)
5788 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5790 return any(v.bered for v in self._value)
5792 def __getstate__(self):
5793 return SequenceOfState(
5796 [copy(v) for v in self._value],
5811 def __setstate__(self, state):
5812 super(SequenceOf, self).__setstate__(state)
5813 self.spec = state.spec
5814 self._value = state.value
5815 self._bound_min = state.bound_min
5816 self._bound_max = state.bound_max
5817 self.tag = state.tag
5818 self._expl = state.expl
5819 self.default = state.default
5820 self.optional = state.optional
5821 self.offset = state.offset
5822 self.llen = state.llen
5823 self.vlen = state.vlen
5824 self.expl_lenindef = state.expl_lenindef
5825 self.lenindef = state.lenindef
5826 self.ber_encoded = state.ber_encoded
5828 def __eq__(self, their):
5829 if isinstance(their, self.__class__):
5831 self.spec == their.spec and
5832 self.tag == their.tag and
5833 self._expl == their._expl and
5834 self._value == their._value
5836 if hasattr(their, "__iter__"):
5837 return self._value == list(their)
5849 return self.__class__(
5853 (self._bound_min, self._bound_max)
5854 if bounds is None else bounds
5856 impl=self.tag if impl is None else impl,
5857 expl=self._expl if expl is None else expl,
5858 default=self.default if default is None else default,
5859 optional=self.optional if optional is None else optional,
5862 def __contains__(self, key):
5863 return key in self._value
5865 def append(self, value):
5866 if not isinstance(value, self.spec.__class__):
5867 raise InvalidValueType((self.spec.__class__,))
5868 if len(self._value) + 1 > self._bound_max:
5871 len(self._value) + 1,
5874 self._value.append(value)
5877 self._assert_ready()
5878 return iter(self._value)
5881 self._assert_ready()
5882 return len(self._value)
5884 def __setitem__(self, key, value):
5885 if not isinstance(value, self.spec.__class__):
5886 raise InvalidValueType((self.spec.__class__,))
5887 self._value[key] = self.spec(value=value)
5889 def __getitem__(self, key):
5890 return self._value[key]
5892 def _encoded_values(self):
5893 return [v.encode() for v in self._value]
5896 v = b"".join(self._encoded_values())
5897 return b"".join((self.tag, len_encode(len(v)), v))
5899 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5901 t, tlen, lv = tag_strip(tlv)
5902 except DecodeError as err:
5903 raise err.__class__(
5905 klass=self.__class__,
5906 decode_path=decode_path,
5911 klass=self.__class__,
5912 decode_path=decode_path,
5918 ctx_bered = ctx.get("bered", False)
5920 l, llen, v = len_decode(lv)
5921 except LenIndefForm as err:
5923 raise err.__class__(
5925 klass=self.__class__,
5926 decode_path=decode_path,
5929 l, llen, v = 0, 1, lv[1:]
5931 except DecodeError as err:
5932 raise err.__class__(
5934 klass=self.__class__,
5935 decode_path=decode_path,
5939 raise NotEnoughData(
5940 "encoded length is longer than data",
5941 klass=self.__class__,
5942 decode_path=decode_path,
5946 v, tail = v[:l], v[l:]
5948 sub_offset = offset + tlen + llen
5950 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5951 value_prev = memoryview(v[:0])
5955 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5957 sub_decode_path = decode_path + (str(len(_value)),)
5958 value, v_tail = spec.decode(
5962 decode_path=sub_decode_path,
5964 _ctx_immutable=False,
5966 value_len = value.fulllen
5968 if value_prev.tobytes() > v[:value_len].tobytes():
5969 if ctx_bered or ctx_allow_unordered_set:
5973 "unordered " + self.asn1_type_name,
5974 klass=self.__class__,
5975 decode_path=sub_decode_path,
5978 value_prev = v[:value_len]
5979 _value.append(value)
5980 sub_offset += value_len
5984 obj = self.__class__(
5987 bounds=(self._bound_min, self._bound_max),
5990 default=self.default,
5991 optional=self.optional,
5992 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5994 except BoundsError as err:
5997 klass=self.__class__,
5998 decode_path=decode_path,
6002 if v[:EOC_LEN].tobytes() != EOC:
6005 klass=self.__class__,
6006 decode_path=decode_path,
6011 obj.ber_encoded = ber_encoded
6016 pp_console_row(next(self.pps())),
6017 ", ".join(repr(v) for v in self._value),
6020 def pps(self, decode_path=()):
6023 asn1_type_name=self.asn1_type_name,
6024 obj_name=self.__class__.__name__,
6025 decode_path=decode_path,
6026 optional=self.optional,
6027 default=self == self.default,
6028 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6029 expl=None if self._expl is None else tag_decode(self._expl),
6034 expl_offset=self.expl_offset if self.expled else None,
6035 expl_tlen=self.expl_tlen if self.expled else None,
6036 expl_llen=self.expl_llen if self.expled else None,
6037 expl_vlen=self.expl_vlen if self.expled else None,
6038 expl_lenindef=self.expl_lenindef,
6039 lenindef=self.lenindef,
6040 ber_encoded=self.ber_encoded,
6043 for i, value in enumerate(self._value):
6044 yield value.pps(decode_path=decode_path + (str(i),))
6045 for pp in self.pps_lenindef(decode_path):
6049 class SetOf(SequenceOf):
6050 """``SET OF`` sequence type
6052 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6055 tag_default = tag_encode(form=TagFormConstructed, num=17)
6056 asn1_type_name = "SET OF"
6059 raws = self._encoded_values()
6062 return b"".join((self.tag, len_encode(len(v)), v))
6064 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6065 return super(SetOf, self)._decode(
6071 ordering_check=True,
6075 def obj_by_path(pypath): # pragma: no cover
6076 """Import object specified as string Python path
6078 Modules must be separated from classes/functions with ``:``.
6080 >>> obj_by_path("foo.bar:Baz")
6081 <class 'foo.bar.Baz'>
6082 >>> obj_by_path("foo.bar:Baz.boo")
6083 <classmethod 'foo.bar.Baz.boo'>
6085 mod, objs = pypath.rsplit(":", 1)
6086 from importlib import import_module
6087 obj = import_module(mod)
6088 for obj_name in objs.split("."):
6089 obj = getattr(obj, obj_name)
6093 def generic_decoder(): # pragma: no cover
6094 # All of this below is a big hack with self references
6095 choice = PrimitiveTypes()
6096 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6097 choice.specs["SetOf"] = SetOf(schema=choice)
6098 for i in six_xrange(31):
6099 choice.specs["SequenceOf%d" % i] = SequenceOf(
6103 choice.specs["Any"] = Any()
6105 # Class name equals to type name, to omit it from output
6106 class SEQUENCEOF(SequenceOf):
6114 with_decode_path=False,
6115 decode_path_only=(),
6117 def _pprint_pps(pps):
6119 if hasattr(pp, "_fields"):
6121 decode_path_only != () and
6122 pp.decode_path[:len(decode_path_only)] != decode_path_only
6125 if pp.asn1_type_name == Choice.asn1_type_name:
6127 pp_kwargs = pp._asdict()
6128 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6129 pp = _pp(**pp_kwargs)
6130 yield pp_console_row(
6135 with_colours=with_colours,
6136 with_decode_path=with_decode_path,
6137 decode_path_len_decrease=len(decode_path_only),
6139 for row in pp_console_blob(
6141 decode_path_len_decrease=len(decode_path_only),
6145 for row in _pprint_pps(pp):
6147 return "\n".join(_pprint_pps(obj.pps()))
6148 return SEQUENCEOF(), pprint_any
6151 def main(): # pragma: no cover
6153 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6154 parser.add_argument(
6158 help="Skip that number of bytes from the beginning",
6160 parser.add_argument(
6162 help="Python paths to dictionary with OIDs, comma separated",
6164 parser.add_argument(
6166 help="Python path to schema definition to use",
6168 parser.add_argument(
6169 "--defines-by-path",
6170 help="Python path to decoder's defines_by_path",
6172 parser.add_argument(
6174 action="store_true",
6175 help="Disallow BER encoding",
6177 parser.add_argument(
6178 "--print-decode-path",
6179 action="store_true",
6180 help="Print decode paths",
6182 parser.add_argument(
6183 "--decode-path-only",
6184 help="Print only specified decode path",
6186 parser.add_argument(
6188 action="store_true",
6189 help="Allow explicit tag out-of-bound",
6191 parser.add_argument(
6193 type=argparse.FileType("rb"),
6194 help="Path to DER file you want to decode",
6196 args = parser.parse_args()
6197 args.DERFile.seek(args.skip)
6198 der = memoryview(args.DERFile.read())
6199 args.DERFile.close()
6201 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6202 if args.oids else ()
6205 schema = obj_by_path(args.schema)
6206 from functools import partial
6207 pprinter = partial(pprint, big_blobs=True)
6209 schema, pprinter = generic_decoder()
6211 "bered": not args.nobered,
6212 "allow_expl_oob": args.allow_expl_oob,
6214 if args.defines_by_path is not None:
6215 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6216 obj, tail = schema().decode(der, ctx=ctx)
6220 with_colours=environ.get("NO_COLOR") is None,
6221 with_decode_path=args.print_decode_path,
6223 () if args.decode_path_only is None else
6224 tuple(args.decode_path_only.split(":"))
6228 print("\nTrailing data: %s" % hexenc(tail))
6231 if __name__ == "__main__":