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", (
3425 if (value[0] in "+- ") or (value[-1] == " "):
3426 raise ValueError("non-pure integer")
3430 class ObjectIdentifier(Obj):
3431 """``OBJECT IDENTIFIER`` OID type
3433 >>> oid = ObjectIdentifier((1, 2, 3))
3434 OBJECT IDENTIFIER 1.2.3
3435 >>> oid == ObjectIdentifier("1.2.3")
3441 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3442 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3444 >>> str(ObjectIdentifier((3, 1)))
3445 Traceback (most recent call last):
3446 pyderasn.InvalidOID: unacceptable first arc value
3448 __slots__ = ("defines",)
3449 tag_default = tag_encode(6)
3450 asn1_type_name = "OBJECT IDENTIFIER"
3463 :param value: set the value. Either tuples of integers,
3464 string of "."-concatenated integers, or
3465 :py:class:`pyderasn.ObjectIdentifier` object
3466 :param defines: sequence of tuples. Each tuple has two elements.
3467 First one is relative to current one decode
3468 path, aiming to the field defined by that OID.
3469 Read about relative path in
3470 :py:func:`pyderasn.abs_decode_path`. Second
3471 tuple element is ``{OID: pyderasn.Obj()}``
3472 dictionary, mapping between current OID value
3473 and structure applied to defined field.
3474 :ref:`Read about DEFINED BY <definedby>`
3475 :param bytes impl: override default tag with ``IMPLICIT`` one
3476 :param bytes expl: override default tag with ``EXPLICIT`` one
3477 :param default: set default value. Type same as in ``value``
3478 :param bool optional: is object ``OPTIONAL`` in sequence
3480 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3482 if value is not None:
3483 self._value = self._value_sanitize(value)
3484 if default is not None:
3485 default = self._value_sanitize(default)
3486 self.default = self.__class__(
3491 if self._value is None:
3492 self._value = default
3493 self.defines = defines
3495 def __add__(self, their):
3496 if isinstance(their, self.__class__):
3497 return self.__class__(self._value + their._value)
3498 if isinstance(their, tuple):
3499 return self.__class__(self._value + their)
3500 raise InvalidValueType((self.__class__, tuple))
3502 def _value_sanitize(self, value):
3503 if issubclass(value.__class__, ObjectIdentifier):
3505 if isinstance(value, string_types):
3507 value = tuple(pureint(arc) for arc in value.split("."))
3509 raise InvalidOID("unacceptable arcs values")
3510 if isinstance(value, tuple):
3512 raise InvalidOID("less than 2 arcs")
3513 first_arc = value[0]
3514 if first_arc in (0, 1):
3515 if not (0 <= value[1] <= 39):
3516 raise InvalidOID("second arc is too wide")
3517 elif first_arc == 2:
3520 raise InvalidOID("unacceptable first arc value")
3521 if not all(arc >= 0 for arc in value):
3522 raise InvalidOID("negative arc value")
3524 raise InvalidValueType((self.__class__, str, tuple))
3528 return self._value is not None
3530 def __getstate__(self):
3531 return ObjectIdentifierState(
3547 def __setstate__(self, state):
3548 super(ObjectIdentifier, self).__setstate__(state)
3549 self._value = state.value
3550 self.tag = state.tag
3551 self._expl = state.expl
3552 self.default = state.default
3553 self.optional = state.optional
3554 self.offset = state.offset
3555 self.llen = state.llen
3556 self.vlen = state.vlen
3557 self.expl_lenindef = state.expl_lenindef
3558 self.lenindef = state.lenindef
3559 self.ber_encoded = state.ber_encoded
3560 self.defines = state.defines
3563 self._assert_ready()
3564 return iter(self._value)
3567 return ".".join(str(arc) for arc in self._value or ())
3570 self._assert_ready()
3573 bytes(self._expl or b"") +
3574 str(self._value).encode("ascii"),
3577 def __eq__(self, their):
3578 if isinstance(their, tuple):
3579 return self._value == their
3580 if not issubclass(their.__class__, ObjectIdentifier):
3583 self.tag == their.tag and
3584 self._expl == their._expl and
3585 self._value == their._value
3588 def __lt__(self, their):
3589 return self._value < their._value
3600 return self.__class__(
3602 defines=self.defines if defines is None else defines,
3603 impl=self.tag if impl is None else impl,
3604 expl=self._expl if expl is None else expl,
3605 default=self.default if default is None else default,
3606 optional=self.optional if optional is None else optional,
3610 self._assert_ready()
3612 first_value = value[1]
3613 first_arc = value[0]
3616 elif first_arc == 1:
3618 elif first_arc == 2:
3620 else: # pragma: no cover
3621 raise RuntimeError("invalid arc is stored")
3622 octets = [zero_ended_encode(first_value)]
3623 for arc in value[2:]:
3624 octets.append(zero_ended_encode(arc))
3625 v = b"".join(octets)
3626 return b"".join((self.tag, len_encode(len(v)), v))
3628 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3630 t, _, lv = tag_strip(tlv)
3631 except DecodeError as err:
3632 raise err.__class__(
3634 klass=self.__class__,
3635 decode_path=decode_path,
3640 klass=self.__class__,
3641 decode_path=decode_path,
3644 if tag_only: # pragma: no cover
3647 l, llen, v = len_decode(lv)
3648 except DecodeError as err:
3649 raise err.__class__(
3651 klass=self.__class__,
3652 decode_path=decode_path,
3656 raise NotEnoughData(
3657 "encoded length is longer than data",
3658 klass=self.__class__,
3659 decode_path=decode_path,
3663 raise NotEnoughData(
3665 klass=self.__class__,
3666 decode_path=decode_path,
3669 v, tail = v[:l], v[l:]
3676 octet = indexbytes(v, i)
3677 if i == 0 and octet == 0x80:
3678 if ctx.get("bered", False):
3681 raise DecodeError("non normalized arc encoding")
3682 arc = (arc << 7) | (octet & 0x7F)
3683 if octet & 0x80 == 0:
3691 klass=self.__class__,
3692 decode_path=decode_path,
3696 second_arc = arcs[0]
3697 if 0 <= second_arc <= 39:
3699 elif 40 <= second_arc <= 79:
3705 obj = self.__class__(
3706 value=tuple([first_arc, second_arc] + arcs[1:]),
3709 default=self.default,
3710 optional=self.optional,
3711 _decoded=(offset, llen, l),
3714 obj.ber_encoded = True
3718 return pp_console_row(next(self.pps()))
3720 def pps(self, decode_path=()):
3723 asn1_type_name=self.asn1_type_name,
3724 obj_name=self.__class__.__name__,
3725 decode_path=decode_path,
3726 value=str(self) if self.ready else None,
3727 optional=self.optional,
3728 default=self == self.default,
3729 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3730 expl=None if self._expl is None else tag_decode(self._expl),
3735 expl_offset=self.expl_offset if self.expled else None,
3736 expl_tlen=self.expl_tlen if self.expled else None,
3737 expl_llen=self.expl_llen if self.expled else None,
3738 expl_vlen=self.expl_vlen if self.expled else None,
3739 expl_lenindef=self.expl_lenindef,
3740 ber_encoded=self.ber_encoded,
3743 for pp in self.pps_lenindef(decode_path):
3747 class Enumerated(Integer):
3748 """``ENUMERATED`` integer type
3750 This type is identical to :py:class:`pyderasn.Integer`, but requires
3751 schema to be specified and does not accept values missing from it.
3754 tag_default = tag_encode(10)
3755 asn1_type_name = "ENUMERATED"
3766 bounds=None, # dummy argument, workability for Integer.decode
3768 super(Enumerated, self).__init__(
3769 value, bounds, impl, expl, default, optional, _specs, _decoded,
3771 if len(self.specs) == 0:
3772 raise ValueError("schema must be specified")
3774 def _value_sanitize(self, value):
3775 if isinstance(value, self.__class__):
3776 value = value._value
3777 elif isinstance(value, integer_types):
3778 for _value in itervalues(self.specs):
3783 "unknown integer value: %s" % value,
3784 klass=self.__class__,
3786 elif isinstance(value, string_types):
3787 value = self.specs.get(value)
3789 raise ObjUnknown("integer value: %s" % value)
3791 raise InvalidValueType((self.__class__, int, str))
3803 return self.__class__(
3805 impl=self.tag if impl is None else impl,
3806 expl=self._expl if expl is None else expl,
3807 default=self.default if default is None else default,
3808 optional=self.optional if optional is None else optional,
3813 def escape_control_unicode(c):
3814 if unicat(c).startswith("C"):
3815 c = repr(c).lstrip("u").strip("'")
3819 class CommonString(OctetString):
3820 """Common class for all strings
3822 Everything resembles :py:class:`pyderasn.OctetString`, except
3823 ability to deal with unicode text strings.
3825 >>> hexenc("привет мир".encode("utf-8"))
3826 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3827 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3829 >>> s = UTF8String("привет мир")
3830 UTF8String UTF8String привет мир
3832 'привет мир'
3833 >>> hexenc(bytes(s))
3834 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3836 >>> PrintableString("привет мир")
3837 Traceback (most recent call last):
3838 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3840 >>> BMPString("ада", bounds=(2, 2))
3841 Traceback (most recent call last):
3842 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3843 >>> s = BMPString("ад", bounds=(2, 2))
3846 >>> hexenc(bytes(s))
3854 * - :py:class:`pyderasn.UTF8String`
3856 * - :py:class:`pyderasn.NumericString`
3858 * - :py:class:`pyderasn.PrintableString`
3860 * - :py:class:`pyderasn.TeletexString`
3862 * - :py:class:`pyderasn.T61String`
3864 * - :py:class:`pyderasn.VideotexString`
3866 * - :py:class:`pyderasn.IA5String`
3868 * - :py:class:`pyderasn.GraphicString`
3870 * - :py:class:`pyderasn.VisibleString`
3872 * - :py:class:`pyderasn.ISO646String`
3874 * - :py:class:`pyderasn.GeneralString`
3876 * - :py:class:`pyderasn.UniversalString`
3878 * - :py:class:`pyderasn.BMPString`
3883 def _value_sanitize(self, value):
3885 value_decoded = None
3886 if isinstance(value, self.__class__):
3887 value_raw = value._value
3888 elif isinstance(value, text_type):
3889 value_decoded = value
3890 elif isinstance(value, binary_type):
3893 raise InvalidValueType((self.__class__, text_type, binary_type))
3896 value_decoded.encode(self.encoding)
3897 if value_raw is None else value_raw
3900 value_raw.decode(self.encoding)
3901 if value_decoded is None else value_decoded
3903 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3904 raise DecodeError(str(err))
3905 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3913 def __eq__(self, their):
3914 if isinstance(their, binary_type):
3915 return self._value == their
3916 if isinstance(their, text_type):
3917 return self._value == their.encode(self.encoding)
3918 if not isinstance(their, self.__class__):
3921 self._value == their._value and
3922 self.tag == their.tag and
3923 self._expl == their._expl
3926 def __unicode__(self):
3928 return self._value.decode(self.encoding)
3929 return text_type(self._value)
3932 return pp_console_row(next(self.pps(no_unicode=PY2)))
3934 def pps(self, decode_path=(), no_unicode=False):
3938 hexenc(bytes(self)) if no_unicode else
3939 "".join(escape_control_unicode(c) for c in self.__unicode__())
3943 asn1_type_name=self.asn1_type_name,
3944 obj_name=self.__class__.__name__,
3945 decode_path=decode_path,
3947 optional=self.optional,
3948 default=self == self.default,
3949 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3950 expl=None if self._expl is None else tag_decode(self._expl),
3955 expl_offset=self.expl_offset if self.expled else None,
3956 expl_tlen=self.expl_tlen if self.expled else None,
3957 expl_llen=self.expl_llen if self.expled else None,
3958 expl_vlen=self.expl_vlen if self.expled else None,
3959 expl_lenindef=self.expl_lenindef,
3960 ber_encoded=self.ber_encoded,
3963 for pp in self.pps_lenindef(decode_path):
3967 class UTF8String(CommonString):
3969 tag_default = tag_encode(12)
3971 asn1_type_name = "UTF8String"
3974 class AllowableCharsMixin(object):
3976 def allowable_chars(self):
3978 return self._allowable_chars
3979 return frozenset(six_unichr(c) for c in self._allowable_chars)
3982 class NumericString(AllowableCharsMixin, CommonString):
3985 Its value is properly sanitized: only ASCII digits with spaces can
3988 >>> NumericString().allowable_chars
3989 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3992 tag_default = tag_encode(18)
3994 asn1_type_name = "NumericString"
3995 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3997 def _value_sanitize(self, value):
3998 value = super(NumericString, self)._value_sanitize(value)
3999 if not frozenset(value) <= self._allowable_chars:
4000 raise DecodeError("non-numeric value")
4004 PrintableStringState = namedtuple(
4005 "PrintableStringState",
4006 OctetStringState._fields + ("allowable_chars",),
4010 class PrintableString(AllowableCharsMixin, CommonString):
4013 Its value is properly sanitized: see X.680 41.4 table 10.
4015 >>> PrintableString().allowable_chars
4016 frozenset([' ', "'", ..., 'z'])
4017 >>> obj = PrintableString("foo*bar", allow_asterisk=True)
4018 PrintableString PrintableString foo*bar
4019 >>> obj.allow_asterisk, obj.allow_ampersand
4023 tag_default = tag_encode(19)
4025 asn1_type_name = "PrintableString"
4026 _allowable_chars = frozenset(
4027 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
4029 _asterisk = frozenset("*".encode("ascii"))
4030 _ampersand = frozenset("&".encode("ascii"))
4041 allow_asterisk=False,
4042 allow_ampersand=False,
4045 :param allow_asterisk: allow asterisk character
4046 :param allow_ampersand: allow ampersand character
4049 self._allowable_chars |= self._asterisk
4051 self._allowable_chars |= self._ampersand
4052 super(PrintableString, self).__init__(
4053 value, bounds, impl, expl, default, optional, _decoded,
4057 def allow_asterisk(self):
4058 """Is asterisk character allowed?
4060 return self._asterisk <= self._allowable_chars
4063 def allow_ampersand(self):
4064 """Is ampersand character allowed?
4066 return self._ampersand <= self._allowable_chars
4068 def _value_sanitize(self, value):
4069 value = super(PrintableString, self)._value_sanitize(value)
4070 if not frozenset(value) <= self._allowable_chars:
4071 raise DecodeError("non-printable value")
4074 def __getstate__(self):
4075 return PrintableStringState(
4076 *super(PrintableString, self).__getstate__(),
4077 **{"allowable_chars": self._allowable_chars}
4080 def __setstate__(self, state):
4081 super(PrintableString, self).__setstate__(state)
4082 self._allowable_chars = state.allowable_chars
4093 return self.__class__(
4096 (self._bound_min, self._bound_max)
4097 if bounds is None else bounds
4099 impl=self.tag if impl is None else impl,
4100 expl=self._expl if expl is None else expl,
4101 default=self.default if default is None else default,
4102 optional=self.optional if optional is None else optional,
4103 allow_asterisk=self.allow_asterisk,
4104 allow_ampersand=self.allow_ampersand,
4108 class TeletexString(CommonString):
4110 tag_default = tag_encode(20)
4112 asn1_type_name = "TeletexString"
4115 class T61String(TeletexString):
4117 asn1_type_name = "T61String"
4120 class VideotexString(CommonString):
4122 tag_default = tag_encode(21)
4123 encoding = "iso-8859-1"
4124 asn1_type_name = "VideotexString"
4127 class IA5String(CommonString):
4129 tag_default = tag_encode(22)
4131 asn1_type_name = "IA5"
4134 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
4135 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
4136 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
4139 class VisibleString(CommonString):
4141 tag_default = tag_encode(26)
4143 asn1_type_name = "VisibleString"
4146 class UTCTime(VisibleString):
4147 """``UTCTime`` datetime type
4149 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4150 UTCTime UTCTime 2017-09-30T22:07:50
4156 datetime.datetime(2017, 9, 30, 22, 7, 50)
4157 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
4158 datetime.datetime(1957, 9, 30, 22, 7, 50)
4162 BER encoding is unsupported.
4165 tag_default = tag_encode(23)
4167 asn1_type_name = "UTCTime"
4177 bounds=None, # dummy argument, workability for OctetString.decode
4180 :param value: set the value. Either datetime type, or
4181 :py:class:`pyderasn.UTCTime` object
4182 :param bytes impl: override default tag with ``IMPLICIT`` one
4183 :param bytes expl: override default tag with ``EXPLICIT`` one
4184 :param default: set default value. Type same as in ``value``
4185 :param bool optional: is object ``OPTIONAL`` in sequence
4187 super(UTCTime, self).__init__(
4188 None, None, impl, expl, default, optional, _decoded,
4191 if value is not None:
4192 self._value = self._value_sanitize(value)
4193 if default is not None:
4194 default = self._value_sanitize(default)
4195 self.default = self.__class__(
4200 if self._value is None:
4201 self._value = default
4203 def _strptime(self, value):
4204 # datetime.strptime's format: %y%m%d%H%M%SZ
4205 if len(value) != LEN_YYMMDDHHMMSSZ:
4206 raise ValueError("invalid UTCTime length")
4207 if value[-1] != "Z":
4208 raise ValueError("non UTC timezone")
4210 2000 + int(value[:2]), # %y
4211 int(value[2:4]), # %m
4212 int(value[4:6]), # %d
4213 int(value[6:8]), # %H
4214 int(value[8:10]), # %M
4215 int(value[10:12]), # %S
4218 def _value_sanitize(self, value):
4219 if isinstance(value, binary_type):
4221 value_decoded = value.decode("ascii")
4222 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4223 raise DecodeError("invalid UTCTime encoding: %r" % err)
4225 self._strptime(value_decoded)
4226 except (TypeError, ValueError) as err:
4227 raise DecodeError("invalid UTCTime format: %r" % err)
4229 if isinstance(value, self.__class__):
4231 if isinstance(value, datetime):
4232 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
4233 raise InvalidValueType((self.__class__, datetime))
4235 def __eq__(self, their):
4236 if isinstance(their, binary_type):
4237 return self._value == their
4238 if isinstance(their, datetime):
4239 return self.todatetime() == their
4240 if not isinstance(their, self.__class__):
4243 self._value == their._value and
4244 self.tag == their.tag and
4245 self._expl == their._expl
4248 def todatetime(self):
4249 """Convert to datetime
4253 Pay attention that UTCTime can not hold full year, so all years
4254 having < 50 years are treated as 20xx, 19xx otherwise, according
4255 to X.509 recomendation.
4257 value = self._strptime(self._value.decode("ascii"))
4258 year = value.year % 100
4260 year=(2000 + year) if year < 50 else (1900 + year),
4264 minute=value.minute,
4265 second=value.second,
4269 return pp_console_row(next(self.pps()))
4271 def pps(self, decode_path=()):
4274 asn1_type_name=self.asn1_type_name,
4275 obj_name=self.__class__.__name__,
4276 decode_path=decode_path,
4277 value=self.todatetime().isoformat() if self.ready else None,
4278 optional=self.optional,
4279 default=self == self.default,
4280 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4281 expl=None if self._expl is None else tag_decode(self._expl),
4286 expl_offset=self.expl_offset if self.expled else None,
4287 expl_tlen=self.expl_tlen if self.expled else None,
4288 expl_llen=self.expl_llen if self.expled else None,
4289 expl_vlen=self.expl_vlen if self.expled else None,
4290 expl_lenindef=self.expl_lenindef,
4291 ber_encoded=self.ber_encoded,
4294 for pp in self.pps_lenindef(decode_path):
4298 class GeneralizedTime(UTCTime):
4299 """``GeneralizedTime`` datetime type
4301 This type is similar to :py:class:`pyderasn.UTCTime`.
4303 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4304 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4306 '20170930220750.000123Z'
4307 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4308 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4312 BER encoding is unsupported.
4316 Only microsecond fractions are supported.
4317 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4318 higher precision values.
4322 Zero year is unsupported.
4325 tag_default = tag_encode(24)
4326 asn1_type_name = "GeneralizedTime"
4328 def _strptime(self, value):
4330 if l == LEN_YYYYMMDDHHMMSSZ:
4331 # datetime.strptime's format: %Y%m%d%H%M%SZ
4332 if value[-1] != "Z":
4333 raise ValueError("non UTC timezone")
4335 int(value[:4]), # %Y
4336 int(value[4:6]), # %m
4337 int(value[6:8]), # %d
4338 int(value[8:10]), # %H
4339 int(value[10:12]), # %M
4340 int(value[12:14]), # %S
4342 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4343 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4344 if value[-1] != "Z":
4345 raise ValueError("non UTC timezone")
4346 if value[14] != ".":
4347 raise ValueError("no fractions separator")
4350 raise ValueError("trailing zero")
4353 raise ValueError("only microsecond fractions are supported")
4354 us = int(us + ("0" * (6 - us_len)))
4356 int(value[:4]), # %Y
4357 int(value[4:6]), # %m
4358 int(value[6:8]), # %d
4359 int(value[8:10]), # %H
4360 int(value[10:12]), # %M
4361 int(value[12:14]), # %S
4365 raise ValueError("invalid GeneralizedTime length")
4367 def _value_sanitize(self, value):
4368 if isinstance(value, binary_type):
4370 value_decoded = value.decode("ascii")
4371 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4372 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4374 self._strptime(value_decoded)
4375 except (TypeError, ValueError) as err:
4377 "invalid GeneralizedTime format: %r" % err,
4378 klass=self.__class__,
4381 if isinstance(value, self.__class__):
4383 if isinstance(value, datetime):
4384 encoded = value.strftime("%Y%m%d%H%M%S")
4385 if value.microsecond > 0:
4386 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4387 return (encoded + "Z").encode("ascii")
4388 raise InvalidValueType((self.__class__, datetime))
4390 def todatetime(self):
4391 return self._strptime(self._value.decode("ascii"))
4394 class GraphicString(CommonString):
4396 tag_default = tag_encode(25)
4397 encoding = "iso-8859-1"
4398 asn1_type_name = "GraphicString"
4401 class ISO646String(VisibleString):
4403 asn1_type_name = "ISO646String"
4406 class GeneralString(CommonString):
4408 tag_default = tag_encode(27)
4409 encoding = "iso-8859-1"
4410 asn1_type_name = "GeneralString"
4413 class UniversalString(CommonString):
4415 tag_default = tag_encode(28)
4416 encoding = "utf-32-be"
4417 asn1_type_name = "UniversalString"
4420 class BMPString(CommonString):
4422 tag_default = tag_encode(30)
4423 encoding = "utf-16-be"
4424 asn1_type_name = "BMPString"
4427 ChoiceState = namedtuple("ChoiceState", (
4445 """``CHOICE`` special type
4449 class GeneralName(Choice):
4451 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4452 ("dNSName", IA5String(impl=tag_ctxp(2))),
4455 >>> gn = GeneralName()
4457 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4458 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4459 >>> gn["dNSName"] = IA5String("bar.baz")
4460 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4461 >>> gn["rfc822Name"]
4464 [2] IA5String IA5 bar.baz
4467 >>> gn.value == gn["dNSName"]
4470 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4472 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4473 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4475 __slots__ = ("specs",)
4477 asn1_type_name = "CHOICE"
4490 :param value: set the value. Either ``(choice, value)`` tuple, or
4491 :py:class:`pyderasn.Choice` object
4492 :param bytes impl: can not be set, do **not** use it
4493 :param bytes expl: override default tag with ``EXPLICIT`` one
4494 :param default: set default value. Type same as in ``value``
4495 :param bool optional: is object ``OPTIONAL`` in sequence
4497 if impl is not None:
4498 raise ValueError("no implicit tag allowed for CHOICE")
4499 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4501 schema = getattr(self, "schema", ())
4502 if len(schema) == 0:
4503 raise ValueError("schema must be specified")
4505 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4508 if value is not None:
4509 self._value = self._value_sanitize(value)
4510 if default is not None:
4511 default_value = self._value_sanitize(default)
4512 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4513 default_obj.specs = self.specs
4514 default_obj._value = default_value
4515 self.default = default_obj
4517 self._value = copy(default_obj._value)
4519 def _value_sanitize(self, value):
4520 if isinstance(value, tuple) and len(value) == 2:
4522 spec = self.specs.get(choice)
4524 raise ObjUnknown(choice)
4525 if not isinstance(obj, spec.__class__):
4526 raise InvalidValueType((spec,))
4527 return (choice, spec(obj))
4528 if isinstance(value, self.__class__):
4530 raise InvalidValueType((self.__class__, tuple))
4534 return self._value is not None and self._value[1].ready
4538 return self.expl_lenindef or (
4539 (self._value is not None) and
4540 self._value[1].bered
4543 def __getstate__(self):
4560 def __setstate__(self, state):
4561 super(Choice, self).__setstate__(state)
4562 self.specs = state.specs
4563 self._value = state.value
4564 self._expl = state.expl
4565 self.default = state.default
4566 self.optional = state.optional
4567 self.offset = state.offset
4568 self.llen = state.llen
4569 self.vlen = state.vlen
4570 self.expl_lenindef = state.expl_lenindef
4571 self.lenindef = state.lenindef
4572 self.ber_encoded = state.ber_encoded
4574 def __eq__(self, their):
4575 if isinstance(their, tuple) and len(their) == 2:
4576 return self._value == their
4577 if not isinstance(their, self.__class__):
4580 self.specs == their.specs and
4581 self._value == their._value
4591 return self.__class__(
4594 expl=self._expl if expl is None else expl,
4595 default=self.default if default is None else default,
4596 optional=self.optional if optional is None else optional,
4601 self._assert_ready()
4602 return self._value[0]
4606 self._assert_ready()
4607 return self._value[1]
4609 def __getitem__(self, key):
4610 if key not in self.specs:
4611 raise ObjUnknown(key)
4612 if self._value is None:
4614 choice, value = self._value
4619 def __setitem__(self, key, value):
4620 spec = self.specs.get(key)
4622 raise ObjUnknown(key)
4623 if not isinstance(value, spec.__class__):
4624 raise InvalidValueType((spec.__class__,))
4625 self._value = (key, spec(value))
4633 return self._value[1].decoded if self.ready else False
4636 self._assert_ready()
4637 return self._value[1].encode()
4639 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4640 for choice, spec in iteritems(self.specs):
4641 sub_decode_path = decode_path + (choice,)
4647 decode_path=sub_decode_path,
4650 _ctx_immutable=False,
4657 klass=self.__class__,
4658 decode_path=decode_path,
4661 if tag_only: # pragma: no cover
4663 value, tail = spec.decode(
4667 decode_path=sub_decode_path,
4669 _ctx_immutable=False,
4671 obj = self.__class__(
4674 default=self.default,
4675 optional=self.optional,
4676 _decoded=(offset, 0, value.fulllen),
4678 obj._value = (choice, value)
4682 value = pp_console_row(next(self.pps()))
4684 value = "%s[%r]" % (value, self.value)
4687 def pps(self, decode_path=()):
4690 asn1_type_name=self.asn1_type_name,
4691 obj_name=self.__class__.__name__,
4692 decode_path=decode_path,
4693 value=self.choice if self.ready else None,
4694 optional=self.optional,
4695 default=self == self.default,
4696 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4697 expl=None if self._expl is None else tag_decode(self._expl),
4702 expl_lenindef=self.expl_lenindef,
4706 yield self.value.pps(decode_path=decode_path + (self.choice,))
4707 for pp in self.pps_lenindef(decode_path):
4711 class PrimitiveTypes(Choice):
4712 """Predefined ``CHOICE`` for all generic primitive types
4714 It could be useful for general decoding of some unspecified values:
4716 >>> PrimitiveTypes().decod(hexdec("0403666f6f")).value
4717 OCTET STRING 3 bytes 666f6f
4718 >>> PrimitiveTypes().decod(hexdec("0203123456")).value
4722 schema = tuple((klass.__name__, klass()) for klass in (
4746 AnyState = namedtuple("AnyState", (
4763 """``ANY`` special type
4765 >>> Any(Integer(-123))
4767 >>> a = Any(OctetString(b"hello world").encode())
4768 ANY 040b68656c6c6f20776f726c64
4769 >>> hexenc(bytes(a))
4770 b'0x040x0bhello world'
4772 __slots__ = ("defined",)
4773 tag_default = tag_encode(0)
4774 asn1_type_name = "ANY"
4784 :param value: set the value. Either any kind of pyderasn's
4785 **ready** object, or bytes. Pay attention that
4786 **no** validation is performed is raw binary value
4788 :param bytes expl: override default tag with ``EXPLICIT`` one
4789 :param bool optional: is object ``OPTIONAL`` in sequence
4791 super(Any, self).__init__(None, expl, None, optional, _decoded)
4792 self._value = None if value is None else self._value_sanitize(value)
4795 def _value_sanitize(self, value):
4796 if isinstance(value, binary_type):
4798 if isinstance(value, self.__class__):
4800 if isinstance(value, Obj):
4801 return value.encode()
4802 raise InvalidValueType((self.__class__, Obj, binary_type))
4806 return self._value is not None
4810 if self.expl_lenindef or self.lenindef:
4812 if self.defined is None:
4814 return self.defined[1].bered
4816 def __getstate__(self):
4832 def __setstate__(self, state):
4833 super(Any, self).__setstate__(state)
4834 self._value = state.value
4835 self.tag = state.tag
4836 self._expl = state.expl
4837 self.optional = state.optional
4838 self.offset = state.offset
4839 self.llen = state.llen
4840 self.vlen = state.vlen
4841 self.expl_lenindef = state.expl_lenindef
4842 self.lenindef = state.lenindef
4843 self.ber_encoded = state.ber_encoded
4844 self.defined = state.defined
4846 def __eq__(self, their):
4847 if isinstance(their, binary_type):
4848 return self._value == their
4849 if issubclass(their.__class__, Any):
4850 return self._value == their._value
4859 return self.__class__(
4861 expl=self._expl if expl is None else expl,
4862 optional=self.optional if optional is None else optional,
4865 def __bytes__(self):
4866 self._assert_ready()
4874 self._assert_ready()
4877 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4879 t, tlen, lv = tag_strip(tlv)
4880 except DecodeError as err:
4881 raise err.__class__(
4883 klass=self.__class__,
4884 decode_path=decode_path,
4888 l, llen, v = len_decode(lv)
4889 except LenIndefForm as err:
4890 if not ctx.get("bered", False):
4891 raise err.__class__(
4893 klass=self.__class__,
4894 decode_path=decode_path,
4897 llen, vlen, v = 1, 0, lv[1:]
4898 sub_offset = offset + tlen + llen
4900 while v[:EOC_LEN].tobytes() != EOC:
4901 chunk, v = Any().decode(
4904 decode_path=decode_path + (str(chunk_i),),
4907 _ctx_immutable=False,
4909 vlen += chunk.tlvlen
4910 sub_offset += chunk.tlvlen
4912 tlvlen = tlen + llen + vlen + EOC_LEN
4913 obj = self.__class__(
4914 value=tlv[:tlvlen].tobytes(),
4916 optional=self.optional,
4917 _decoded=(offset, 0, tlvlen),
4920 obj.tag = t.tobytes()
4921 return obj, v[EOC_LEN:]
4922 except DecodeError as err:
4923 raise err.__class__(
4925 klass=self.__class__,
4926 decode_path=decode_path,
4930 raise NotEnoughData(
4931 "encoded length is longer than data",
4932 klass=self.__class__,
4933 decode_path=decode_path,
4936 tlvlen = tlen + llen + l
4937 v, tail = tlv[:tlvlen], v[l:]
4938 obj = self.__class__(
4941 optional=self.optional,
4942 _decoded=(offset, 0, tlvlen),
4944 obj.tag = t.tobytes()
4948 return pp_console_row(next(self.pps()))
4950 def pps(self, decode_path=()):
4953 asn1_type_name=self.asn1_type_name,
4954 obj_name=self.__class__.__name__,
4955 decode_path=decode_path,
4956 blob=self._value if self.ready else None,
4957 optional=self.optional,
4958 default=self == self.default,
4959 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4960 expl=None if self._expl is None else tag_decode(self._expl),
4965 expl_offset=self.expl_offset if self.expled else None,
4966 expl_tlen=self.expl_tlen if self.expled else None,
4967 expl_llen=self.expl_llen if self.expled else None,
4968 expl_vlen=self.expl_vlen if self.expled else None,
4969 expl_lenindef=self.expl_lenindef,
4970 lenindef=self.lenindef,
4973 defined_by, defined = self.defined or (None, None)
4974 if defined_by is not None:
4976 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4978 for pp in self.pps_lenindef(decode_path):
4982 ########################################################################
4983 # ASN.1 constructed types
4984 ########################################################################
4986 def get_def_by_path(defines_by_path, sub_decode_path):
4987 """Get define by decode path
4989 for path, define in defines_by_path:
4990 if len(path) != len(sub_decode_path):
4992 for p1, p2 in zip(path, sub_decode_path):
4993 if (p1 != any) and (p1 != p2):
4999 def abs_decode_path(decode_path, rel_path):
5000 """Create an absolute decode path from current and relative ones
5002 :param decode_path: current decode path, starting point. Tuple of strings
5003 :param rel_path: relative path to ``decode_path``. Tuple of strings.
5004 If first tuple's element is "/", then treat it as
5005 an absolute path, ignoring ``decode_path`` as
5006 starting point. Also this tuple can contain ".."
5007 elements, stripping the leading element from
5010 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
5011 ("foo", "bar", "baz", "whatever")
5012 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
5014 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
5017 if rel_path[0] == "/":
5019 if rel_path[0] == "..":
5020 return abs_decode_path(decode_path[:-1], rel_path[1:])
5021 return decode_path + rel_path
5024 SequenceState = namedtuple("SequenceState", (
5041 class Sequence(Obj):
5042 """``SEQUENCE`` structure type
5044 You have to make specification of sequence::
5046 class Extension(Sequence):
5048 ("extnID", ObjectIdentifier()),
5049 ("critical", Boolean(default=False)),
5050 ("extnValue", OctetString()),
5053 Then, you can work with it as with dictionary.
5055 >>> ext = Extension()
5056 >>> Extension().specs
5058 ('extnID', OBJECT IDENTIFIER),
5059 ('critical', BOOLEAN False OPTIONAL DEFAULT),
5060 ('extnValue', OCTET STRING),
5062 >>> ext["extnID"] = "1.2.3"
5063 Traceback (most recent call last):
5064 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
5065 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
5067 You can determine if sequence is ready to be encoded:
5072 Traceback (most recent call last):
5073 pyderasn.ObjNotReady: object is not ready: extnValue
5074 >>> ext["extnValue"] = OctetString(b"foobar")
5078 Value you want to assign, must have the same **type** as in
5079 corresponding specification, but it can have different tags,
5080 optional/default attributes -- they will be taken from specification
5083 class TBSCertificate(Sequence):
5085 ("version", Version(expl=tag_ctxc(0), default="v1")),
5088 >>> tbs = TBSCertificate()
5089 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
5091 Assign ``None`` to remove value from sequence.
5093 You can set values in Sequence during its initialization:
5095 >>> AlgorithmIdentifier((
5096 ("algorithm", ObjectIdentifier("1.2.3")),
5097 ("parameters", Any(Null()))
5099 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
5101 You can determine if value exists/set in the sequence and take its value:
5103 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
5106 OBJECT IDENTIFIER 1.2.3
5108 But pay attention that if value has default, then it won't be (not
5109 in) in the sequence (because ``DEFAULT`` must not be encoded in
5110 DER), but you can read its value:
5112 >>> "critical" in ext, ext["critical"]
5113 (False, BOOLEAN False)
5114 >>> ext["critical"] = Boolean(True)
5115 >>> "critical" in ext, ext["critical"]
5116 (True, BOOLEAN True)
5118 All defaulted values are always optional.
5120 .. _allow_default_values_ctx:
5122 DER prohibits default value encoding and will raise an error if
5123 default value is unexpectedly met during decode.
5124 If :ref:`bered <bered_ctx>` context option is set, then no error
5125 will be raised, but ``bered`` attribute set. You can disable strict
5126 defaulted values existence validation by setting
5127 ``"allow_default_values": True`` :ref:`context <ctx>` option.
5129 Two sequences are equal if they have equal specification (schema),
5130 implicit/explicit tagging and the same values.
5132 __slots__ = ("specs",)
5133 tag_default = tag_encode(form=TagFormConstructed, num=16)
5134 asn1_type_name = "SEQUENCE"
5146 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
5148 schema = getattr(self, "schema", ())
5150 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
5153 if value is not None:
5154 if issubclass(value.__class__, Sequence):
5155 self._value = value._value
5156 elif hasattr(value, "__iter__"):
5157 for seq_key, seq_value in value:
5158 self[seq_key] = seq_value
5160 raise InvalidValueType((Sequence,))
5161 if default is not None:
5162 if not issubclass(default.__class__, Sequence):
5163 raise InvalidValueType((Sequence,))
5164 default_value = default._value
5165 default_obj = self.__class__(impl=self.tag, expl=self._expl)
5166 default_obj.specs = self.specs
5167 default_obj._value = default_value
5168 self.default = default_obj
5170 self._value = copy(default_obj._value)
5174 for name, spec in iteritems(self.specs):
5175 value = self._value.get(name)
5186 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5188 return any(value.bered for value in itervalues(self._value))
5190 def __getstate__(self):
5191 return SequenceState(
5194 {k: copy(v) for k, v in iteritems(self._value)},
5207 def __setstate__(self, state):
5208 super(Sequence, self).__setstate__(state)
5209 self.specs = state.specs
5210 self._value = state.value
5211 self.tag = state.tag
5212 self._expl = state.expl
5213 self.default = state.default
5214 self.optional = state.optional
5215 self.offset = state.offset
5216 self.llen = state.llen
5217 self.vlen = state.vlen
5218 self.expl_lenindef = state.expl_lenindef
5219 self.lenindef = state.lenindef
5220 self.ber_encoded = state.ber_encoded
5222 def __eq__(self, their):
5223 if not isinstance(their, self.__class__):
5226 self.specs == their.specs and
5227 self.tag == their.tag and
5228 self._expl == their._expl and
5229 self._value == their._value
5240 return self.__class__(
5243 impl=self.tag if impl is None else impl,
5244 expl=self._expl if expl is None else expl,
5245 default=self.default if default is None else default,
5246 optional=self.optional if optional is None else optional,
5249 def __contains__(self, key):
5250 return key in self._value
5252 def __setitem__(self, key, value):
5253 spec = self.specs.get(key)
5255 raise ObjUnknown(key)
5257 self._value.pop(key, None)
5259 if not isinstance(value, spec.__class__):
5260 raise InvalidValueType((spec.__class__,))
5261 value = spec(value=value)
5262 if spec.default is not None and value == spec.default:
5263 self._value.pop(key, None)
5265 self._value[key] = value
5267 def __getitem__(self, key):
5268 value = self._value.get(key)
5269 if value is not None:
5271 spec = self.specs.get(key)
5273 raise ObjUnknown(key)
5274 if spec.default is not None:
5278 def _encoded_values(self):
5280 for name, spec in iteritems(self.specs):
5281 value = self._value.get(name)
5285 raise ObjNotReady(name)
5286 raws.append(value.encode())
5290 v = b"".join(self._encoded_values())
5291 return b"".join((self.tag, len_encode(len(v)), v))
5293 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5295 t, tlen, lv = tag_strip(tlv)
5296 except DecodeError as err:
5297 raise err.__class__(
5299 klass=self.__class__,
5300 decode_path=decode_path,
5305 klass=self.__class__,
5306 decode_path=decode_path,
5309 if tag_only: # pragma: no cover
5312 ctx_bered = ctx.get("bered", False)
5314 l, llen, v = len_decode(lv)
5315 except LenIndefForm as err:
5317 raise err.__class__(
5319 klass=self.__class__,
5320 decode_path=decode_path,
5323 l, llen, v = 0, 1, lv[1:]
5325 except DecodeError as err:
5326 raise err.__class__(
5328 klass=self.__class__,
5329 decode_path=decode_path,
5333 raise NotEnoughData(
5334 "encoded length is longer than data",
5335 klass=self.__class__,
5336 decode_path=decode_path,
5340 v, tail = v[:l], v[l:]
5342 sub_offset = offset + tlen + llen
5345 ctx_allow_default_values = ctx.get("allow_default_values", False)
5346 for name, spec in iteritems(self.specs):
5347 if spec.optional and (
5348 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
5352 sub_decode_path = decode_path + (name,)
5354 value, v_tail = spec.decode(
5358 decode_path=sub_decode_path,
5360 _ctx_immutable=False,
5362 except TagMismatch as err:
5363 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5367 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5368 if defined is not None:
5369 defined_by, defined_spec = defined
5370 if issubclass(value.__class__, SequenceOf):
5371 for i, _value in enumerate(value):
5372 sub_sub_decode_path = sub_decode_path + (
5374 DecodePathDefBy(defined_by),
5376 defined_value, defined_tail = defined_spec.decode(
5377 memoryview(bytes(_value)),
5379 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5380 if value.expled else (value.tlen + value.llen)
5383 decode_path=sub_sub_decode_path,
5385 _ctx_immutable=False,
5387 if len(defined_tail) > 0:
5390 klass=self.__class__,
5391 decode_path=sub_sub_decode_path,
5394 _value.defined = (defined_by, defined_value)
5396 defined_value, defined_tail = defined_spec.decode(
5397 memoryview(bytes(value)),
5399 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5400 if value.expled else (value.tlen + value.llen)
5403 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5405 _ctx_immutable=False,
5407 if len(defined_tail) > 0:
5410 klass=self.__class__,
5411 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5414 value.defined = (defined_by, defined_value)
5416 value_len = value.fulllen
5418 sub_offset += value_len
5420 if spec.default is not None and value == spec.default:
5421 if ctx_bered or ctx_allow_default_values:
5425 "DEFAULT value met",
5426 klass=self.__class__,
5427 decode_path=sub_decode_path,
5430 values[name] = value
5432 spec_defines = getattr(spec, "defines", ())
5433 if len(spec_defines) == 0:
5434 defines_by_path = ctx.get("defines_by_path", ())
5435 if len(defines_by_path) > 0:
5436 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5437 if spec_defines is not None and len(spec_defines) > 0:
5438 for rel_path, schema in spec_defines:
5439 defined = schema.get(value, None)
5440 if defined is not None:
5441 ctx.setdefault("_defines", []).append((
5442 abs_decode_path(sub_decode_path[:-1], rel_path),
5446 if v[:EOC_LEN].tobytes() != EOC:
5449 klass=self.__class__,
5450 decode_path=decode_path,
5458 klass=self.__class__,
5459 decode_path=decode_path,
5462 obj = self.__class__(
5466 default=self.default,
5467 optional=self.optional,
5468 _decoded=(offset, llen, vlen),
5471 obj.lenindef = lenindef
5472 obj.ber_encoded = ber_encoded
5476 value = pp_console_row(next(self.pps()))
5478 for name in self.specs:
5479 _value = self._value.get(name)
5482 cols.append("%s: %s" % (name, repr(_value)))
5483 return "%s[%s]" % (value, "; ".join(cols))
5485 def pps(self, decode_path=()):
5488 asn1_type_name=self.asn1_type_name,
5489 obj_name=self.__class__.__name__,
5490 decode_path=decode_path,
5491 optional=self.optional,
5492 default=self == self.default,
5493 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5494 expl=None if self._expl is None else tag_decode(self._expl),
5499 expl_offset=self.expl_offset if self.expled else None,
5500 expl_tlen=self.expl_tlen if self.expled else None,
5501 expl_llen=self.expl_llen if self.expled else None,
5502 expl_vlen=self.expl_vlen if self.expled else None,
5503 expl_lenindef=self.expl_lenindef,
5504 lenindef=self.lenindef,
5505 ber_encoded=self.ber_encoded,
5508 for name in self.specs:
5509 value = self._value.get(name)
5512 yield value.pps(decode_path=decode_path + (name,))
5513 for pp in self.pps_lenindef(decode_path):
5517 class Set(Sequence):
5518 """``SET`` structure type
5520 Its usage is identical to :py:class:`pyderasn.Sequence`.
5522 .. _allow_unordered_set_ctx:
5524 DER prohibits unordered values encoding and will raise an error
5525 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5526 then no error will occure. Also you can disable strict values
5527 ordering check by setting ``"allow_unordered_set": True``
5528 :ref:`context <ctx>` option.
5531 tag_default = tag_encode(form=TagFormConstructed, num=17)
5532 asn1_type_name = "SET"
5535 raws = self._encoded_values()
5538 return b"".join((self.tag, len_encode(len(v)), v))
5540 def _specs_items(self):
5541 return iteritems(self.specs)
5543 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5545 t, tlen, lv = tag_strip(tlv)
5546 except DecodeError as err:
5547 raise err.__class__(
5549 klass=self.__class__,
5550 decode_path=decode_path,
5555 klass=self.__class__,
5556 decode_path=decode_path,
5562 ctx_bered = ctx.get("bered", False)
5564 l, llen, v = len_decode(lv)
5565 except LenIndefForm as err:
5567 raise err.__class__(
5569 klass=self.__class__,
5570 decode_path=decode_path,
5573 l, llen, v = 0, 1, lv[1:]
5575 except DecodeError as err:
5576 raise err.__class__(
5578 klass=self.__class__,
5579 decode_path=decode_path,
5583 raise NotEnoughData(
5584 "encoded length is longer than data",
5585 klass=self.__class__,
5589 v, tail = v[:l], v[l:]
5591 sub_offset = offset + tlen + llen
5594 ctx_allow_default_values = ctx.get("allow_default_values", False)
5595 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5596 value_prev = memoryview(v[:0])
5599 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5601 for name, spec in self._specs_items():
5602 sub_decode_path = decode_path + (name,)
5608 decode_path=sub_decode_path,
5611 _ctx_immutable=False,
5618 klass=self.__class__,
5619 decode_path=decode_path,
5622 value, v_tail = spec.decode(
5626 decode_path=sub_decode_path,
5628 _ctx_immutable=False,
5630 value_len = value.fulllen
5631 if value_prev.tobytes() > v[:value_len].tobytes():
5632 if ctx_bered or ctx_allow_unordered_set:
5636 "unordered " + self.asn1_type_name,
5637 klass=self.__class__,
5638 decode_path=sub_decode_path,
5641 if spec.default is None or value != spec.default:
5643 elif ctx_bered or ctx_allow_default_values:
5647 "DEFAULT value met",
5648 klass=self.__class__,
5649 decode_path=sub_decode_path,
5652 values[name] = value
5653 value_prev = v[:value_len]
5654 sub_offset += value_len
5657 obj = self.__class__(
5661 default=self.default,
5662 optional=self.optional,
5663 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5666 if v[:EOC_LEN].tobytes() != EOC:
5669 klass=self.__class__,
5670 decode_path=decode_path,
5678 "not all values are ready",
5679 klass=self.__class__,
5680 decode_path=decode_path,
5683 obj.ber_encoded = ber_encoded
5687 SequenceOfState = namedtuple("SequenceOfState", (
5706 class SequenceOf(Obj):
5707 """``SEQUENCE OF`` sequence type
5709 For that kind of type you must specify the object it will carry on
5710 (bounds are for example here, not required)::
5712 class Ints(SequenceOf):
5717 >>> ints.append(Integer(123))
5718 >>> ints.append(Integer(234))
5720 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5721 >>> [int(i) for i in ints]
5723 >>> ints.append(Integer(345))
5724 Traceback (most recent call last):
5725 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5728 >>> ints[1] = Integer(345)
5730 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5732 Also you can initialize sequence with preinitialized values:
5734 >>> ints = Ints([Integer(123), Integer(234)])
5736 __slots__ = ("spec", "_bound_min", "_bound_max")
5737 tag_default = tag_encode(form=TagFormConstructed, num=16)
5738 asn1_type_name = "SEQUENCE OF"
5751 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5753 schema = getattr(self, "schema", None)
5755 raise ValueError("schema must be specified")
5757 self._bound_min, self._bound_max = getattr(
5761 ) if bounds is None else bounds
5763 if value is not None:
5764 self._value = self._value_sanitize(value)
5765 if default is not None:
5766 default_value = self._value_sanitize(default)
5767 default_obj = self.__class__(
5772 default_obj._value = default_value
5773 self.default = default_obj
5775 self._value = copy(default_obj._value)
5777 def _value_sanitize(self, value):
5778 if issubclass(value.__class__, SequenceOf):
5779 value = value._value
5780 elif hasattr(value, "__iter__"):
5783 raise InvalidValueType((self.__class__, iter))
5784 if not self._bound_min <= len(value) <= self._bound_max:
5785 raise BoundsError(self._bound_min, len(value), self._bound_max)
5787 if not isinstance(v, self.spec.__class__):
5788 raise InvalidValueType((self.spec.__class__,))
5793 return all(v.ready for v in self._value)
5797 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5799 return any(v.bered for v in self._value)
5801 def __getstate__(self):
5802 return SequenceOfState(
5805 [copy(v) for v in self._value],
5820 def __setstate__(self, state):
5821 super(SequenceOf, self).__setstate__(state)
5822 self.spec = state.spec
5823 self._value = state.value
5824 self._bound_min = state.bound_min
5825 self._bound_max = state.bound_max
5826 self.tag = state.tag
5827 self._expl = state.expl
5828 self.default = state.default
5829 self.optional = state.optional
5830 self.offset = state.offset
5831 self.llen = state.llen
5832 self.vlen = state.vlen
5833 self.expl_lenindef = state.expl_lenindef
5834 self.lenindef = state.lenindef
5835 self.ber_encoded = state.ber_encoded
5837 def __eq__(self, their):
5838 if isinstance(their, self.__class__):
5840 self.spec == their.spec and
5841 self.tag == their.tag and
5842 self._expl == their._expl and
5843 self._value == their._value
5845 if hasattr(their, "__iter__"):
5846 return self._value == list(their)
5858 return self.__class__(
5862 (self._bound_min, self._bound_max)
5863 if bounds is None else bounds
5865 impl=self.tag if impl is None else impl,
5866 expl=self._expl if expl is None else expl,
5867 default=self.default if default is None else default,
5868 optional=self.optional if optional is None else optional,
5871 def __contains__(self, key):
5872 return key in self._value
5874 def append(self, value):
5875 if not isinstance(value, self.spec.__class__):
5876 raise InvalidValueType((self.spec.__class__,))
5877 if len(self._value) + 1 > self._bound_max:
5880 len(self._value) + 1,
5883 self._value.append(value)
5886 self._assert_ready()
5887 return iter(self._value)
5890 self._assert_ready()
5891 return len(self._value)
5893 def __setitem__(self, key, value):
5894 if not isinstance(value, self.spec.__class__):
5895 raise InvalidValueType((self.spec.__class__,))
5896 self._value[key] = self.spec(value=value)
5898 def __getitem__(self, key):
5899 return self._value[key]
5901 def _encoded_values(self):
5902 return [v.encode() for v in self._value]
5905 v = b"".join(self._encoded_values())
5906 return b"".join((self.tag, len_encode(len(v)), v))
5908 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5910 t, tlen, lv = tag_strip(tlv)
5911 except DecodeError as err:
5912 raise err.__class__(
5914 klass=self.__class__,
5915 decode_path=decode_path,
5920 klass=self.__class__,
5921 decode_path=decode_path,
5927 ctx_bered = ctx.get("bered", False)
5929 l, llen, v = len_decode(lv)
5930 except LenIndefForm as err:
5932 raise err.__class__(
5934 klass=self.__class__,
5935 decode_path=decode_path,
5938 l, llen, v = 0, 1, lv[1:]
5940 except DecodeError as err:
5941 raise err.__class__(
5943 klass=self.__class__,
5944 decode_path=decode_path,
5948 raise NotEnoughData(
5949 "encoded length is longer than data",
5950 klass=self.__class__,
5951 decode_path=decode_path,
5955 v, tail = v[:l], v[l:]
5957 sub_offset = offset + tlen + llen
5959 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5960 value_prev = memoryview(v[:0])
5964 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5966 sub_decode_path = decode_path + (str(len(_value)),)
5967 value, v_tail = spec.decode(
5971 decode_path=sub_decode_path,
5973 _ctx_immutable=False,
5975 value_len = value.fulllen
5977 if value_prev.tobytes() > v[:value_len].tobytes():
5978 if ctx_bered or ctx_allow_unordered_set:
5982 "unordered " + self.asn1_type_name,
5983 klass=self.__class__,
5984 decode_path=sub_decode_path,
5987 value_prev = v[:value_len]
5988 _value.append(value)
5989 sub_offset += value_len
5993 obj = self.__class__(
5996 bounds=(self._bound_min, self._bound_max),
5999 default=self.default,
6000 optional=self.optional,
6001 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
6003 except BoundsError as err:
6006 klass=self.__class__,
6007 decode_path=decode_path,
6011 if v[:EOC_LEN].tobytes() != EOC:
6014 klass=self.__class__,
6015 decode_path=decode_path,
6020 obj.ber_encoded = ber_encoded
6025 pp_console_row(next(self.pps())),
6026 ", ".join(repr(v) for v in self._value),
6029 def pps(self, decode_path=()):
6032 asn1_type_name=self.asn1_type_name,
6033 obj_name=self.__class__.__name__,
6034 decode_path=decode_path,
6035 optional=self.optional,
6036 default=self == self.default,
6037 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
6038 expl=None if self._expl is None else tag_decode(self._expl),
6043 expl_offset=self.expl_offset if self.expled else None,
6044 expl_tlen=self.expl_tlen if self.expled else None,
6045 expl_llen=self.expl_llen if self.expled else None,
6046 expl_vlen=self.expl_vlen if self.expled else None,
6047 expl_lenindef=self.expl_lenindef,
6048 lenindef=self.lenindef,
6049 ber_encoded=self.ber_encoded,
6052 for i, value in enumerate(self._value):
6053 yield value.pps(decode_path=decode_path + (str(i),))
6054 for pp in self.pps_lenindef(decode_path):
6058 class SetOf(SequenceOf):
6059 """``SET OF`` sequence type
6061 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
6064 tag_default = tag_encode(form=TagFormConstructed, num=17)
6065 asn1_type_name = "SET OF"
6068 raws = self._encoded_values()
6071 return b"".join((self.tag, len_encode(len(v)), v))
6073 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
6074 return super(SetOf, self)._decode(
6080 ordering_check=True,
6084 def obj_by_path(pypath): # pragma: no cover
6085 """Import object specified as string Python path
6087 Modules must be separated from classes/functions with ``:``.
6089 >>> obj_by_path("foo.bar:Baz")
6090 <class 'foo.bar.Baz'>
6091 >>> obj_by_path("foo.bar:Baz.boo")
6092 <classmethod 'foo.bar.Baz.boo'>
6094 mod, objs = pypath.rsplit(":", 1)
6095 from importlib import import_module
6096 obj = import_module(mod)
6097 for obj_name in objs.split("."):
6098 obj = getattr(obj, obj_name)
6102 def generic_decoder(): # pragma: no cover
6103 # All of this below is a big hack with self references
6104 choice = PrimitiveTypes()
6105 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
6106 choice.specs["SetOf"] = SetOf(schema=choice)
6107 for i in six_xrange(31):
6108 choice.specs["SequenceOf%d" % i] = SequenceOf(
6112 choice.specs["Any"] = Any()
6114 # Class name equals to type name, to omit it from output
6115 class SEQUENCEOF(SequenceOf):
6123 with_decode_path=False,
6124 decode_path_only=(),
6126 def _pprint_pps(pps):
6128 if hasattr(pp, "_fields"):
6130 decode_path_only != () and
6131 pp.decode_path[:len(decode_path_only)] != decode_path_only
6134 if pp.asn1_type_name == Choice.asn1_type_name:
6136 pp_kwargs = pp._asdict()
6137 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
6138 pp = _pp(**pp_kwargs)
6139 yield pp_console_row(
6144 with_colours=with_colours,
6145 with_decode_path=with_decode_path,
6146 decode_path_len_decrease=len(decode_path_only),
6148 for row in pp_console_blob(
6150 decode_path_len_decrease=len(decode_path_only),
6154 for row in _pprint_pps(pp):
6156 return "\n".join(_pprint_pps(obj.pps()))
6157 return SEQUENCEOF(), pprint_any
6160 def main(): # pragma: no cover
6162 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
6163 parser.add_argument(
6167 help="Skip that number of bytes from the beginning",
6169 parser.add_argument(
6171 help="Python paths to dictionary with OIDs, comma separated",
6173 parser.add_argument(
6175 help="Python path to schema definition to use",
6177 parser.add_argument(
6178 "--defines-by-path",
6179 help="Python path to decoder's defines_by_path",
6181 parser.add_argument(
6183 action="store_true",
6184 help="Disallow BER encoding",
6186 parser.add_argument(
6187 "--print-decode-path",
6188 action="store_true",
6189 help="Print decode paths",
6191 parser.add_argument(
6192 "--decode-path-only",
6193 help="Print only specified decode path",
6195 parser.add_argument(
6197 action="store_true",
6198 help="Allow explicit tag out-of-bound",
6200 parser.add_argument(
6202 type=argparse.FileType("rb"),
6203 help="Path to DER file you want to decode",
6205 args = parser.parse_args()
6206 args.DERFile.seek(args.skip)
6207 der = memoryview(args.DERFile.read())
6208 args.DERFile.close()
6210 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
6211 if args.oids else ()
6214 schema = obj_by_path(args.schema)
6215 from functools import partial
6216 pprinter = partial(pprint, big_blobs=True)
6218 schema, pprinter = generic_decoder()
6220 "bered": not args.nobered,
6221 "allow_expl_oob": args.allow_expl_oob,
6223 if args.defines_by_path is not None:
6224 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
6225 obj, tail = schema().decode(der, ctx=ctx)
6229 with_colours=environ.get("NO_COLOR") is None,
6230 with_decode_path=args.print_decode_path,
6232 () if args.decode_path_only is None else
6233 tuple(args.decode_path_only.split(":"))
6237 print("\nTrailing data: %s" % hexenc(tail))
6240 if __name__ == "__main__":