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().decode(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 ``impl`` keyword argument), or
69 ``EXPLICIT`` one (using ``expl`` keyword argument). Both arguments take
70 raw binary string, containing that tag. You can **not** set implicit and
71 explicit tags simultaneously.
73 There are :py:func:`pyderasn.tag_ctxp` and :py:func:`pyderasn.tag_ctxc`
74 functions, allowing you to easily create ``CONTEXT``
75 ``PRIMITIVE``/``CONSTRUCTED`` tags, by specifying only the required tag
76 number. Pay attention that explicit tags always have *constructed* tag
77 (``tag_ctxc``), but implicit tags for primitive types are primitive
82 >>> Integer(impl=tag_ctxp(1))
84 >>> Integer(expl=tag_ctxc(2))
87 Implicit tag is not explicitly shown.
89 Two objects of the same type, but with different implicit/explicit tags
92 You can get object's effective tag (either default or implicited) through
93 ``tag`` property. You can decode it using :py:func:`pyderasn.tag_decode`
96 >>> tag_decode(tag_ctxc(123))
98 >>> klass, form, num = tag_decode(tag_ctxc(123))
99 >>> klass == TagClassContext
101 >>> form == TagFormConstructed
104 To determine if object has explicit tag, use ``expled`` boolean property
105 and ``expl_tag`` property, returning explicit tag's value.
110 Many objects in sequences could be ``OPTIONAL`` and could have
111 ``DEFAULT`` value. You can specify that object's property using
112 corresponding keyword arguments.
114 >>> Integer(optional=True, default=123)
115 INTEGER 123 OPTIONAL DEFAULT
117 Those specifications do not play any role in primitive value encoding,
118 but are taken into account when dealing with sequences holding them. For
119 example ``TBSCertificate`` sequence holds defaulted, explicitly tagged
122 class Version(Integer):
128 class TBSCertificate(Sequence):
130 ("version", Version(expl=tag_ctxc(0), default="v1")),
133 When default argument is used and value is not specified, then it equals
141 Some objects give ability to set value size constraints. This is either
142 possible integer value, or allowed length of various strings and
143 sequences. Constraints are set in the following way::
148 And values satisfaction is checked as: ``MIN <= X <= MAX``.
150 For simplicity you can also set bounds the following way::
152 bounded_x = X(bounds=(MIN, MAX))
154 If bounds are not satisfied, then :py:exc:`pyderasn.BoundsError` is
160 All objects have ``ready`` boolean property, that tells if object is
161 ready to be encoded. If that kind of action is performed on unready
162 object, then :py:exc:`pyderasn.ObjNotReady` exception will be raised.
164 All objects have ``copy()`` method, that returns their copy, that can be
172 Decoding is performed using ``decode()`` method. ``offset`` optional
173 argument could be used to set initial object's offset in the binary
174 data, for convenience. It returns decoded object and remaining
175 unmarshalled data (tail). Internally all work is done on
176 ``memoryview(data)``, and you can leave returning tail as a memoryview,
177 by specifying ``leavemm=True`` argument.
179 When object is decoded, ``decoded`` property is true and you can safely
180 use following properties:
182 * ``offset`` -- position including initial offset where object's tag starts
183 * ``tlen`` -- length of object's tag
184 * ``llen`` -- length of object's length value
185 * ``vlen`` -- length of object's value
186 * ``tlvlen`` -- length of the whole object
188 Pay attention that those values do **not** include anything related to
189 explicit tag. If you want to know information about it, then use:
191 * ``expled`` -- to know if explicit tag is set
192 * ``expl_offset`` (it is lesser than ``offset``)
195 * ``expl_vlen`` (that actually equals to ordinary ``tlvlen``)
196 * ``fulloffset`` -- it equals to ``expl_offset`` if explicit tag is set,
198 * ``fulllen`` -- it equals to ``expl_len`` if explicit tag is set,
201 When error occurs, :py:exc:`pyderasn.DecodeError` is raised.
208 You can specify so called context keyword argument during ``decode()``
209 invocation. It is dictionary containing various options governing
212 Currently available context options:
214 * :ref:`allow_default_values <allow_default_values_ctx>`
215 * :ref:`allow_expl_oob <allow_expl_oob_ctx>`
216 * :ref:`allow_unordered_set <allow_unordered_set_ctx>`
217 * :ref:`bered <bered_ctx>`
218 * :ref:`defines_by_path <defines_by_path_ctx>`
225 All objects have ``pps()`` method, that is a generator of
226 :py:class:`pyderasn.PP` namedtuple, holding various raw information
227 about the object. If ``pps`` is called on sequences, then all underlying
228 ``PP`` will be yielded.
230 You can use :py:func:`pyderasn.pp_console_row` function, converting
231 those ``PP`` to human readable string. Actually exactly it is used for
232 all object ``repr``. But it is easy to write custom formatters.
234 >>> from pyderasn import pprint
235 >>> encoded = Integer(-12345).encode()
236 >>> obj, tail = Integer().decode(encoded)
237 >>> print(pprint(obj))
238 0 [1,1, 2] INTEGER -12345
242 Example certificate::
244 >>> print(pprint(crt))
245 0 [1,3,1604] Certificate SEQUENCE
246 4 [1,3,1453] . tbsCertificate: TBSCertificate SEQUENCE
247 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
248 13 [1,1, 3] . . serialNumber: CertificateSerialNumber INTEGER 61595
249 18 [1,1, 13] . . signature: AlgorithmIdentifier SEQUENCE
250 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
251 31 [0,0, 2] . . . parameters: [UNIV 5] ANY OPTIONAL
253 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
254 33 [1,3, 274] . . . rdnSequence: RDNSequence SEQUENCE OF
255 37 [1,1, 11] . . . . 0: RelativeDistinguishedName SET OF
256 39 [1,1, 9] . . . . . 0: AttributeTypeAndValue SEQUENCE
257 41 [1,1, 3] . . . . . . type: AttributeType OBJECT IDENTIFIER 2.5.4.6
258 46 [0,0, 4] . . . . . . value: [UNIV 19] AttributeValue ANY
259 . . . . . . . 13:02:45:53
261 1461 [1,1, 13] . signatureAlgorithm: AlgorithmIdentifier SEQUENCE
262 1463 [1,1, 9] . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
263 1474 [0,0, 2] . . parameters: [UNIV 5] ANY OPTIONAL
265 1476 [1,2, 129] . signatureValue: BIT STRING 1024 bits
266 . . 68:EE:79:97:97:DD:3B:EF:16:6A:06:F2:14:9A:6E:CD
267 . . 9E:12:F7:AA:83:10:BD:D1:7C:98:FA:C7:AE:D4:0E:2C
272 Let's parse that output, human::
274 10-2 [1,1, 1] . . version: [0] EXPLICIT Version INTEGER v3 OPTIONAL
275 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
276 0 1 2 3 4 5 6 7 8 9 10 11
280 20 [1,1, 9] . . . algorithm: OBJECT IDENTIFIER 1.2.840.113549.1.1.5
286 33 [0,0, 278] . . issuer: Name CHOICE rdnSequence
292 52-2∞ B [1,1,1054]∞ . . . . eContent: [0] EXPLICIT BER OCTET STRING 1046 bytes
297 Offset of the object, where its DER/BER encoding begins.
298 Pay attention that it does **not** include explicit tag.
300 If explicit tag exists, then this is its length (tag + encoded length).
302 Length of object's tag. For example CHOICE does not have its own tag,
305 Length of encoded length.
307 Length of encoded value.
309 Visual indentation to show the depth of object in the hierarchy.
311 Object's name inside SEQUENCE/CHOICE.
313 If either IMPLICIT or EXPLICIT tag is set, then it will be shown
314 here. "IMPLICIT" is omitted.
316 Object's class name, if set. Omitted if it is just an ordinary simple
317 value (like with ``algorithm`` in example above).
321 Object's value, if set. Can consist of multiple words (like OCTET/BIT
322 STRINGs above). We see ``v3`` value in Version, because it is named.
323 ``rdnSequence`` is the choice of CHOICE type.
325 Possible other flags like OPTIONAL and DEFAULT, if value equals to the
326 default one, specified in the schema.
328 Shows does object contains any kind of BER encoded data (possibly
329 Sequence holding BER-encoded underlying value).
331 Only applicable to BER encoded data. Indefinite length encoding mark.
333 Only applicable to BER encoded data. If object has BER-specific
334 encoding, then ``BER`` will be shown. It does not depend on indefinite
335 length encoding. ``EOC``, ``BOOLEAN``, ``BIT STRING``, ``OCTET STRING``
336 (and its derivatives), ``SET``, ``SET OF`` could be BERed.
344 ASN.1 structures often have ANY and OCTET STRING fields, that are
345 DEFINED BY some previously met ObjectIdentifier. This library provides
346 ability to specify mapping between some OID and field that must be
347 decoded with specific specification.
354 :py:class:`pyderasn.ObjectIdentifier` field inside
355 :py:class:`pyderasn.Sequence` can hold mapping between OIDs and
356 necessary for decoding structures. For example, CMS (:rfc:`5652`)
359 class ContentInfo(Sequence):
361 ("contentType", ContentType(defines=((("content",), {
362 id_digestedData: DigestedData(),
363 id_signedData: SignedData(),
365 ("content", Any(expl=tag_ctxc(0))),
368 ``contentType`` field tells that it defines that ``content`` must be
369 decoded with ``SignedData`` specification, if ``contentType`` equals to
370 ``id-signedData``. The same applies to ``DigestedData``. If
371 ``contentType`` contains unknown OID, then no automatic decoding is
374 You can specify multiple fields, that will be autodecoded -- that is why
375 ``defines`` kwarg is a sequence. You can specify defined field
376 relatively or absolutely to current decode path. For example ``defines``
377 for AlgorithmIdentifier of X.509's
378 ``tbsCertificate:subjectPublicKeyInfo:algorithm:algorithm``::
382 id_ecPublicKey: ECParameters(),
383 id_GostR3410_2001: GostR34102001PublicKeyParameters(),
385 (("..", "subjectPublicKey"), {
386 id_rsaEncryption: RSAPublicKey(),
387 id_GostR3410_2001: OctetString(),
391 tells that if certificate's SPKI algorithm is GOST R 34.10-2001, then
392 autodecode its parameters inside SPKI's algorithm and its public key
395 Following types can be automatically decoded (DEFINED BY):
397 * :py:class:`pyderasn.Any`
398 * :py:class:`pyderasn.BitString` (that is multiple of 8 bits)
399 * :py:class:`pyderasn.OctetString`
400 * :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
401 ``Any``/``BitString``/``OctetString``-s
403 When any of those fields is automatically decoded, then ``.defined``
404 attribute contains ``(OID, value)`` tuple. ``OID`` tells by which OID it
405 was defined, ``value`` contains corresponding decoded value. For example
406 above, ``content_info["content"].defined == (id_signedData, signed_data)``.
408 .. _defines_by_path_ctx:
410 defines_by_path context option
411 ______________________________
413 Sometimes you either can not or do not want to explicitly set *defines*
414 in the scheme. You can dynamically apply those definitions when calling
415 ``.decode()`` method.
417 Specify ``defines_by_path`` key in the :ref:`decode context <ctx>`. Its
418 value must be sequence of following tuples::
420 (decode_path, defines)
422 where ``decode_path`` is a tuple holding so-called decode path to the
423 exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
424 ``defines``, holding exactly the same value as accepted in its
425 :ref:`keyword argument <defines>`.
427 For example, again for CMS, you want to automatically decode
428 ``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
429 structures it may hold. Also, automatically decode ``controlSequence``
432 content_info, tail = ContentInfo().decode(data, ctx={"defines_by_path": (
435 ((("content",), {id_signedData: SignedData()}),),
440 DecodePathDefBy(id_signedData),
445 id_cct_PKIData: PKIData(),
446 id_cct_PKIResponse: PKIResponse(),
452 DecodePathDefBy(id_signedData),
455 DecodePathDefBy(id_cct_PKIResponse),
461 id_cmc_recipientNonce: RecipientNonce(),
462 id_cmc_senderNonce: SenderNonce(),
463 id_cmc_statusInfoV2: CMCStatusInfoV2(),
464 id_cmc_transactionId: TransactionId(),
469 Pay attention for :py:class:`pyderasn.DecodePathDefBy` and ``any``.
470 First function is useful for path construction when some automatic
471 decoding is already done. ``any`` means literally any value it meet --
472 useful for SEQUENCE/SET OF-s.
479 By default PyDERASN accepts only DER encoded data. It always encodes to
480 DER. But you can optionally enable BER decoding with setting ``bered``
481 :ref:`context <ctx>` argument to True. Indefinite lengths and
482 constructed primitive types should be parsed successfully.
484 * If object is encoded in BER form (not the DER one), then ``ber_encoded``
485 attribute is set to True. Only ``BOOLEAN``, ``BIT STRING``, ``OCTET
486 STRING``, ``OBJECT IDENTIFIER``, ``SEQUENCE``, ``SET``, ``SET OF``
488 * If object has an indefinite length encoding, then its ``lenindef``
489 attribute is set to True. Only ``BIT STRING``, ``OCTET STRING``,
490 ``SEQUENCE``, ``SET``, ``SEQUENCE OF``, ``SET OF``, ``ANY`` can
492 * If object has an indefinite length encoded explicit tag, then
493 ``expl_lenindef`` is set to True.
494 * If object has either any of BER-related encoding (explicit tag
495 indefinite length, object's indefinite length, BER-encoding) or any
496 underlying component has that kind of encoding, then ``bered``
497 attribute is set to True. For example SignedData CMS can have
498 ``ContentInfo:content:signerInfos:*`` ``bered`` value set to True, but
499 ``ContentInfo:content:signerInfos:*:signedAttrs`` won't.
501 EOC (end-of-contents) token's length is taken in advance in object's
504 .. _allow_expl_oob_ctx:
506 Allow explicit tag out-of-bound
507 -------------------------------
509 Invalid BER encoding could contain ``EXPLICIT`` tag containing more than
510 one value, more than one object. If you set ``allow_expl_oob`` context
511 option to True, then no error will be raised and that invalid encoding
512 will be silently further processed. But pay attention that offsets and
513 lengths will be invalid in that case.
517 This option should be used only for skipping some decode errors, just
518 to see the decoded structure somehow.
522 .. autoclass:: pyderasn.Obj
530 .. autoclass:: pyderasn.Boolean
535 .. autoclass:: pyderasn.Integer
540 .. autoclass:: pyderasn.BitString
545 .. autoclass:: pyderasn.OctetString
550 .. autoclass:: pyderasn.Null
555 .. autoclass:: pyderasn.ObjectIdentifier
560 .. autoclass:: pyderasn.Enumerated
564 .. autoclass:: pyderasn.CommonString
568 .. autoclass:: pyderasn.NumericString
572 .. autoclass:: pyderasn.PrintableString
577 .. autoclass:: pyderasn.UTCTime
578 :members: __init__, todatetime
582 .. autoclass:: pyderasn.GeneralizedTime
589 .. autoclass:: pyderasn.Choice
594 .. autoclass:: PrimitiveTypes
598 .. autoclass:: pyderasn.Any
606 .. autoclass:: pyderasn.Sequence
611 .. autoclass:: pyderasn.Set
616 .. autoclass:: pyderasn.SequenceOf
621 .. autoclass:: pyderasn.SetOf
627 .. autofunction:: pyderasn.abs_decode_path
628 .. autofunction:: pyderasn.colonize_hex
629 .. autofunction:: pyderasn.hexenc
630 .. autofunction:: pyderasn.hexdec
631 .. autofunction:: pyderasn.tag_encode
632 .. autofunction:: pyderasn.tag_decode
633 .. autofunction:: pyderasn.tag_ctxp
634 .. autofunction:: pyderasn.tag_ctxc
635 .. autoclass:: pyderasn.DecodeError
637 .. autoclass:: pyderasn.NotEnoughData
638 .. autoclass:: pyderasn.ExceedingData
639 .. autoclass:: pyderasn.LenIndefForm
640 .. autoclass:: pyderasn.TagMismatch
641 .. autoclass:: pyderasn.InvalidLength
642 .. autoclass:: pyderasn.InvalidOID
643 .. autoclass:: pyderasn.ObjUnknown
644 .. autoclass:: pyderasn.ObjNotReady
645 .. autoclass:: pyderasn.InvalidValueType
646 .. autoclass:: pyderasn.BoundsError
649 from codecs import getdecoder
650 from codecs import getencoder
651 from collections import namedtuple
652 from collections import OrderedDict
653 from copy import copy
654 from datetime import datetime
655 from math import ceil
656 from os import environ
657 from string import ascii_letters
658 from string import digits
659 from unicodedata import category as unicat
661 from six import add_metaclass
662 from six import binary_type
663 from six import byte2int
664 from six import indexbytes
665 from six import int2byte
666 from six import integer_types
667 from six import iterbytes
668 from six import iteritems
669 from six import itervalues
671 from six import string_types
672 from six import text_type
673 from six import unichr as six_unichr
674 from six.moves import xrange as six_xrange
678 from termcolor import colored
679 except ImportError: # pragma: no cover
680 def colored(what, *args, **kwargs):
726 "TagClassApplication",
730 "TagFormConstructed",
741 TagClassUniversal = 0
742 TagClassApplication = 1 << 6
743 TagClassContext = 1 << 7
744 TagClassPrivate = 1 << 6 | 1 << 7
746 TagFormConstructed = 1 << 5
749 TagClassApplication: "APPLICATION ",
750 TagClassPrivate: "PRIVATE ",
751 TagClassUniversal: "UNIV ",
755 LENINDEF = b"\x80" # length indefinite mark
756 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
759 ########################################################################
761 ########################################################################
763 class ASN1Error(ValueError):
767 class DecodeError(ASN1Error):
768 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
770 :param str msg: reason of decode failing
771 :param klass: optional exact DecodeError inherited class (like
772 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
773 :py:exc:`InvalidLength`)
774 :param decode_path: tuple of strings. It contains human
775 readable names of the fields through which
776 decoding process has passed
777 :param int offset: binary offset where failure happened
779 super(DecodeError, self).__init__()
782 self.decode_path = decode_path
788 "" if self.klass is None else self.klass.__name__,
790 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
791 if len(self.decode_path) > 0 else ""
793 ("(at %d)" % self.offset) if self.offset > 0 else "",
799 return "%s(%s)" % (self.__class__.__name__, self)
802 class NotEnoughData(DecodeError):
806 class ExceedingData(ASN1Error):
807 def __init__(self, nbytes):
808 super(ExceedingData, self).__init__()
812 return "%d trailing bytes" % self.nbytes
815 return "%s(%s)" % (self.__class__.__name__, self)
818 class LenIndefForm(DecodeError):
822 class TagMismatch(DecodeError):
826 class InvalidLength(DecodeError):
830 class InvalidOID(DecodeError):
834 class ObjUnknown(ASN1Error):
835 def __init__(self, name):
836 super(ObjUnknown, self).__init__()
840 return "object is unknown: %s" % self.name
843 return "%s(%s)" % (self.__class__.__name__, self)
846 class ObjNotReady(ASN1Error):
847 def __init__(self, name):
848 super(ObjNotReady, self).__init__()
852 return "object is not ready: %s" % self.name
855 return "%s(%s)" % (self.__class__.__name__, self)
858 class InvalidValueType(ASN1Error):
859 def __init__(self, expected_types):
860 super(InvalidValueType, self).__init__()
861 self.expected_types = expected_types
864 return "invalid value type, expected: %s" % ", ".join(
865 [repr(t) for t in self.expected_types]
869 return "%s(%s)" % (self.__class__.__name__, self)
872 class BoundsError(ASN1Error):
873 def __init__(self, bound_min, value, bound_max):
874 super(BoundsError, self).__init__()
875 self.bound_min = bound_min
877 self.bound_max = bound_max
880 return "unsatisfied bounds: %s <= %s <= %s" % (
887 return "%s(%s)" % (self.__class__.__name__, self)
890 ########################################################################
892 ########################################################################
894 _hexdecoder = getdecoder("hex")
895 _hexencoder = getencoder("hex")
899 """Binary data to hexadecimal string convert
901 return _hexdecoder(data)[0]
905 """Hexadecimal string to binary data convert
907 return _hexencoder(data)[0].decode("ascii")
910 def int_bytes_len(num, byte_len=8):
913 return int(ceil(float(num.bit_length()) / byte_len))
916 def zero_ended_encode(num):
917 octets = bytearray(int_bytes_len(num, 7))
919 octets[i] = num & 0x7F
923 octets[i] = 0x80 | (num & 0x7F)
929 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
930 """Encode tag to binary form
932 :param int num: tag's number
933 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
934 :py:data:`pyderasn.TagClassContext`,
935 :py:data:`pyderasn.TagClassApplication`,
936 :py:data:`pyderasn.TagClassPrivate`)
937 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
938 :py:data:`pyderasn.TagFormConstructed`)
942 return int2byte(klass | form | num)
943 # [XX|X|11111][1.......][1.......] ... [0.......]
944 return int2byte(klass | form | 31) + zero_ended_encode(num)
948 """Decode tag from binary form
952 No validation is performed, assuming that it has already passed.
954 It returns tuple with three integers, as
955 :py:func:`pyderasn.tag_encode` accepts.
957 first_octet = byte2int(tag)
958 klass = first_octet & 0xC0
959 form = first_octet & 0x20
960 if first_octet & 0x1F < 0x1F:
961 return (klass, form, first_octet & 0x1F)
963 for octet in iterbytes(tag[1:]):
966 return (klass, form, num)
970 """Create CONTEXT PRIMITIVE tag
972 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
976 """Create CONTEXT CONSTRUCTED tag
978 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
982 """Take off tag from the data
984 :returns: (encoded tag, tag length, remaining data)
987 raise NotEnoughData("no data at all")
988 if byte2int(data) & 0x1F < 31:
989 return data[:1], 1, data[1:]
994 raise DecodeError("unfinished tag")
995 if indexbytes(data, i) & 0x80 == 0:
998 return data[:i], i, data[i:]
1004 octets = bytearray(int_bytes_len(l) + 1)
1005 octets[0] = 0x80 | (len(octets) - 1)
1006 for i in six_xrange(len(octets) - 1, 0, -1):
1007 octets[i] = l & 0xFF
1009 return bytes(octets)
1012 def len_decode(data):
1015 :returns: (decoded length, length's length, remaining data)
1016 :raises LenIndefForm: if indefinite form encoding is met
1019 raise NotEnoughData("no data at all")
1020 first_octet = byte2int(data)
1021 if first_octet & 0x80 == 0:
1022 return first_octet, 1, data[1:]
1023 octets_num = first_octet & 0x7F
1024 if octets_num + 1 > len(data):
1025 raise NotEnoughData("encoded length is longer than data")
1027 raise LenIndefForm()
1028 if byte2int(data[1:]) == 0:
1029 raise DecodeError("leading zeros")
1031 for v in iterbytes(data[1:1 + octets_num]):
1034 raise DecodeError("long form instead of short one")
1035 return l, 1 + octets_num, data[1 + octets_num:]
1038 ########################################################################
1040 ########################################################################
1042 class AutoAddSlots(type):
1043 def __new__(cls, name, bases, _dict):
1044 _dict["__slots__"] = _dict.get("__slots__", ())
1045 return type.__new__(cls, name, bases, _dict)
1048 @add_metaclass(AutoAddSlots)
1050 """Common ASN.1 object class
1052 All ASN.1 types are inherited from it. It has metaclass that
1053 automatically adds ``__slots__`` to all inherited classes.
1077 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1078 self._expl = getattr(self, "expl", None) if expl is None else expl
1079 if self.tag != self.tag_default and self._expl is not None:
1080 raise ValueError("implicit and explicit tags can not be set simultaneously")
1081 if default is not None:
1083 self.optional = optional
1084 self.offset, self.llen, self.vlen = _decoded
1086 self.expl_lenindef = False
1087 self.lenindef = False
1088 self.ber_encoded = False
1091 def ready(self): # pragma: no cover
1092 """Is object ready to be encoded?
1094 raise NotImplementedError()
1096 def _assert_ready(self):
1098 raise ObjNotReady(self.__class__.__name__)
1102 """Is either object or any elements inside is BER encoded?
1104 return self.expl_lenindef or self.lenindef or self.ber_encoded
1108 """Is object decoded?
1110 return (self.llen + self.vlen) > 0
1112 def copy(self): # pragma: no cover
1113 """Make a copy of object, safe to be mutated
1115 raise NotImplementedError()
1119 """See :ref:`decoding`
1121 return len(self.tag)
1125 """See :ref:`decoding`
1127 return self.tlen + self.llen + self.vlen
1129 def __str__(self): # pragma: no cover
1130 return self.__bytes__() if PY2 else self.__unicode__()
1132 def __ne__(self, their):
1133 return not(self == their)
1135 def __gt__(self, their): # pragma: no cover
1136 return not(self < their)
1138 def __le__(self, their): # pragma: no cover
1139 return (self == their) or (self < their)
1141 def __ge__(self, their): # pragma: no cover
1142 return (self == their) or (self > their)
1144 def _encode(self): # pragma: no cover
1145 raise NotImplementedError()
1147 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1148 raise NotImplementedError()
1151 """Encode the structure
1153 :returns: DER representation
1155 raw = self._encode()
1156 if self._expl is None:
1158 return b"".join((self._expl, len_encode(len(raw)), raw))
1168 _ctx_immutable=True,
1172 :param data: either binary or memoryview
1173 :param int offset: initial data's offset
1174 :param bool leavemm: do we need to leave memoryview of remaining
1175 data as is, or convert it to bytes otherwise
1176 :param ctx: optional :ref:`context <ctx>` governing decoding process
1177 :param tag_only: decode only the tag, without length and contents
1178 (used only in Choice and Set structures, trying to
1179 determine if tag satisfies the scheme)
1180 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1181 :returns: (Obj, remaining data)
1183 .. seealso:: :ref:`decoding`
1187 elif _ctx_immutable:
1189 tlv = memoryview(data)
1190 if self._expl is None:
1191 result = self._decode(
1194 decode_path=decode_path,
1203 t, tlen, lv = tag_strip(tlv)
1204 except DecodeError as err:
1205 raise err.__class__(
1207 klass=self.__class__,
1208 decode_path=decode_path,
1213 klass=self.__class__,
1214 decode_path=decode_path,
1218 l, llen, v = len_decode(lv)
1219 except LenIndefForm as err:
1220 if not ctx.get("bered", False):
1221 raise err.__class__(
1223 klass=self.__class__,
1224 decode_path=decode_path,
1228 offset += tlen + llen
1229 result = self._decode(
1232 decode_path=decode_path,
1236 if tag_only: # pragma: no cover
1239 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1240 if eoc_expected.tobytes() != EOC:
1243 klass=self.__class__,
1244 decode_path=decode_path,
1248 obj.expl_lenindef = True
1249 except DecodeError as err:
1250 raise err.__class__(
1252 klass=self.__class__,
1253 decode_path=decode_path,
1258 raise NotEnoughData(
1259 "encoded length is longer than data",
1260 klass=self.__class__,
1261 decode_path=decode_path,
1264 result = self._decode(
1266 offset=offset + tlen + llen,
1267 decode_path=decode_path,
1271 if tag_only: # pragma: no cover
1274 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1276 "explicit tag out-of-bound, longer than data",
1277 klass=self.__class__,
1278 decode_path=decode_path,
1281 return obj, (tail if leavemm else tail.tobytes())
1283 def decod(self, data, offset=0, decode_path=(), ctx=None):
1284 """Decode the data, check that tail is empty
1286 :raises ExceedingData: if tail is not empty
1288 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1289 (decode without tail) that also checks that there is no
1292 obj, tail = self.decode(
1295 decode_path=decode_path,
1300 raise ExceedingData(len(tail))
1305 """See :ref:`decoding`
1307 return self._expl is not None
1311 """See :ref:`decoding`
1316 def expl_tlen(self):
1317 """See :ref:`decoding`
1319 return len(self._expl)
1322 def expl_llen(self):
1323 """See :ref:`decoding`
1325 if self.expl_lenindef:
1327 return len(len_encode(self.tlvlen))
1330 def expl_offset(self):
1331 """See :ref:`decoding`
1333 return self.offset - self.expl_tlen - self.expl_llen
1336 def expl_vlen(self):
1337 """See :ref:`decoding`
1342 def expl_tlvlen(self):
1343 """See :ref:`decoding`
1345 return self.expl_tlen + self.expl_llen + self.expl_vlen
1348 def fulloffset(self):
1349 """See :ref:`decoding`
1351 return self.expl_offset if self.expled else self.offset
1355 """See :ref:`decoding`
1357 return self.expl_tlvlen if self.expled else self.tlvlen
1359 def pps_lenindef(self, decode_path):
1360 if self.lenindef and not (
1361 getattr(self, "defined", None) is not None and
1362 self.defined[1].lenindef
1365 asn1_type_name="EOC",
1367 decode_path=decode_path,
1369 self.offset + self.tlvlen -
1370 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1378 if self.expl_lenindef:
1380 asn1_type_name="EOC",
1381 obj_name="EXPLICIT",
1382 decode_path=decode_path,
1383 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1392 class DecodePathDefBy(object):
1393 """DEFINED BY representation inside decode path
1395 __slots__ = ("defined_by",)
1397 def __init__(self, defined_by):
1398 self.defined_by = defined_by
1400 def __ne__(self, their):
1401 return not(self == their)
1403 def __eq__(self, their):
1404 if not isinstance(their, self.__class__):
1406 return self.defined_by == their.defined_by
1409 return "DEFINED BY " + str(self.defined_by)
1412 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1415 ########################################################################
1417 ########################################################################
1419 PP = namedtuple("PP", (
1447 asn1_type_name="unknown",
1464 expl_lenindef=False,
1495 def _colourize(what, colour, with_colours, attrs=("bold",)):
1496 return colored(what, colour, attrs=attrs) if with_colours else what
1499 def colonize_hex(hexed):
1500 """Separate hexadecimal string with colons
1502 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1511 with_decode_path=False,
1512 decode_path_len_decrease=0,
1519 " " if pp.expl_offset is None else
1520 ("-%d" % (pp.offset - pp.expl_offset))
1522 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1524 col = _colourize(col, "red", with_colours, ())
1525 col += _colourize("B", "red", with_colours) if pp.bered else " "
1527 col = "[%d,%d,%4d]%s" % (
1531 LENINDEF_PP_CHAR if pp.lenindef else " "
1533 col = _colourize(col, "green", with_colours, ())
1535 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1536 if decode_path_len > 0:
1537 cols.append(" ." * decode_path_len)
1538 ent = pp.decode_path[-1]
1539 if isinstance(ent, DecodePathDefBy):
1540 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1541 value = str(ent.defined_by)
1544 len(oid_maps) > 0 and
1545 ent.defined_by.asn1_type_name ==
1546 ObjectIdentifier.asn1_type_name
1548 for oid_map in oid_maps:
1549 oid_name = oid_map.get(value)
1550 if oid_name is not None:
1551 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1553 if oid_name is None:
1554 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1556 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1557 if pp.expl is not None:
1558 klass, _, num = pp.expl
1559 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1560 cols.append(_colourize(col, "blue", with_colours))
1561 if pp.impl is not None:
1562 klass, _, num = pp.impl
1563 col = "[%s%d]" % (TagClassReprs[klass], num)
1564 cols.append(_colourize(col, "blue", with_colours))
1565 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1566 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1568 cols.append(_colourize("BER", "red", with_colours))
1569 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1570 if pp.value is not None:
1572 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1574 len(oid_maps) > 0 and
1575 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1577 for oid_map in oid_maps:
1578 oid_name = oid_map.get(value)
1579 if oid_name is not None:
1580 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1582 if pp.asn1_type_name == Integer.asn1_type_name:
1583 hex_repr = hex(int(pp.obj._value))[2:].upper()
1584 if len(hex_repr) % 2 != 0:
1585 hex_repr = "0" + hex_repr
1586 cols.append(_colourize(
1587 "(%s)" % colonize_hex(hex_repr),
1592 if isinstance(pp.blob, binary_type):
1593 cols.append(hexenc(pp.blob))
1594 elif isinstance(pp.blob, tuple):
1595 cols.append(", ".join(pp.blob))
1597 cols.append(_colourize("OPTIONAL", "red", with_colours))
1599 cols.append(_colourize("DEFAULT", "red", with_colours))
1600 if with_decode_path:
1601 cols.append(_colourize(
1602 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1606 return " ".join(cols)
1609 def pp_console_blob(pp, decode_path_len_decrease=0):
1610 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1611 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1612 if decode_path_len > 0:
1613 cols.append(" ." * (decode_path_len + 1))
1614 if isinstance(pp.blob, binary_type):
1615 blob = hexenc(pp.blob).upper()
1616 for i in six_xrange(0, len(blob), 32):
1617 chunk = blob[i:i + 32]
1618 yield " ".join(cols + [colonize_hex(chunk)])
1619 elif isinstance(pp.blob, tuple):
1620 yield " ".join(cols + [", ".join(pp.blob)])
1628 with_decode_path=False,
1629 decode_path_only=(),
1631 """Pretty print object
1633 :param Obj obj: object you want to pretty print
1634 :param oid_maps: list of ``OID <-> humand readable string`` dictionary.
1635 When OID from it is met, then its humand readable form
1637 :param big_blobs: if large binary objects are met (like OctetString
1638 values), do we need to print them too, on separate
1640 :param with_colours: colourize output, if ``termcolor`` library
1642 :param with_decode_path: print decode path
1643 :param decode_path_only: print only that specified decode path
1645 def _pprint_pps(pps):
1647 if hasattr(pp, "_fields"):
1649 decode_path_only != () and
1651 str(p) for p in pp.decode_path[:len(decode_path_only)]
1652 ) != decode_path_only
1656 yield pp_console_row(
1661 with_colours=with_colours,
1662 with_decode_path=with_decode_path,
1663 decode_path_len_decrease=len(decode_path_only),
1665 for row in pp_console_blob(
1667 decode_path_len_decrease=len(decode_path_only),
1671 yield pp_console_row(
1676 with_colours=with_colours,
1677 with_decode_path=with_decode_path,
1678 decode_path_len_decrease=len(decode_path_only),
1681 for row in _pprint_pps(pp):
1683 return "\n".join(_pprint_pps(obj.pps()))
1686 ########################################################################
1687 # ASN.1 primitive types
1688 ########################################################################
1691 """``BOOLEAN`` boolean type
1693 >>> b = Boolean(True)
1695 >>> b == Boolean(True)
1701 tag_default = tag_encode(1)
1702 asn1_type_name = "BOOLEAN"
1714 :param value: set the value. Either boolean type, or
1715 :py:class:`pyderasn.Boolean` object
1716 :param bytes impl: override default tag with ``IMPLICIT`` one
1717 :param bytes expl: override default tag with ``EXPLICIT`` one
1718 :param default: set default value. Type same as in ``value``
1719 :param bool optional: is object ``OPTIONAL`` in sequence
1721 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1722 self._value = None if value is None else self._value_sanitize(value)
1723 if default is not None:
1724 default = self._value_sanitize(default)
1725 self.default = self.__class__(
1731 self._value = default
1733 def _value_sanitize(self, value):
1734 if isinstance(value, bool):
1736 if issubclass(value.__class__, Boolean):
1738 raise InvalidValueType((self.__class__, bool))
1742 return self._value is not None
1745 obj = self.__class__()
1746 obj._value = self._value
1748 obj._expl = self._expl
1749 obj.default = self.default
1750 obj.optional = self.optional
1751 obj.offset = self.offset
1752 obj.llen = self.llen
1753 obj.vlen = self.vlen
1754 obj.expl_lenindef = self.expl_lenindef
1755 obj.lenindef = self.lenindef
1756 obj.ber_encoded = self.ber_encoded
1759 def __nonzero__(self):
1760 self._assert_ready()
1764 self._assert_ready()
1767 def __eq__(self, their):
1768 if isinstance(their, bool):
1769 return self._value == their
1770 if not issubclass(their.__class__, Boolean):
1773 self._value == their._value and
1774 self.tag == their.tag and
1775 self._expl == their._expl
1786 return self.__class__(
1788 impl=self.tag if impl is None else impl,
1789 expl=self._expl if expl is None else expl,
1790 default=self.default if default is None else default,
1791 optional=self.optional if optional is None else optional,
1795 self._assert_ready()
1799 (b"\xFF" if self._value else b"\x00"),
1802 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1804 t, _, lv = tag_strip(tlv)
1805 except DecodeError as err:
1806 raise err.__class__(
1808 klass=self.__class__,
1809 decode_path=decode_path,
1814 klass=self.__class__,
1815 decode_path=decode_path,
1821 l, _, v = len_decode(lv)
1822 except DecodeError as err:
1823 raise err.__class__(
1825 klass=self.__class__,
1826 decode_path=decode_path,
1830 raise InvalidLength(
1831 "Boolean's length must be equal to 1",
1832 klass=self.__class__,
1833 decode_path=decode_path,
1837 raise NotEnoughData(
1838 "encoded length is longer than data",
1839 klass=self.__class__,
1840 decode_path=decode_path,
1843 first_octet = byte2int(v)
1845 if first_octet == 0:
1847 elif first_octet == 0xFF:
1849 elif ctx.get("bered", False):
1854 "unacceptable Boolean value",
1855 klass=self.__class__,
1856 decode_path=decode_path,
1859 obj = self.__class__(
1863 default=self.default,
1864 optional=self.optional,
1865 _decoded=(offset, 1, 1),
1867 obj.ber_encoded = ber_encoded
1871 return pp_console_row(next(self.pps()))
1873 def pps(self, decode_path=()):
1876 asn1_type_name=self.asn1_type_name,
1877 obj_name=self.__class__.__name__,
1878 decode_path=decode_path,
1879 value=str(self._value) if self.ready else None,
1880 optional=self.optional,
1881 default=self == self.default,
1882 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1883 expl=None if self._expl is None else tag_decode(self._expl),
1888 expl_offset=self.expl_offset if self.expled else None,
1889 expl_tlen=self.expl_tlen if self.expled else None,
1890 expl_llen=self.expl_llen if self.expled else None,
1891 expl_vlen=self.expl_vlen if self.expled else None,
1892 expl_lenindef=self.expl_lenindef,
1893 ber_encoded=self.ber_encoded,
1896 for pp in self.pps_lenindef(decode_path):
1901 """``INTEGER`` integer type
1903 >>> b = Integer(-123)
1905 >>> b == Integer(-123)
1910 >>> Integer(2, bounds=(1, 3))
1912 >>> Integer(5, bounds=(1, 3))
1913 Traceback (most recent call last):
1914 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1918 class Version(Integer):
1925 >>> v = Version("v1")
1932 {'v3': 2, 'v1': 0, 'v2': 1}
1934 __slots__ = ("specs", "_bound_min", "_bound_max")
1935 tag_default = tag_encode(2)
1936 asn1_type_name = "INTEGER"
1950 :param value: set the value. Either integer type, named value
1951 (if ``schema`` is specified in the class), or
1952 :py:class:`pyderasn.Integer` object
1953 :param bounds: set ``(MIN, MAX)`` value constraint.
1954 (-inf, +inf) by default
1955 :param bytes impl: override default tag with ``IMPLICIT`` one
1956 :param bytes expl: override default tag with ``EXPLICIT`` one
1957 :param default: set default value. Type same as in ``value``
1958 :param bool optional: is object ``OPTIONAL`` in sequence
1960 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1962 specs = getattr(self, "schema", {}) if _specs is None else _specs
1963 self.specs = specs if isinstance(specs, dict) else dict(specs)
1964 self._bound_min, self._bound_max = getattr(
1967 (float("-inf"), float("+inf")),
1968 ) if bounds is None else bounds
1969 if value is not None:
1970 self._value = self._value_sanitize(value)
1971 if default is not None:
1972 default = self._value_sanitize(default)
1973 self.default = self.__class__(
1979 if self._value is None:
1980 self._value = default
1982 def _value_sanitize(self, value):
1983 if isinstance(value, integer_types):
1985 elif issubclass(value.__class__, Integer):
1986 value = value._value
1987 elif isinstance(value, str):
1988 value = self.specs.get(value)
1990 raise ObjUnknown("integer value: %s" % value)
1992 raise InvalidValueType((self.__class__, int, str))
1993 if not self._bound_min <= value <= self._bound_max:
1994 raise BoundsError(self._bound_min, value, self._bound_max)
1999 return self._value is not None
2002 obj = self.__class__(_specs=self.specs)
2003 obj._value = self._value
2004 obj._bound_min = self._bound_min
2005 obj._bound_max = self._bound_max
2007 obj._expl = self._expl
2008 obj.default = self.default
2009 obj.optional = self.optional
2010 obj.offset = self.offset
2011 obj.llen = self.llen
2012 obj.vlen = self.vlen
2013 obj.expl_lenindef = self.expl_lenindef
2014 obj.lenindef = self.lenindef
2015 obj.ber_encoded = self.ber_encoded
2019 self._assert_ready()
2020 return int(self._value)
2023 self._assert_ready()
2026 bytes(self._expl or b"") +
2027 str(self._value).encode("ascii"),
2030 def __eq__(self, their):
2031 if isinstance(their, integer_types):
2032 return self._value == their
2033 if not issubclass(their.__class__, Integer):
2036 self._value == their._value and
2037 self.tag == their.tag and
2038 self._expl == their._expl
2041 def __lt__(self, their):
2042 return self._value < their._value
2046 for name, value in iteritems(self.specs):
2047 if value == self._value:
2060 return self.__class__(
2063 (self._bound_min, self._bound_max)
2064 if bounds is None else bounds
2066 impl=self.tag if impl is None else impl,
2067 expl=self._expl if expl is None else expl,
2068 default=self.default if default is None else default,
2069 optional=self.optional if optional is None else optional,
2074 self._assert_ready()
2078 octets = bytearray([0])
2082 octets = bytearray()
2084 octets.append((value & 0xFF) ^ 0xFF)
2086 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2089 octets = bytearray()
2091 octets.append(value & 0xFF)
2093 if octets[-1] & 0x80 > 0:
2096 octets = bytes(octets)
2098 bytes_len = ceil(value.bit_length() / 8) or 1
2101 octets = value.to_bytes(
2106 except OverflowError:
2110 return b"".join((self.tag, len_encode(len(octets)), octets))
2112 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2114 t, _, lv = tag_strip(tlv)
2115 except DecodeError as err:
2116 raise err.__class__(
2118 klass=self.__class__,
2119 decode_path=decode_path,
2124 klass=self.__class__,
2125 decode_path=decode_path,
2131 l, llen, v = len_decode(lv)
2132 except DecodeError as err:
2133 raise err.__class__(
2135 klass=self.__class__,
2136 decode_path=decode_path,
2140 raise NotEnoughData(
2141 "encoded length is longer than data",
2142 klass=self.__class__,
2143 decode_path=decode_path,
2147 raise NotEnoughData(
2149 klass=self.__class__,
2150 decode_path=decode_path,
2153 v, tail = v[:l], v[l:]
2154 first_octet = byte2int(v)
2156 second_octet = byte2int(v[1:])
2158 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2159 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2162 "non normalized integer",
2163 klass=self.__class__,
2164 decode_path=decode_path,
2169 if first_octet & 0x80 > 0:
2170 octets = bytearray()
2171 for octet in bytearray(v):
2172 octets.append(octet ^ 0xFF)
2173 for octet in octets:
2174 value = (value << 8) | octet
2178 for octet in bytearray(v):
2179 value = (value << 8) | octet
2181 value = int.from_bytes(v, byteorder="big", signed=True)
2183 obj = self.__class__(
2185 bounds=(self._bound_min, self._bound_max),
2188 default=self.default,
2189 optional=self.optional,
2191 _decoded=(offset, llen, l),
2193 except BoundsError as err:
2196 klass=self.__class__,
2197 decode_path=decode_path,
2203 return pp_console_row(next(self.pps()))
2205 def pps(self, decode_path=()):
2208 asn1_type_name=self.asn1_type_name,
2209 obj_name=self.__class__.__name__,
2210 decode_path=decode_path,
2211 value=(self.named or str(self._value)) if self.ready else None,
2212 optional=self.optional,
2213 default=self == self.default,
2214 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2215 expl=None if self._expl is None else tag_decode(self._expl),
2220 expl_offset=self.expl_offset if self.expled else None,
2221 expl_tlen=self.expl_tlen if self.expled else None,
2222 expl_llen=self.expl_llen if self.expled else None,
2223 expl_vlen=self.expl_vlen if self.expled else None,
2224 expl_lenindef=self.expl_lenindef,
2227 for pp in self.pps_lenindef(decode_path):
2231 SET01 = frozenset(("0", "1"))
2234 class BitString(Obj):
2235 """``BIT STRING`` bit string type
2237 >>> BitString(b"hello world")
2238 BIT STRING 88 bits 68656c6c6f20776f726c64
2241 >>> b == b"hello world"
2246 >>> BitString("'0A3B5F291CD'H")
2247 BIT STRING 44 bits 0a3b5f291cd0
2248 >>> b = BitString("'010110000000'B")
2249 BIT STRING 12 bits 5800
2252 >>> b[0], b[1], b[2], b[3]
2253 (False, True, False, True)
2257 [False, True, False, True, True, False, False, False, False, False, False, False]
2261 class KeyUsage(BitString):
2263 ("digitalSignature", 0),
2264 ("nonRepudiation", 1),
2265 ("keyEncipherment", 2),
2268 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2269 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2271 ['nonRepudiation', 'keyEncipherment']
2273 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2277 Pay attention that BIT STRING can be encoded both in primitive
2278 and constructed forms. Decoder always checks constructed form tag
2279 additionally to specified primitive one. If BER decoding is
2280 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2281 of DER restrictions.
2283 __slots__ = ("tag_constructed", "specs", "defined")
2284 tag_default = tag_encode(3)
2285 asn1_type_name = "BIT STRING"
2298 :param value: set the value. Either binary type, tuple of named
2299 values (if ``schema`` is specified in the class),
2300 string in ``'XXX...'B`` form, or
2301 :py:class:`pyderasn.BitString` object
2302 :param bytes impl: override default tag with ``IMPLICIT`` one
2303 :param bytes expl: override default tag with ``EXPLICIT`` one
2304 :param default: set default value. Type same as in ``value``
2305 :param bool optional: is object ``OPTIONAL`` in sequence
2307 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2308 specs = getattr(self, "schema", {}) if _specs is None else _specs
2309 self.specs = specs if isinstance(specs, dict) else dict(specs)
2310 self._value = None if value is None else self._value_sanitize(value)
2311 if default is not None:
2312 default = self._value_sanitize(default)
2313 self.default = self.__class__(
2319 self._value = default
2321 tag_klass, _, tag_num = tag_decode(self.tag)
2322 self.tag_constructed = tag_encode(
2324 form=TagFormConstructed,
2328 def _bits2octets(self, bits):
2329 if len(self.specs) > 0:
2330 bits = bits.rstrip("0")
2332 bits += "0" * ((8 - (bit_len % 8)) % 8)
2333 octets = bytearray(len(bits) // 8)
2334 for i in six_xrange(len(octets)):
2335 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2336 return bit_len, bytes(octets)
2338 def _value_sanitize(self, value):
2339 if isinstance(value, (string_types, binary_type)):
2341 isinstance(value, string_types) and
2342 value.startswith("'")
2344 if value.endswith("'B"):
2346 if not frozenset(value) <= SET01:
2347 raise ValueError("B's coding contains unacceptable chars")
2348 return self._bits2octets(value)
2349 if value.endswith("'H"):
2353 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2355 if isinstance(value, binary_type):
2356 return (len(value) * 8, value)
2357 raise InvalidValueType((self.__class__, string_types, binary_type))
2358 if isinstance(value, tuple):
2361 isinstance(value[0], integer_types) and
2362 isinstance(value[1], binary_type)
2367 bit = self.specs.get(name)
2369 raise ObjUnknown("BitString value: %s" % name)
2372 return self._bits2octets("")
2373 bits = frozenset(bits)
2374 return self._bits2octets("".join(
2375 ("1" if bit in bits else "0")
2376 for bit in six_xrange(max(bits) + 1)
2378 if issubclass(value.__class__, BitString):
2380 raise InvalidValueType((self.__class__, binary_type, string_types))
2384 return self._value is not None
2387 obj = self.__class__(_specs=self.specs)
2389 if value is not None:
2390 value = (value[0], value[1])
2393 obj._expl = self._expl
2394 obj.default = self.default
2395 obj.optional = self.optional
2396 obj.offset = self.offset
2397 obj.llen = self.llen
2398 obj.vlen = self.vlen
2399 obj.expl_lenindef = self.expl_lenindef
2400 obj.lenindef = self.lenindef
2401 obj.ber_encoded = self.ber_encoded
2405 self._assert_ready()
2406 for i in six_xrange(self._value[0]):
2411 self._assert_ready()
2412 return self._value[0]
2414 def __bytes__(self):
2415 self._assert_ready()
2416 return self._value[1]
2418 def __eq__(self, their):
2419 if isinstance(their, bytes):
2420 return self._value[1] == their
2421 if not issubclass(their.__class__, BitString):
2424 self._value == their._value and
2425 self.tag == their.tag and
2426 self._expl == their._expl
2431 return [name for name, bit in iteritems(self.specs) if self[bit]]
2441 return self.__class__(
2443 impl=self.tag if impl is None else impl,
2444 expl=self._expl if expl is None else expl,
2445 default=self.default if default is None else default,
2446 optional=self.optional if optional is None else optional,
2450 def __getitem__(self, key):
2451 if isinstance(key, int):
2452 bit_len, octets = self._value
2456 byte2int(memoryview(octets)[key // 8:]) >>
2459 if isinstance(key, string_types):
2460 value = self.specs.get(key)
2462 raise ObjUnknown("BitString value: %s" % key)
2464 raise InvalidValueType((int, str))
2467 self._assert_ready()
2468 bit_len, octets = self._value
2471 len_encode(len(octets) + 1),
2472 int2byte((8 - bit_len % 8) % 8),
2476 def _decode_chunk(self, lv, offset, decode_path):
2478 l, llen, v = len_decode(lv)
2479 except DecodeError as err:
2480 raise err.__class__(
2482 klass=self.__class__,
2483 decode_path=decode_path,
2487 raise NotEnoughData(
2488 "encoded length is longer than data",
2489 klass=self.__class__,
2490 decode_path=decode_path,
2494 raise NotEnoughData(
2496 klass=self.__class__,
2497 decode_path=decode_path,
2500 pad_size = byte2int(v)
2501 if l == 1 and pad_size != 0:
2503 "invalid empty value",
2504 klass=self.__class__,
2505 decode_path=decode_path,
2511 klass=self.__class__,
2512 decode_path=decode_path,
2515 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2518 klass=self.__class__,
2519 decode_path=decode_path,
2522 v, tail = v[:l], v[l:]
2523 obj = self.__class__(
2524 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2527 default=self.default,
2528 optional=self.optional,
2530 _decoded=(offset, llen, l),
2534 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2536 t, tlen, lv = tag_strip(tlv)
2537 except DecodeError as err:
2538 raise err.__class__(
2540 klass=self.__class__,
2541 decode_path=decode_path,
2545 if tag_only: # pragma: no cover
2547 return self._decode_chunk(lv, offset, decode_path)
2548 if t == self.tag_constructed:
2549 if not ctx.get("bered", False):
2551 "unallowed BER constructed encoding",
2552 klass=self.__class__,
2553 decode_path=decode_path,
2556 if tag_only: # pragma: no cover
2560 l, llen, v = len_decode(lv)
2561 except LenIndefForm:
2562 llen, l, v = 1, 0, lv[1:]
2564 except DecodeError as err:
2565 raise err.__class__(
2567 klass=self.__class__,
2568 decode_path=decode_path,
2572 raise NotEnoughData(
2573 "encoded length is longer than data",
2574 klass=self.__class__,
2575 decode_path=decode_path,
2578 if not lenindef and l == 0:
2579 raise NotEnoughData(
2581 klass=self.__class__,
2582 decode_path=decode_path,
2586 sub_offset = offset + tlen + llen
2590 if v[:EOC_LEN].tobytes() == EOC:
2597 "chunk out of bounds",
2598 klass=self.__class__,
2599 decode_path=decode_path + (str(len(chunks) - 1),),
2600 offset=chunks[-1].offset,
2602 sub_decode_path = decode_path + (str(len(chunks)),)
2604 chunk, v_tail = BitString().decode(
2607 decode_path=sub_decode_path,
2610 _ctx_immutable=False,
2614 "expected BitString encoded chunk",
2615 klass=self.__class__,
2616 decode_path=sub_decode_path,
2619 chunks.append(chunk)
2620 sub_offset += chunk.tlvlen
2621 vlen += chunk.tlvlen
2623 if len(chunks) == 0:
2626 klass=self.__class__,
2627 decode_path=decode_path,
2632 for chunk_i, chunk in enumerate(chunks[:-1]):
2633 if chunk.bit_len % 8 != 0:
2635 "BitString chunk is not multiple of 8 bits",
2636 klass=self.__class__,
2637 decode_path=decode_path + (str(chunk_i),),
2638 offset=chunk.offset,
2640 values.append(bytes(chunk))
2641 bit_len += chunk.bit_len
2642 chunk_last = chunks[-1]
2643 values.append(bytes(chunk_last))
2644 bit_len += chunk_last.bit_len
2645 obj = self.__class__(
2646 value=(bit_len, b"".join(values)),
2649 default=self.default,
2650 optional=self.optional,
2652 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2654 obj.lenindef = lenindef
2655 obj.ber_encoded = True
2656 return obj, (v[EOC_LEN:] if lenindef else v)
2658 klass=self.__class__,
2659 decode_path=decode_path,
2664 return pp_console_row(next(self.pps()))
2666 def pps(self, decode_path=()):
2670 bit_len, blob = self._value
2671 value = "%d bits" % bit_len
2672 if len(self.specs) > 0:
2673 blob = tuple(self.named)
2676 asn1_type_name=self.asn1_type_name,
2677 obj_name=self.__class__.__name__,
2678 decode_path=decode_path,
2681 optional=self.optional,
2682 default=self == self.default,
2683 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2684 expl=None if self._expl is None else tag_decode(self._expl),
2689 expl_offset=self.expl_offset if self.expled else None,
2690 expl_tlen=self.expl_tlen if self.expled else None,
2691 expl_llen=self.expl_llen if self.expled else None,
2692 expl_vlen=self.expl_vlen if self.expled else None,
2693 expl_lenindef=self.expl_lenindef,
2694 lenindef=self.lenindef,
2695 ber_encoded=self.ber_encoded,
2698 defined_by, defined = self.defined or (None, None)
2699 if defined_by is not None:
2701 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2703 for pp in self.pps_lenindef(decode_path):
2707 class OctetString(Obj):
2708 """``OCTET STRING`` binary string type
2710 >>> s = OctetString(b"hello world")
2711 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2712 >>> s == OctetString(b"hello world")
2717 >>> OctetString(b"hello", bounds=(4, 4))
2718 Traceback (most recent call last):
2719 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2720 >>> OctetString(b"hell", bounds=(4, 4))
2721 OCTET STRING 4 bytes 68656c6c
2725 Pay attention that OCTET STRING can be encoded both in primitive
2726 and constructed forms. Decoder always checks constructed form tag
2727 additionally to specified primitive one. If BER decoding is
2728 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2729 of DER restrictions.
2731 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2732 tag_default = tag_encode(4)
2733 asn1_type_name = "OCTET STRING"
2746 :param value: set the value. Either binary type, or
2747 :py:class:`pyderasn.OctetString` object
2748 :param bounds: set ``(MIN, MAX)`` value size constraint.
2749 (-inf, +inf) by default
2750 :param bytes impl: override default tag with ``IMPLICIT`` one
2751 :param bytes expl: override default tag with ``EXPLICIT`` one
2752 :param default: set default value. Type same as in ``value``
2753 :param bool optional: is object ``OPTIONAL`` in sequence
2755 super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
2757 self._bound_min, self._bound_max = getattr(
2761 ) if bounds is None else bounds
2762 if value is not None:
2763 self._value = self._value_sanitize(value)
2764 if default is not None:
2765 default = self._value_sanitize(default)
2766 self.default = self.__class__(
2771 if self._value is None:
2772 self._value = default
2774 tag_klass, _, tag_num = tag_decode(self.tag)
2775 self.tag_constructed = tag_encode(
2777 form=TagFormConstructed,
2781 def _value_sanitize(self, value):
2782 if isinstance(value, binary_type):
2784 elif issubclass(value.__class__, OctetString):
2785 value = value._value
2787 raise InvalidValueType((self.__class__, bytes))
2788 if not self._bound_min <= len(value) <= self._bound_max:
2789 raise BoundsError(self._bound_min, len(value), self._bound_max)
2794 return self._value is not None
2797 obj = self.__class__()
2798 obj._value = self._value
2799 obj._bound_min = self._bound_min
2800 obj._bound_max = self._bound_max
2802 obj._expl = self._expl
2803 obj.default = self.default
2804 obj.optional = self.optional
2805 obj.offset = self.offset
2806 obj.llen = self.llen
2807 obj.vlen = self.vlen
2808 obj.expl_lenindef = self.expl_lenindef
2809 obj.lenindef = self.lenindef
2810 obj.ber_encoded = self.ber_encoded
2813 def __bytes__(self):
2814 self._assert_ready()
2817 def __eq__(self, their):
2818 if isinstance(their, binary_type):
2819 return self._value == their
2820 if not issubclass(their.__class__, OctetString):
2823 self._value == their._value and
2824 self.tag == their.tag and
2825 self._expl == their._expl
2828 def __lt__(self, their):
2829 return self._value < their._value
2840 return self.__class__(
2843 (self._bound_min, self._bound_max)
2844 if bounds is None else bounds
2846 impl=self.tag if impl is None else impl,
2847 expl=self._expl if expl is None else expl,
2848 default=self.default if default is None else default,
2849 optional=self.optional if optional is None else optional,
2853 self._assert_ready()
2856 len_encode(len(self._value)),
2860 def _decode_chunk(self, lv, offset, decode_path):
2862 l, llen, v = len_decode(lv)
2863 except DecodeError as err:
2864 raise err.__class__(
2866 klass=self.__class__,
2867 decode_path=decode_path,
2871 raise NotEnoughData(
2872 "encoded length is longer than data",
2873 klass=self.__class__,
2874 decode_path=decode_path,
2877 v, tail = v[:l], v[l:]
2879 obj = self.__class__(
2881 bounds=(self._bound_min, self._bound_max),
2884 default=self.default,
2885 optional=self.optional,
2886 _decoded=(offset, llen, l),
2888 except DecodeError as err:
2891 klass=self.__class__,
2892 decode_path=decode_path,
2895 except BoundsError as err:
2898 klass=self.__class__,
2899 decode_path=decode_path,
2904 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2906 t, tlen, lv = tag_strip(tlv)
2907 except DecodeError as err:
2908 raise err.__class__(
2910 klass=self.__class__,
2911 decode_path=decode_path,
2917 return self._decode_chunk(lv, offset, decode_path)
2918 if t == self.tag_constructed:
2919 if not ctx.get("bered", False):
2921 "unallowed BER constructed encoding",
2922 klass=self.__class__,
2923 decode_path=decode_path,
2930 l, llen, v = len_decode(lv)
2931 except LenIndefForm:
2932 llen, l, v = 1, 0, lv[1:]
2934 except DecodeError as err:
2935 raise err.__class__(
2937 klass=self.__class__,
2938 decode_path=decode_path,
2942 raise NotEnoughData(
2943 "encoded length is longer than data",
2944 klass=self.__class__,
2945 decode_path=decode_path,
2949 sub_offset = offset + tlen + llen
2953 if v[:EOC_LEN].tobytes() == EOC:
2960 "chunk out of bounds",
2961 klass=self.__class__,
2962 decode_path=decode_path + (str(len(chunks) - 1),),
2963 offset=chunks[-1].offset,
2965 sub_decode_path = decode_path + (str(len(chunks)),)
2967 chunk, v_tail = OctetString().decode(
2970 decode_path=sub_decode_path,
2973 _ctx_immutable=False,
2977 "expected OctetString encoded chunk",
2978 klass=self.__class__,
2979 decode_path=sub_decode_path,
2982 chunks.append(chunk)
2983 sub_offset += chunk.tlvlen
2984 vlen += chunk.tlvlen
2987 obj = self.__class__(
2988 value=b"".join(bytes(chunk) for chunk in chunks),
2989 bounds=(self._bound_min, self._bound_max),
2992 default=self.default,
2993 optional=self.optional,
2994 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2996 except DecodeError as err:
2999 klass=self.__class__,
3000 decode_path=decode_path,
3003 except BoundsError as err:
3006 klass=self.__class__,
3007 decode_path=decode_path,
3010 obj.lenindef = lenindef
3011 obj.ber_encoded = True
3012 return obj, (v[EOC_LEN:] if lenindef else v)
3014 klass=self.__class__,
3015 decode_path=decode_path,
3020 return pp_console_row(next(self.pps()))
3022 def pps(self, decode_path=()):
3025 asn1_type_name=self.asn1_type_name,
3026 obj_name=self.__class__.__name__,
3027 decode_path=decode_path,
3028 value=("%d bytes" % len(self._value)) if self.ready else None,
3029 blob=self._value if self.ready else None,
3030 optional=self.optional,
3031 default=self == self.default,
3032 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3033 expl=None if self._expl is None else tag_decode(self._expl),
3038 expl_offset=self.expl_offset if self.expled else None,
3039 expl_tlen=self.expl_tlen if self.expled else None,
3040 expl_llen=self.expl_llen if self.expled else None,
3041 expl_vlen=self.expl_vlen if self.expled else None,
3042 expl_lenindef=self.expl_lenindef,
3043 lenindef=self.lenindef,
3044 ber_encoded=self.ber_encoded,
3047 defined_by, defined = self.defined or (None, None)
3048 if defined_by is not None:
3050 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3052 for pp in self.pps_lenindef(decode_path):
3057 """``NULL`` null object
3065 tag_default = tag_encode(5)
3066 asn1_type_name = "NULL"
3070 value=None, # unused, but Sequence passes it
3077 :param bytes impl: override default tag with ``IMPLICIT`` one
3078 :param bytes expl: override default tag with ``EXPLICIT`` one
3079 :param bool optional: is object ``OPTIONAL`` in sequence
3081 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3089 obj = self.__class__()
3091 obj._expl = self._expl
3092 obj.default = self.default
3093 obj.optional = self.optional
3094 obj.offset = self.offset
3095 obj.llen = self.llen
3096 obj.vlen = self.vlen
3097 obj.expl_lenindef = self.expl_lenindef
3098 obj.lenindef = self.lenindef
3099 obj.ber_encoded = self.ber_encoded
3102 def __eq__(self, their):
3103 if not issubclass(their.__class__, Null):
3106 self.tag == their.tag and
3107 self._expl == their._expl
3117 return self.__class__(
3118 impl=self.tag if impl is None else impl,
3119 expl=self._expl if expl is None else expl,
3120 optional=self.optional if optional is None else optional,
3124 return self.tag + len_encode(0)
3126 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3128 t, _, lv = tag_strip(tlv)
3129 except DecodeError as err:
3130 raise err.__class__(
3132 klass=self.__class__,
3133 decode_path=decode_path,
3138 klass=self.__class__,
3139 decode_path=decode_path,
3142 if tag_only: # pragma: no cover
3145 l, _, v = len_decode(lv)
3146 except DecodeError as err:
3147 raise err.__class__(
3149 klass=self.__class__,
3150 decode_path=decode_path,
3154 raise InvalidLength(
3155 "Null must have zero length",
3156 klass=self.__class__,
3157 decode_path=decode_path,
3160 obj = self.__class__(
3163 optional=self.optional,
3164 _decoded=(offset, 1, 0),
3169 return pp_console_row(next(self.pps()))
3171 def pps(self, decode_path=()):
3174 asn1_type_name=self.asn1_type_name,
3175 obj_name=self.__class__.__name__,
3176 decode_path=decode_path,
3177 optional=self.optional,
3178 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3179 expl=None if self._expl is None else tag_decode(self._expl),
3184 expl_offset=self.expl_offset if self.expled else None,
3185 expl_tlen=self.expl_tlen if self.expled else None,
3186 expl_llen=self.expl_llen if self.expled else None,
3187 expl_vlen=self.expl_vlen if self.expled else None,
3188 expl_lenindef=self.expl_lenindef,
3191 for pp in self.pps_lenindef(decode_path):
3195 class ObjectIdentifier(Obj):
3196 """``OBJECT IDENTIFIER`` OID type
3198 >>> oid = ObjectIdentifier((1, 2, 3))
3199 OBJECT IDENTIFIER 1.2.3
3200 >>> oid == ObjectIdentifier("1.2.3")
3206 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3207 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3209 >>> str(ObjectIdentifier((3, 1)))
3210 Traceback (most recent call last):
3211 pyderasn.InvalidOID: unacceptable first arc value
3213 __slots__ = ("defines",)
3214 tag_default = tag_encode(6)
3215 asn1_type_name = "OBJECT IDENTIFIER"
3228 :param value: set the value. Either tuples of integers,
3229 string of "."-concatenated integers, or
3230 :py:class:`pyderasn.ObjectIdentifier` object
3231 :param defines: sequence of tuples. Each tuple has two elements.
3232 First one is relative to current one decode
3233 path, aiming to the field defined by that OID.
3234 Read about relative path in
3235 :py:func:`pyderasn.abs_decode_path`. Second
3236 tuple element is ``{OID: pyderasn.Obj()}``
3237 dictionary, mapping between current OID value
3238 and structure applied to defined field.
3239 :ref:`Read about DEFINED BY <definedby>`
3240 :param bytes impl: override default tag with ``IMPLICIT`` one
3241 :param bytes expl: override default tag with ``EXPLICIT`` one
3242 :param default: set default value. Type same as in ``value``
3243 :param bool optional: is object ``OPTIONAL`` in sequence
3245 super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
3247 if value is not None:
3248 self._value = self._value_sanitize(value)
3249 if default is not None:
3250 default = self._value_sanitize(default)
3251 self.default = self.__class__(
3256 if self._value is None:
3257 self._value = default
3258 self.defines = defines
3260 def __add__(self, their):
3261 if isinstance(their, self.__class__):
3262 return self.__class__(self._value + their._value)
3263 if isinstance(their, tuple):
3264 return self.__class__(self._value + their)
3265 raise InvalidValueType((self.__class__, tuple))
3267 def _value_sanitize(self, value):
3268 if issubclass(value.__class__, ObjectIdentifier):
3270 if isinstance(value, string_types):
3272 value = tuple(int(arc) for arc in value.split("."))
3274 raise InvalidOID("unacceptable arcs values")
3275 if isinstance(value, tuple):
3277 raise InvalidOID("less than 2 arcs")
3278 first_arc = value[0]
3279 if first_arc in (0, 1):
3280 if not (0 <= value[1] <= 39):
3281 raise InvalidOID("second arc is too wide")
3282 elif first_arc == 2:
3285 raise InvalidOID("unacceptable first arc value")
3287 raise InvalidValueType((self.__class__, str, tuple))
3291 return self._value is not None
3294 obj = self.__class__()
3295 obj._value = self._value
3296 obj.defines = self.defines
3298 obj._expl = self._expl
3299 obj.default = self.default
3300 obj.optional = self.optional
3301 obj.offset = self.offset
3302 obj.llen = self.llen
3303 obj.vlen = self.vlen
3304 obj.expl_lenindef = self.expl_lenindef
3305 obj.lenindef = self.lenindef
3306 obj.ber_encoded = self.ber_encoded
3310 self._assert_ready()
3311 return iter(self._value)
3314 return ".".join(str(arc) for arc in self._value or ())
3317 self._assert_ready()
3320 bytes(self._expl or b"") +
3321 str(self._value).encode("ascii"),
3324 def __eq__(self, their):
3325 if isinstance(their, tuple):
3326 return self._value == their
3327 if not issubclass(their.__class__, ObjectIdentifier):
3330 self.tag == their.tag and
3331 self._expl == their._expl and
3332 self._value == their._value
3335 def __lt__(self, their):
3336 return self._value < their._value
3347 return self.__class__(
3349 defines=self.defines if defines is None else defines,
3350 impl=self.tag if impl is None else impl,
3351 expl=self._expl if expl is None else expl,
3352 default=self.default if default is None else default,
3353 optional=self.optional if optional is None else optional,
3357 self._assert_ready()
3359 first_value = value[1]
3360 first_arc = value[0]
3363 elif first_arc == 1:
3365 elif first_arc == 2:
3367 else: # pragma: no cover
3368 raise RuntimeError("invalid arc is stored")
3369 octets = [zero_ended_encode(first_value)]
3370 for arc in value[2:]:
3371 octets.append(zero_ended_encode(arc))
3372 v = b"".join(octets)
3373 return b"".join((self.tag, len_encode(len(v)), v))
3375 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3377 t, _, lv = tag_strip(tlv)
3378 except DecodeError as err:
3379 raise err.__class__(
3381 klass=self.__class__,
3382 decode_path=decode_path,
3387 klass=self.__class__,
3388 decode_path=decode_path,
3391 if tag_only: # pragma: no cover
3394 l, llen, v = len_decode(lv)
3395 except DecodeError as err:
3396 raise err.__class__(
3398 klass=self.__class__,
3399 decode_path=decode_path,
3403 raise NotEnoughData(
3404 "encoded length is longer than data",
3405 klass=self.__class__,
3406 decode_path=decode_path,
3410 raise NotEnoughData(
3412 klass=self.__class__,
3413 decode_path=decode_path,
3416 v, tail = v[:l], v[l:]
3423 octet = indexbytes(v, i)
3424 if i == 0 and octet == 0x80:
3425 if ctx.get("bered", False):
3428 raise DecodeError("non normalized arc encoding")
3429 arc = (arc << 7) | (octet & 0x7F)
3430 if octet & 0x80 == 0:
3438 klass=self.__class__,
3439 decode_path=decode_path,
3443 second_arc = arcs[0]
3444 if 0 <= second_arc <= 39:
3446 elif 40 <= second_arc <= 79:
3452 obj = self.__class__(
3453 value=tuple([first_arc, second_arc] + arcs[1:]),
3456 default=self.default,
3457 optional=self.optional,
3458 _decoded=(offset, llen, l),
3461 obj.ber_encoded = True
3465 return pp_console_row(next(self.pps()))
3467 def pps(self, decode_path=()):
3470 asn1_type_name=self.asn1_type_name,
3471 obj_name=self.__class__.__name__,
3472 decode_path=decode_path,
3473 value=str(self) if self.ready else None,
3474 optional=self.optional,
3475 default=self == self.default,
3476 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3477 expl=None if self._expl is None else tag_decode(self._expl),
3482 expl_offset=self.expl_offset if self.expled else None,
3483 expl_tlen=self.expl_tlen if self.expled else None,
3484 expl_llen=self.expl_llen if self.expled else None,
3485 expl_vlen=self.expl_vlen if self.expled else None,
3486 expl_lenindef=self.expl_lenindef,
3487 ber_encoded=self.ber_encoded,
3490 for pp in self.pps_lenindef(decode_path):
3494 class Enumerated(Integer):
3495 """``ENUMERATED`` integer type
3497 This type is identical to :py:class:`pyderasn.Integer`, but requires
3498 schema to be specified and does not accept values missing from it.
3501 tag_default = tag_encode(10)
3502 asn1_type_name = "ENUMERATED"
3513 bounds=None, # dummy argument, workability for Integer.decode
3515 super(Enumerated, self).__init__(
3516 value, bounds, impl, expl,default, optional, _specs, _decoded,
3518 if len(self.specs) == 0:
3519 raise ValueError("schema must be specified")
3521 def _value_sanitize(self, value):
3522 if isinstance(value, self.__class__):
3523 value = value._value
3524 elif isinstance(value, integer_types):
3525 for _value in itervalues(self.specs):
3530 "unknown integer value: %s" % value,
3531 klass=self.__class__,
3533 elif isinstance(value, string_types):
3534 value = self.specs.get(value)
3536 raise ObjUnknown("integer value: %s" % value)
3538 raise InvalidValueType((self.__class__, int, str))
3542 obj = self.__class__(_specs=self.specs)
3543 obj._value = self._value
3544 obj._bound_min = self._bound_min
3545 obj._bound_max = self._bound_max
3547 obj._expl = self._expl
3548 obj.default = self.default
3549 obj.optional = self.optional
3550 obj.offset = self.offset
3551 obj.llen = self.llen
3552 obj.vlen = self.vlen
3553 obj.expl_lenindef = self.expl_lenindef
3554 obj.lenindef = self.lenindef
3555 obj.ber_encoded = self.ber_encoded
3567 return self.__class__(
3569 impl=self.tag if impl is None else impl,
3570 expl=self._expl if expl is None else expl,
3571 default=self.default if default is None else default,
3572 optional=self.optional if optional is None else optional,
3577 def escape_control_unicode(c):
3578 if unicat(c).startswith("C"):
3579 c = repr(c).lstrip("u").strip("'")
3583 class CommonString(OctetString):
3584 """Common class for all strings
3586 Everything resembles :py:class:`pyderasn.OctetString`, except
3587 ability to deal with unicode text strings.
3589 >>> hexenc("привет мир".encode("utf-8"))
3590 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3591 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3593 >>> s = UTF8String("привет мир")
3594 UTF8String UTF8String привет мир
3596 'привет мир'
3597 >>> hexenc(bytes(s))
3598 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3600 >>> PrintableString("привет мир")
3601 Traceback (most recent call last):
3602 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3604 >>> BMPString("ада", bounds=(2, 2))
3605 Traceback (most recent call last):
3606 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3607 >>> s = BMPString("ад", bounds=(2, 2))
3610 >>> hexenc(bytes(s))
3618 * - :py:class:`pyderasn.UTF8String`
3620 * - :py:class:`pyderasn.NumericString`
3622 * - :py:class:`pyderasn.PrintableString`
3624 * - :py:class:`pyderasn.TeletexString`
3626 * - :py:class:`pyderasn.T61String`
3628 * - :py:class:`pyderasn.VideotexString`
3630 * - :py:class:`pyderasn.IA5String`
3632 * - :py:class:`pyderasn.GraphicString`
3634 * - :py:class:`pyderasn.VisibleString`
3636 * - :py:class:`pyderasn.ISO646String`
3638 * - :py:class:`pyderasn.GeneralString`
3640 * - :py:class:`pyderasn.UniversalString`
3642 * - :py:class:`pyderasn.BMPString`
3647 def _value_sanitize(self, value):
3649 value_decoded = None
3650 if isinstance(value, self.__class__):
3651 value_raw = value._value
3652 elif isinstance(value, text_type):
3653 value_decoded = value
3654 elif isinstance(value, binary_type):
3657 raise InvalidValueType((self.__class__, text_type, binary_type))
3660 value_decoded.encode(self.encoding)
3661 if value_raw is None else value_raw
3664 value_raw.decode(self.encoding)
3665 if value_decoded is None else value_decoded
3667 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3668 raise DecodeError(str(err))
3669 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3677 def __eq__(self, their):
3678 if isinstance(their, binary_type):
3679 return self._value == their
3680 if isinstance(their, text_type):
3681 return self._value == their.encode(self.encoding)
3682 if not isinstance(their, self.__class__):
3685 self._value == their._value and
3686 self.tag == their.tag and
3687 self._expl == their._expl
3690 def __unicode__(self):
3692 return self._value.decode(self.encoding)
3693 return text_type(self._value)
3696 return pp_console_row(next(self.pps(no_unicode=PY2)))
3698 def pps(self, decode_path=(), no_unicode=False):
3702 hexenc(bytes(self)) if no_unicode else
3703 "".join(escape_control_unicode(c) for c in self.__unicode__())
3707 asn1_type_name=self.asn1_type_name,
3708 obj_name=self.__class__.__name__,
3709 decode_path=decode_path,
3711 optional=self.optional,
3712 default=self == self.default,
3713 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3714 expl=None if self._expl is None else tag_decode(self._expl),
3719 expl_offset=self.expl_offset if self.expled else None,
3720 expl_tlen=self.expl_tlen if self.expled else None,
3721 expl_llen=self.expl_llen if self.expled else None,
3722 expl_vlen=self.expl_vlen if self.expled else None,
3723 expl_lenindef=self.expl_lenindef,
3724 ber_encoded=self.ber_encoded,
3727 for pp in self.pps_lenindef(decode_path):
3731 class UTF8String(CommonString):
3733 tag_default = tag_encode(12)
3735 asn1_type_name = "UTF8String"
3738 class AllowableCharsMixin(object):
3740 def allowable_chars(self):
3742 return self._allowable_chars
3743 return frozenset(six_unichr(c) for c in self._allowable_chars)
3746 class NumericString(AllowableCharsMixin, CommonString):
3749 Its value is properly sanitized: only ASCII digits with spaces can
3752 >>> NumericString().allowable_chars
3753 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3756 tag_default = tag_encode(18)
3758 asn1_type_name = "NumericString"
3759 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3761 def _value_sanitize(self, value):
3762 value = super(NumericString, self)._value_sanitize(value)
3763 if not frozenset(value) <= self._allowable_chars:
3764 raise DecodeError("non-numeric value")
3768 class PrintableString(AllowableCharsMixin, CommonString):
3771 Its value is properly sanitized: see X.680 41.4 table 10.
3773 >>> PrintableString().allowable_chars
3774 frozenset([' ', "'", ..., 'z'])
3777 tag_default = tag_encode(19)
3779 asn1_type_name = "PrintableString"
3780 _allowable_chars = frozenset(
3781 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3783 _asterisk = frozenset("*".encode("ascii"))
3784 _ampersand = frozenset("&".encode("ascii"))
3795 allow_asterisk=False,
3796 allow_ampersand=False,
3799 :param allow_asterisk: allow asterisk character
3800 :param allow_ampersand: allow ampersand character
3803 self._allowable_chars |= self._asterisk
3805 self._allowable_chars |= self._ampersand
3806 super(PrintableString, self).__init__(
3807 value, bounds, impl, expl, default, optional, _decoded,
3810 def _value_sanitize(self, value):
3811 value = super(PrintableString, self)._value_sanitize(value)
3812 if not frozenset(value) <= self._allowable_chars:
3813 raise DecodeError("non-printable value")
3817 obj = super(PrintableString, self).copy()
3818 obj._allowable_chars = self._allowable_chars
3830 return self.__class__(
3833 (self._bound_min, self._bound_max)
3834 if bounds is None else bounds
3836 impl=self.tag if impl is None else impl,
3837 expl=self._expl if expl is None else expl,
3838 default=self.default if default is None else default,
3839 optional=self.optional if optional is None else optional,
3840 allow_asterisk=self._asterisk <= self._allowable_chars,
3841 allow_ampersand=self._ampersand <= self._allowable_chars,
3845 class TeletexString(CommonString):
3847 tag_default = tag_encode(20)
3849 asn1_type_name = "TeletexString"
3852 class T61String(TeletexString):
3854 asn1_type_name = "T61String"
3857 class VideotexString(CommonString):
3859 tag_default = tag_encode(21)
3860 encoding = "iso-8859-1"
3861 asn1_type_name = "VideotexString"
3864 class IA5String(CommonString):
3866 tag_default = tag_encode(22)
3868 asn1_type_name = "IA5"
3871 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3872 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3873 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3876 class UTCTime(CommonString):
3877 """``UTCTime`` datetime type
3879 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3880 UTCTime UTCTime 2017-09-30T22:07:50
3886 datetime.datetime(2017, 9, 30, 22, 7, 50)
3887 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3888 datetime.datetime(1957, 9, 30, 22, 7, 50)
3892 BER encoding is unsupported.
3895 tag_default = tag_encode(23)
3897 asn1_type_name = "UTCTime"
3907 bounds=None, # dummy argument, workability for OctetString.decode
3910 :param value: set the value. Either datetime type, or
3911 :py:class:`pyderasn.UTCTime` object
3912 :param bytes impl: override default tag with ``IMPLICIT`` one
3913 :param bytes expl: override default tag with ``EXPLICIT`` one
3914 :param default: set default value. Type same as in ``value``
3915 :param bool optional: is object ``OPTIONAL`` in sequence
3917 super(UTCTime, self).__init__(
3918 None, None, impl, expl, default, optional, _decoded,
3921 if value is not None:
3922 self._value = self._value_sanitize(value)
3923 if default is not None:
3924 default = self._value_sanitize(default)
3925 self.default = self.__class__(
3930 if self._value is None:
3931 self._value = default
3933 def _strptime(self, value):
3934 # datetime.strptime's format: %y%m%d%H%M%SZ
3935 if len(value) != LEN_YYMMDDHHMMSSZ:
3936 raise ValueError("invalid UTCTime length")
3937 if value[-1] != "Z":
3938 raise ValueError("non UTC timezone")
3940 2000 + int(value[:2]), # %y
3941 int(value[2:4]), # %m
3942 int(value[4:6]), # %d
3943 int(value[6:8]), # %H
3944 int(value[8:10]), # %M
3945 int(value[10:12]), # %S
3948 def _value_sanitize(self, value):
3949 if isinstance(value, binary_type):
3951 value_decoded = value.decode("ascii")
3952 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3953 raise DecodeError("invalid UTCTime encoding: %r" % err)
3955 self._strptime(value_decoded)
3956 except (TypeError, ValueError) as err:
3957 raise DecodeError("invalid UTCTime format: %r" % err)
3959 if isinstance(value, self.__class__):
3961 if isinstance(value, datetime):
3962 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3963 raise InvalidValueType((self.__class__, datetime))
3965 def __eq__(self, their):
3966 if isinstance(their, binary_type):
3967 return self._value == their
3968 if isinstance(their, datetime):
3969 return self.todatetime() == their
3970 if not isinstance(their, self.__class__):
3973 self._value == their._value and
3974 self.tag == their.tag and
3975 self._expl == their._expl
3978 def todatetime(self):
3979 """Convert to datetime
3983 Pay attention that UTCTime can not hold full year, so all years
3984 having < 50 years are treated as 20xx, 19xx otherwise, according
3985 to X.509 recomendation.
3987 value = self._strptime(self._value.decode("ascii"))
3988 year = value.year % 100
3990 year=(2000 + year) if year < 50 else (1900 + year),
3994 minute=value.minute,
3995 second=value.second,
3999 return pp_console_row(next(self.pps()))
4001 def pps(self, decode_path=()):
4004 asn1_type_name=self.asn1_type_name,
4005 obj_name=self.__class__.__name__,
4006 decode_path=decode_path,
4007 value=self.todatetime().isoformat() if self.ready else None,
4008 optional=self.optional,
4009 default=self == self.default,
4010 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4011 expl=None if self._expl is None else tag_decode(self._expl),
4016 expl_offset=self.expl_offset if self.expled else None,
4017 expl_tlen=self.expl_tlen if self.expled else None,
4018 expl_llen=self.expl_llen if self.expled else None,
4019 expl_vlen=self.expl_vlen if self.expled else None,
4020 expl_lenindef=self.expl_lenindef,
4021 ber_encoded=self.ber_encoded,
4024 for pp in self.pps_lenindef(decode_path):
4028 class GeneralizedTime(UTCTime):
4029 """``GeneralizedTime`` datetime type
4031 This type is similar to :py:class:`pyderasn.UTCTime`.
4033 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4034 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4036 '20170930220750.000123Z'
4037 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4038 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4042 BER encoding is unsupported.
4046 Only microsecond fractions are supported.
4047 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4048 higher precision values.
4051 tag_default = tag_encode(24)
4052 asn1_type_name = "GeneralizedTime"
4054 def _strptime(self, value):
4056 if l == LEN_YYYYMMDDHHMMSSZ:
4057 # datetime.strptime's format: %y%m%d%H%M%SZ
4058 if value[-1] != "Z":
4059 raise ValueError("non UTC timezone")
4061 int(value[:4]), # %Y
4062 int(value[4:6]), # %m
4063 int(value[6:8]), # %d
4064 int(value[8:10]), # %H
4065 int(value[10:12]), # %M
4066 int(value[12:14]), # %S
4068 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4069 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4070 if value[-1] != "Z":
4071 raise ValueError("non UTC timezone")
4072 if value[14] != ".":
4073 raise ValueError("no fractions separator")
4076 raise ValueError("trailing zero")
4079 raise ValueError("only microsecond fractions are supported")
4080 us = int(us + ("0" * (6 - us_len)))
4082 int(value[:4]), # %Y
4083 int(value[4:6]), # %m
4084 int(value[6:8]), # %d
4085 int(value[8:10]), # %H
4086 int(value[10:12]), # %M
4087 int(value[12:14]), # %S
4091 raise ValueError("invalid GeneralizedTime length")
4093 def _value_sanitize(self, value):
4094 if isinstance(value, binary_type):
4096 value_decoded = value.decode("ascii")
4097 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4098 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4100 self._strptime(value_decoded)
4101 except (TypeError, ValueError) as err:
4103 "invalid GeneralizedTime format: %r" % err,
4104 klass=self.__class__,
4107 if isinstance(value, self.__class__):
4109 if isinstance(value, datetime):
4110 encoded = value.strftime("%Y%m%d%H%M%S")
4111 if value.microsecond > 0:
4112 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4113 return (encoded + "Z").encode("ascii")
4114 raise InvalidValueType((self.__class__, datetime))
4116 def todatetime(self):
4117 return self._strptime(self._value.decode("ascii"))
4120 class GraphicString(CommonString):
4122 tag_default = tag_encode(25)
4123 encoding = "iso-8859-1"
4124 asn1_type_name = "GraphicString"
4127 class VisibleString(CommonString):
4129 tag_default = tag_encode(26)
4131 asn1_type_name = "VisibleString"
4134 class ISO646String(VisibleString):
4136 asn1_type_name = "ISO646String"
4139 class GeneralString(CommonString):
4141 tag_default = tag_encode(27)
4142 encoding = "iso-8859-1"
4143 asn1_type_name = "GeneralString"
4146 class UniversalString(CommonString):
4148 tag_default = tag_encode(28)
4149 encoding = "utf-32-be"
4150 asn1_type_name = "UniversalString"
4153 class BMPString(CommonString):
4155 tag_default = tag_encode(30)
4156 encoding = "utf-16-be"
4157 asn1_type_name = "BMPString"
4161 """``CHOICE`` special type
4165 class GeneralName(Choice):
4167 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4168 ("dNSName", IA5String(impl=tag_ctxp(2))),
4171 >>> gn = GeneralName()
4173 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4174 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4175 >>> gn["dNSName"] = IA5String("bar.baz")
4176 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4177 >>> gn["rfc822Name"]
4180 [2] IA5String IA5 bar.baz
4183 >>> gn.value == gn["dNSName"]
4186 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4188 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4189 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4191 __slots__ = ("specs",)
4193 asn1_type_name = "CHOICE"
4206 :param value: set the value. Either ``(choice, value)`` tuple, or
4207 :py:class:`pyderasn.Choice` object
4208 :param bytes impl: can not be set, do **not** use it
4209 :param bytes expl: override default tag with ``EXPLICIT`` one
4210 :param default: set default value. Type same as in ``value``
4211 :param bool optional: is object ``OPTIONAL`` in sequence
4213 if impl is not None:
4214 raise ValueError("no implicit tag allowed for CHOICE")
4215 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4217 schema = getattr(self, "schema", ())
4218 if len(schema) == 0:
4219 raise ValueError("schema must be specified")
4221 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4224 if value is not None:
4225 self._value = self._value_sanitize(value)
4226 if default is not None:
4227 default_value = self._value_sanitize(default)
4228 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4229 default_obj.specs = self.specs
4230 default_obj._value = default_value
4231 self.default = default_obj
4233 self._value = default_obj.copy()._value
4235 def _value_sanitize(self, value):
4236 if isinstance(value, tuple) and len(value) == 2:
4238 spec = self.specs.get(choice)
4240 raise ObjUnknown(choice)
4241 if not isinstance(obj, spec.__class__):
4242 raise InvalidValueType((spec,))
4243 return (choice, spec(obj))
4244 if isinstance(value, self.__class__):
4246 raise InvalidValueType((self.__class__, tuple))
4250 return self._value is not None and self._value[1].ready
4254 return self.expl_lenindef or (
4255 (self._value is not None) and
4256 self._value[1].bered
4260 obj = self.__class__(schema=self.specs)
4261 obj._expl = self._expl
4262 obj.default = self.default
4263 obj.optional = self.optional
4264 obj.offset = self.offset
4265 obj.llen = self.llen
4266 obj.vlen = self.vlen
4267 obj.expl_lenindef = self.expl_lenindef
4268 obj.lenindef = self.lenindef
4269 obj.ber_encoded = self.ber_encoded
4271 if value is not None:
4272 obj._value = (value[0], value[1].copy())
4275 def __eq__(self, their):
4276 if isinstance(their, tuple) and len(their) == 2:
4277 return self._value == their
4278 if not isinstance(their, self.__class__):
4281 self.specs == their.specs and
4282 self._value == their._value
4292 return self.__class__(
4295 expl=self._expl if expl is None else expl,
4296 default=self.default if default is None else default,
4297 optional=self.optional if optional is None else optional,
4302 self._assert_ready()
4303 return self._value[0]
4307 self._assert_ready()
4308 return self._value[1]
4310 def __getitem__(self, key):
4311 if key not in self.specs:
4312 raise ObjUnknown(key)
4313 if self._value is None:
4315 choice, value = self._value
4320 def __setitem__(self, key, value):
4321 spec = self.specs.get(key)
4323 raise ObjUnknown(key)
4324 if not isinstance(value, spec.__class__):
4325 raise InvalidValueType((spec.__class__,))
4326 self._value = (key, spec(value))
4334 return self._value[1].decoded if self.ready else False
4337 self._assert_ready()
4338 return self._value[1].encode()
4340 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4341 for choice, spec in iteritems(self.specs):
4342 sub_decode_path = decode_path + (choice,)
4348 decode_path=sub_decode_path,
4351 _ctx_immutable=False,
4358 klass=self.__class__,
4359 decode_path=decode_path,
4362 if tag_only: # pragma: no cover
4364 value, tail = spec.decode(
4368 decode_path=sub_decode_path,
4370 _ctx_immutable=False,
4372 obj = self.__class__(
4375 default=self.default,
4376 optional=self.optional,
4377 _decoded=(offset, 0, value.fulllen),
4379 obj._value = (choice, value)
4383 value = pp_console_row(next(self.pps()))
4385 value = "%s[%r]" % (value, self.value)
4388 def pps(self, decode_path=()):
4391 asn1_type_name=self.asn1_type_name,
4392 obj_name=self.__class__.__name__,
4393 decode_path=decode_path,
4394 value=self.choice if self.ready else None,
4395 optional=self.optional,
4396 default=self == self.default,
4397 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4398 expl=None if self._expl is None else tag_decode(self._expl),
4403 expl_lenindef=self.expl_lenindef,
4407 yield self.value.pps(decode_path=decode_path + (self.choice,))
4408 for pp in self.pps_lenindef(decode_path):
4412 class PrimitiveTypes(Choice):
4413 """Predefined ``CHOICE`` for all generic primitive types
4415 It could be useful for general decoding of some unspecified values:
4417 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4418 OCTET STRING 3 bytes 666f6f
4419 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4423 schema = tuple((klass.__name__, klass()) for klass in (
4448 """``ANY`` special type
4450 >>> Any(Integer(-123))
4452 >>> a = Any(OctetString(b"hello world").encode())
4453 ANY 040b68656c6c6f20776f726c64
4454 >>> hexenc(bytes(a))
4455 b'0x040x0bhello world'
4457 __slots__ = ("defined",)
4458 tag_default = tag_encode(0)
4459 asn1_type_name = "ANY"
4469 :param value: set the value. Either any kind of pyderasn's
4470 **ready** object, or bytes. Pay attention that
4471 **no** validation is performed is raw binary value
4473 :param bytes expl: override default tag with ``EXPLICIT`` one
4474 :param bool optional: is object ``OPTIONAL`` in sequence
4476 super(Any, self).__init__(None, expl, None, optional, _decoded)
4477 self._value = None if value is None else self._value_sanitize(value)
4480 def _value_sanitize(self, value):
4481 if isinstance(value, binary_type):
4483 if isinstance(value, self.__class__):
4485 if isinstance(value, Obj):
4486 return value.encode()
4487 raise InvalidValueType((self.__class__, Obj, binary_type))
4491 return self._value is not None
4495 if self.expl_lenindef or self.lenindef:
4497 if self.defined is None:
4499 return self.defined[1].bered
4502 obj = self.__class__()
4503 obj._value = self._value
4505 obj._expl = self._expl
4506 obj.optional = self.optional
4507 obj.offset = self.offset
4508 obj.llen = self.llen
4509 obj.vlen = self.vlen
4510 obj.expl_lenindef = self.expl_lenindef
4511 obj.lenindef = self.lenindef
4512 obj.ber_encoded = self.ber_encoded
4515 def __eq__(self, their):
4516 if isinstance(their, binary_type):
4517 return self._value == their
4518 if issubclass(their.__class__, Any):
4519 return self._value == their._value
4528 return self.__class__(
4530 expl=self._expl if expl is None else expl,
4531 optional=self.optional if optional is None else optional,
4534 def __bytes__(self):
4535 self._assert_ready()
4543 self._assert_ready()
4546 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4548 t, tlen, lv = tag_strip(tlv)
4549 except DecodeError as err:
4550 raise err.__class__(
4552 klass=self.__class__,
4553 decode_path=decode_path,
4557 l, llen, v = len_decode(lv)
4558 except LenIndefForm as err:
4559 if not ctx.get("bered", False):
4560 raise err.__class__(
4562 klass=self.__class__,
4563 decode_path=decode_path,
4566 llen, vlen, v = 1, 0, lv[1:]
4567 sub_offset = offset + tlen + llen
4569 while v[:EOC_LEN].tobytes() != EOC:
4570 chunk, v = Any().decode(
4573 decode_path=decode_path + (str(chunk_i),),
4576 _ctx_immutable=False,
4578 vlen += chunk.tlvlen
4579 sub_offset += chunk.tlvlen
4581 tlvlen = tlen + llen + vlen + EOC_LEN
4582 obj = self.__class__(
4583 value=tlv[:tlvlen].tobytes(),
4585 optional=self.optional,
4586 _decoded=(offset, 0, tlvlen),
4590 return obj, v[EOC_LEN:]
4591 except DecodeError as err:
4592 raise err.__class__(
4594 klass=self.__class__,
4595 decode_path=decode_path,
4599 raise NotEnoughData(
4600 "encoded length is longer than data",
4601 klass=self.__class__,
4602 decode_path=decode_path,
4605 tlvlen = tlen + llen + l
4606 v, tail = tlv[:tlvlen], v[l:]
4607 obj = self.__class__(
4610 optional=self.optional,
4611 _decoded=(offset, 0, tlvlen),
4617 return pp_console_row(next(self.pps()))
4619 def pps(self, decode_path=()):
4622 asn1_type_name=self.asn1_type_name,
4623 obj_name=self.__class__.__name__,
4624 decode_path=decode_path,
4625 blob=self._value if self.ready else None,
4626 optional=self.optional,
4627 default=self == self.default,
4628 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4629 expl=None if self._expl is None else tag_decode(self._expl),
4634 expl_offset=self.expl_offset if self.expled else None,
4635 expl_tlen=self.expl_tlen if self.expled else None,
4636 expl_llen=self.expl_llen if self.expled else None,
4637 expl_vlen=self.expl_vlen if self.expled else None,
4638 expl_lenindef=self.expl_lenindef,
4639 lenindef=self.lenindef,
4642 defined_by, defined = self.defined or (None, None)
4643 if defined_by is not None:
4645 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4647 for pp in self.pps_lenindef(decode_path):
4651 ########################################################################
4652 # ASN.1 constructed types
4653 ########################################################################
4655 def get_def_by_path(defines_by_path, sub_decode_path):
4656 """Get define by decode path
4658 for path, define in defines_by_path:
4659 if len(path) != len(sub_decode_path):
4661 for p1, p2 in zip(path, sub_decode_path):
4662 if (p1 != any) and (p1 != p2):
4668 def abs_decode_path(decode_path, rel_path):
4669 """Create an absolute decode path from current and relative ones
4671 :param decode_path: current decode path, starting point. Tuple of strings
4672 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4673 If first tuple's element is "/", then treat it as
4674 an absolute path, ignoring ``decode_path`` as
4675 starting point. Also this tuple can contain ".."
4676 elements, stripping the leading element from
4679 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4680 ("foo", "bar", "baz", "whatever")
4681 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4683 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4686 if rel_path[0] == "/":
4688 if rel_path[0] == "..":
4689 return abs_decode_path(decode_path[:-1], rel_path[1:])
4690 return decode_path + rel_path
4693 class Sequence(Obj):
4694 """``SEQUENCE`` structure type
4696 You have to make specification of sequence::
4698 class Extension(Sequence):
4700 ("extnID", ObjectIdentifier()),
4701 ("critical", Boolean(default=False)),
4702 ("extnValue", OctetString()),
4705 Then, you can work with it as with dictionary.
4707 >>> ext = Extension()
4708 >>> Extension().specs
4710 ('extnID', OBJECT IDENTIFIER),
4711 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4712 ('extnValue', OCTET STRING),
4714 >>> ext["extnID"] = "1.2.3"
4715 Traceback (most recent call last):
4716 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4717 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4719 You can determine if sequence is ready to be encoded:
4724 Traceback (most recent call last):
4725 pyderasn.ObjNotReady: object is not ready: extnValue
4726 >>> ext["extnValue"] = OctetString(b"foobar")
4730 Value you want to assign, must have the same **type** as in
4731 corresponding specification, but it can have different tags,
4732 optional/default attributes -- they will be taken from specification
4735 class TBSCertificate(Sequence):
4737 ("version", Version(expl=tag_ctxc(0), default="v1")),
4740 >>> tbs = TBSCertificate()
4741 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4743 Assign ``None`` to remove value from sequence.
4745 You can set values in Sequence during its initialization:
4747 >>> AlgorithmIdentifier((
4748 ("algorithm", ObjectIdentifier("1.2.3")),
4749 ("parameters", Any(Null()))
4751 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4753 You can determine if value exists/set in the sequence and take its value:
4755 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4758 OBJECT IDENTIFIER 1.2.3
4760 But pay attention that if value has default, then it won't be (not
4761 in) in the sequence (because ``DEFAULT`` must not be encoded in
4762 DER), but you can read its value:
4764 >>> "critical" in ext, ext["critical"]
4765 (False, BOOLEAN False)
4766 >>> ext["critical"] = Boolean(True)
4767 >>> "critical" in ext, ext["critical"]
4768 (True, BOOLEAN True)
4770 All defaulted values are always optional.
4772 .. _allow_default_values_ctx:
4774 DER prohibits default value encoding and will raise an error if
4775 default value is unexpectedly met during decode.
4776 If :ref:`bered <bered_ctx>` context option is set, then no error
4777 will be raised, but ``bered`` attribute set. You can disable strict
4778 defaulted values existence validation by setting
4779 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4781 Two sequences are equal if they have equal specification (schema),
4782 implicit/explicit tagging and the same values.
4784 __slots__ = ("specs",)
4785 tag_default = tag_encode(form=TagFormConstructed, num=16)
4786 asn1_type_name = "SEQUENCE"
4798 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4800 schema = getattr(self, "schema", ())
4802 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4805 if value is not None:
4806 if issubclass(value.__class__, Sequence):
4807 self._value = value._value
4808 elif hasattr(value, "__iter__"):
4809 for seq_key, seq_value in value:
4810 self[seq_key] = seq_value
4812 raise InvalidValueType((Sequence,))
4813 if default is not None:
4814 if not issubclass(default.__class__, Sequence):
4815 raise InvalidValueType((Sequence,))
4816 default_value = default._value
4817 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4818 default_obj.specs = self.specs
4819 default_obj._value = default_value
4820 self.default = default_obj
4822 self._value = default_obj.copy()._value
4826 for name, spec in iteritems(self.specs):
4827 value = self._value.get(name)
4838 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4840 return any(value.bered for value in itervalues(self._value))
4843 obj = self.__class__(schema=self.specs)
4845 obj._expl = self._expl
4846 obj.default = self.default
4847 obj.optional = self.optional
4848 obj.offset = self.offset
4849 obj.llen = self.llen
4850 obj.vlen = self.vlen
4851 obj.expl_lenindef = self.expl_lenindef
4852 obj.lenindef = self.lenindef
4853 obj.ber_encoded = self.ber_encoded
4854 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4857 def __eq__(self, their):
4858 if not isinstance(their, self.__class__):
4861 self.specs == their.specs and
4862 self.tag == their.tag and
4863 self._expl == their._expl and
4864 self._value == their._value
4875 return self.__class__(
4878 impl=self.tag if impl is None else impl,
4879 expl=self._expl if expl is None else expl,
4880 default=self.default if default is None else default,
4881 optional=self.optional if optional is None else optional,
4884 def __contains__(self, key):
4885 return key in self._value
4887 def __setitem__(self, key, value):
4888 spec = self.specs.get(key)
4890 raise ObjUnknown(key)
4892 self._value.pop(key, None)
4894 if not isinstance(value, spec.__class__):
4895 raise InvalidValueType((spec.__class__,))
4896 value = spec(value=value)
4897 if spec.default is not None and value == spec.default:
4898 self._value.pop(key, None)
4900 self._value[key] = value
4902 def __getitem__(self, key):
4903 value = self._value.get(key)
4904 if value is not None:
4906 spec = self.specs.get(key)
4908 raise ObjUnknown(key)
4909 if spec.default is not None:
4913 def _encoded_values(self):
4915 for name, spec in iteritems(self.specs):
4916 value = self._value.get(name)
4920 raise ObjNotReady(name)
4921 raws.append(value.encode())
4925 v = b"".join(self._encoded_values())
4926 return b"".join((self.tag, len_encode(len(v)), v))
4928 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4930 t, tlen, lv = tag_strip(tlv)
4931 except DecodeError as err:
4932 raise err.__class__(
4934 klass=self.__class__,
4935 decode_path=decode_path,
4940 klass=self.__class__,
4941 decode_path=decode_path,
4944 if tag_only: # pragma: no cover
4947 ctx_bered = ctx.get("bered", False)
4949 l, llen, v = len_decode(lv)
4950 except LenIndefForm as err:
4952 raise err.__class__(
4954 klass=self.__class__,
4955 decode_path=decode_path,
4958 l, llen, v = 0, 1, lv[1:]
4960 except DecodeError as err:
4961 raise err.__class__(
4963 klass=self.__class__,
4964 decode_path=decode_path,
4968 raise NotEnoughData(
4969 "encoded length is longer than data",
4970 klass=self.__class__,
4971 decode_path=decode_path,
4975 v, tail = v[:l], v[l:]
4977 sub_offset = offset + tlen + llen
4980 ctx_allow_default_values = ctx.get("allow_default_values", False)
4981 for name, spec in iteritems(self.specs):
4982 if spec.optional and (
4983 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4987 sub_decode_path = decode_path + (name,)
4989 value, v_tail = spec.decode(
4993 decode_path=sub_decode_path,
4995 _ctx_immutable=False,
4997 except TagMismatch as err:
4998 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
5002 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
5003 if defined is not None:
5004 defined_by, defined_spec = defined
5005 if issubclass(value.__class__, SequenceOf):
5006 for i, _value in enumerate(value):
5007 sub_sub_decode_path = sub_decode_path + (
5009 DecodePathDefBy(defined_by),
5011 defined_value, defined_tail = defined_spec.decode(
5012 memoryview(bytes(_value)),
5014 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5015 if value.expled else (value.tlen + value.llen)
5018 decode_path=sub_sub_decode_path,
5020 _ctx_immutable=False,
5022 if len(defined_tail) > 0:
5025 klass=self.__class__,
5026 decode_path=sub_sub_decode_path,
5029 _value.defined = (defined_by, defined_value)
5031 defined_value, defined_tail = defined_spec.decode(
5032 memoryview(bytes(value)),
5034 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5035 if value.expled else (value.tlen + value.llen)
5038 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5040 _ctx_immutable=False,
5042 if len(defined_tail) > 0:
5045 klass=self.__class__,
5046 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5049 value.defined = (defined_by, defined_value)
5051 value_len = value.fulllen
5053 sub_offset += value_len
5055 if spec.default is not None and value == spec.default:
5056 if ctx_bered or ctx_allow_default_values:
5060 "DEFAULT value met",
5061 klass=self.__class__,
5062 decode_path=sub_decode_path,
5065 values[name] = value
5067 spec_defines = getattr(spec, "defines", ())
5068 if len(spec_defines) == 0:
5069 defines_by_path = ctx.get("defines_by_path", ())
5070 if len(defines_by_path) > 0:
5071 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5072 if spec_defines is not None and len(spec_defines) > 0:
5073 for rel_path, schema in spec_defines:
5074 defined = schema.get(value, None)
5075 if defined is not None:
5076 ctx.setdefault("_defines", []).append((
5077 abs_decode_path(sub_decode_path[:-1], rel_path),
5081 if v[:EOC_LEN].tobytes() != EOC:
5084 klass=self.__class__,
5085 decode_path=decode_path,
5093 klass=self.__class__,
5094 decode_path=decode_path,
5097 obj = self.__class__(
5101 default=self.default,
5102 optional=self.optional,
5103 _decoded=(offset, llen, vlen),
5106 obj.lenindef = lenindef
5107 obj.ber_encoded = ber_encoded
5111 value = pp_console_row(next(self.pps()))
5113 for name in self.specs:
5114 _value = self._value.get(name)
5117 cols.append("%s: %s" % (name, repr(_value)))
5118 return "%s[%s]" % (value, "; ".join(cols))
5120 def pps(self, decode_path=()):
5123 asn1_type_name=self.asn1_type_name,
5124 obj_name=self.__class__.__name__,
5125 decode_path=decode_path,
5126 optional=self.optional,
5127 default=self == self.default,
5128 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5129 expl=None if self._expl is None else tag_decode(self._expl),
5134 expl_offset=self.expl_offset if self.expled else None,
5135 expl_tlen=self.expl_tlen if self.expled else None,
5136 expl_llen=self.expl_llen if self.expled else None,
5137 expl_vlen=self.expl_vlen if self.expled else None,
5138 expl_lenindef=self.expl_lenindef,
5139 lenindef=self.lenindef,
5140 ber_encoded=self.ber_encoded,
5143 for name in self.specs:
5144 value = self._value.get(name)
5147 yield value.pps(decode_path=decode_path + (name,))
5148 for pp in self.pps_lenindef(decode_path):
5152 class Set(Sequence):
5153 """``SET`` structure type
5155 Its usage is identical to :py:class:`pyderasn.Sequence`.
5157 .. _allow_unordered_set_ctx:
5159 DER prohibits unordered values encoding and will raise an error
5160 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5161 then no error will occure. Also you can disable strict values
5162 ordering check by setting ``"allow_unordered_set": True``
5163 :ref:`context <ctx>` option.
5166 tag_default = tag_encode(form=TagFormConstructed, num=17)
5167 asn1_type_name = "SET"
5170 raws = self._encoded_values()
5173 return b"".join((self.tag, len_encode(len(v)), v))
5175 def _specs_items(self):
5176 return iteritems(self.specs)
5178 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5180 t, tlen, lv = tag_strip(tlv)
5181 except DecodeError as err:
5182 raise err.__class__(
5184 klass=self.__class__,
5185 decode_path=decode_path,
5190 klass=self.__class__,
5191 decode_path=decode_path,
5197 ctx_bered = ctx.get("bered", False)
5199 l, llen, v = len_decode(lv)
5200 except LenIndefForm as err:
5202 raise err.__class__(
5204 klass=self.__class__,
5205 decode_path=decode_path,
5208 l, llen, v = 0, 1, lv[1:]
5210 except DecodeError as err:
5211 raise err.__class__(
5213 klass=self.__class__,
5214 decode_path=decode_path,
5218 raise NotEnoughData(
5219 "encoded length is longer than data",
5220 klass=self.__class__,
5224 v, tail = v[:l], v[l:]
5226 sub_offset = offset + tlen + llen
5229 ctx_allow_default_values = ctx.get("allow_default_values", False)
5230 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5231 value_prev = memoryview(v[:0])
5234 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5236 for name, spec in self._specs_items():
5237 sub_decode_path = decode_path + (name,)
5243 decode_path=sub_decode_path,
5246 _ctx_immutable=False,
5253 klass=self.__class__,
5254 decode_path=decode_path,
5257 value, v_tail = spec.decode(
5261 decode_path=sub_decode_path,
5263 _ctx_immutable=False,
5265 value_len = value.fulllen
5266 if value_prev.tobytes() > v[:value_len].tobytes():
5267 if ctx_bered or ctx_allow_unordered_set:
5271 "unordered " + self.asn1_type_name,
5272 klass=self.__class__,
5273 decode_path=sub_decode_path,
5276 if spec.default is None or value != spec.default:
5278 elif ctx_bered or ctx_allow_default_values:
5282 "DEFAULT value met",
5283 klass=self.__class__,
5284 decode_path=sub_decode_path,
5287 values[name] = value
5288 value_prev = v[:value_len]
5289 sub_offset += value_len
5292 obj = self.__class__(
5296 default=self.default,
5297 optional=self.optional,
5298 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5301 if v[:EOC_LEN].tobytes() != EOC:
5304 klass=self.__class__,
5305 decode_path=decode_path,
5313 "not all values are ready",
5314 klass=self.__class__,
5315 decode_path=decode_path,
5318 obj.ber_encoded = ber_encoded
5322 class SequenceOf(Obj):
5323 """``SEQUENCE OF`` sequence type
5325 For that kind of type you must specify the object it will carry on
5326 (bounds are for example here, not required)::
5328 class Ints(SequenceOf):
5333 >>> ints.append(Integer(123))
5334 >>> ints.append(Integer(234))
5336 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5337 >>> [int(i) for i in ints]
5339 >>> ints.append(Integer(345))
5340 Traceback (most recent call last):
5341 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5344 >>> ints[1] = Integer(345)
5346 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5348 Also you can initialize sequence with preinitialized values:
5350 >>> ints = Ints([Integer(123), Integer(234)])
5352 __slots__ = ("spec", "_bound_min", "_bound_max")
5353 tag_default = tag_encode(form=TagFormConstructed, num=16)
5354 asn1_type_name = "SEQUENCE OF"
5367 super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
5369 schema = getattr(self, "schema", None)
5371 raise ValueError("schema must be specified")
5373 self._bound_min, self._bound_max = getattr(
5377 ) if bounds is None else bounds
5379 if value is not None:
5380 self._value = self._value_sanitize(value)
5381 if default is not None:
5382 default_value = self._value_sanitize(default)
5383 default_obj = self.__class__(
5388 default_obj._value = default_value
5389 self.default = default_obj
5391 self._value = default_obj.copy()._value
5393 def _value_sanitize(self, value):
5394 if issubclass(value.__class__, SequenceOf):
5395 value = value._value
5396 elif hasattr(value, "__iter__"):
5399 raise InvalidValueType((self.__class__, iter))
5400 if not self._bound_min <= len(value) <= self._bound_max:
5401 raise BoundsError(self._bound_min, len(value), self._bound_max)
5403 if not isinstance(v, self.spec.__class__):
5404 raise InvalidValueType((self.spec.__class__,))
5409 return all(v.ready for v in self._value)
5413 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5415 return any(v.bered for v in self._value)
5418 obj = self.__class__(schema=self.spec)
5419 obj._bound_min = self._bound_min
5420 obj._bound_max = self._bound_max
5422 obj._expl = self._expl
5423 obj.default = self.default
5424 obj.optional = self.optional
5425 obj.offset = self.offset
5426 obj.llen = self.llen
5427 obj.vlen = self.vlen
5428 obj.expl_lenindef = self.expl_lenindef
5429 obj.lenindef = self.lenindef
5430 obj.ber_encoded = self.ber_encoded
5431 obj._value = [v.copy() for v in self._value]
5434 def __eq__(self, their):
5435 if isinstance(their, self.__class__):
5437 self.spec == their.spec and
5438 self.tag == their.tag and
5439 self._expl == their._expl and
5440 self._value == their._value
5442 if hasattr(their, "__iter__"):
5443 return self._value == list(their)
5455 return self.__class__(
5459 (self._bound_min, self._bound_max)
5460 if bounds is None else bounds
5462 impl=self.tag if impl is None else impl,
5463 expl=self._expl if expl is None else expl,
5464 default=self.default if default is None else default,
5465 optional=self.optional if optional is None else optional,
5468 def __contains__(self, key):
5469 return key in self._value
5471 def append(self, value):
5472 if not isinstance(value, self.spec.__class__):
5473 raise InvalidValueType((self.spec.__class__,))
5474 if len(self._value) + 1 > self._bound_max:
5477 len(self._value) + 1,
5480 self._value.append(value)
5483 self._assert_ready()
5484 return iter(self._value)
5487 self._assert_ready()
5488 return len(self._value)
5490 def __setitem__(self, key, value):
5491 if not isinstance(value, self.spec.__class__):
5492 raise InvalidValueType((self.spec.__class__,))
5493 self._value[key] = self.spec(value=value)
5495 def __getitem__(self, key):
5496 return self._value[key]
5498 def _encoded_values(self):
5499 return [v.encode() for v in self._value]
5502 v = b"".join(self._encoded_values())
5503 return b"".join((self.tag, len_encode(len(v)), v))
5505 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5507 t, tlen, lv = tag_strip(tlv)
5508 except DecodeError as err:
5509 raise err.__class__(
5511 klass=self.__class__,
5512 decode_path=decode_path,
5517 klass=self.__class__,
5518 decode_path=decode_path,
5524 ctx_bered = ctx.get("bered", False)
5526 l, llen, v = len_decode(lv)
5527 except LenIndefForm as err:
5529 raise err.__class__(
5531 klass=self.__class__,
5532 decode_path=decode_path,
5535 l, llen, v = 0, 1, lv[1:]
5537 except DecodeError as err:
5538 raise err.__class__(
5540 klass=self.__class__,
5541 decode_path=decode_path,
5545 raise NotEnoughData(
5546 "encoded length is longer than data",
5547 klass=self.__class__,
5548 decode_path=decode_path,
5552 v, tail = v[:l], v[l:]
5554 sub_offset = offset + tlen + llen
5556 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5557 value_prev = memoryview(v[:0])
5561 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5563 sub_decode_path = decode_path + (str(len(_value)),)
5564 value, v_tail = spec.decode(
5568 decode_path=sub_decode_path,
5570 _ctx_immutable=False,
5572 value_len = value.fulllen
5574 if value_prev.tobytes() > v[:value_len].tobytes():
5575 if ctx_bered or ctx_allow_unordered_set:
5579 "unordered " + self.asn1_type_name,
5580 klass=self.__class__,
5581 decode_path=sub_decode_path,
5584 value_prev = v[:value_len]
5585 _value.append(value)
5586 sub_offset += value_len
5590 obj = self.__class__(
5593 bounds=(self._bound_min, self._bound_max),
5596 default=self.default,
5597 optional=self.optional,
5598 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5600 except BoundsError as err:
5603 klass=self.__class__,
5604 decode_path=decode_path,
5608 if v[:EOC_LEN].tobytes() != EOC:
5611 klass=self.__class__,
5612 decode_path=decode_path,
5617 obj.ber_encoded = ber_encoded
5622 pp_console_row(next(self.pps())),
5623 ", ".join(repr(v) for v in self._value),
5626 def pps(self, decode_path=()):
5629 asn1_type_name=self.asn1_type_name,
5630 obj_name=self.__class__.__name__,
5631 decode_path=decode_path,
5632 optional=self.optional,
5633 default=self == self.default,
5634 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5635 expl=None if self._expl is None else tag_decode(self._expl),
5640 expl_offset=self.expl_offset if self.expled else None,
5641 expl_tlen=self.expl_tlen if self.expled else None,
5642 expl_llen=self.expl_llen if self.expled else None,
5643 expl_vlen=self.expl_vlen if self.expled else None,
5644 expl_lenindef=self.expl_lenindef,
5645 lenindef=self.lenindef,
5646 ber_encoded=self.ber_encoded,
5649 for i, value in enumerate(self._value):
5650 yield value.pps(decode_path=decode_path + (str(i),))
5651 for pp in self.pps_lenindef(decode_path):
5655 class SetOf(SequenceOf):
5656 """``SET OF`` sequence type
5658 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5661 tag_default = tag_encode(form=TagFormConstructed, num=17)
5662 asn1_type_name = "SET OF"
5665 raws = self._encoded_values()
5668 return b"".join((self.tag, len_encode(len(v)), v))
5670 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5671 return super(SetOf, self)._decode(
5677 ordering_check=True,
5681 def obj_by_path(pypath): # pragma: no cover
5682 """Import object specified as string Python path
5684 Modules must be separated from classes/functions with ``:``.
5686 >>> obj_by_path("foo.bar:Baz")
5687 <class 'foo.bar.Baz'>
5688 >>> obj_by_path("foo.bar:Baz.boo")
5689 <classmethod 'foo.bar.Baz.boo'>
5691 mod, objs = pypath.rsplit(":", 1)
5692 from importlib import import_module
5693 obj = import_module(mod)
5694 for obj_name in objs.split("."):
5695 obj = getattr(obj, obj_name)
5699 def generic_decoder(): # pragma: no cover
5700 # All of this below is a big hack with self references
5701 choice = PrimitiveTypes()
5702 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5703 choice.specs["SetOf"] = SetOf(schema=choice)
5704 for i in six_xrange(31):
5705 choice.specs["SequenceOf%d" % i] = SequenceOf(
5709 choice.specs["Any"] = Any()
5711 # Class name equals to type name, to omit it from output
5712 class SEQUENCEOF(SequenceOf):
5720 with_decode_path=False,
5721 decode_path_only=(),
5723 def _pprint_pps(pps):
5725 if hasattr(pp, "_fields"):
5727 decode_path_only != () and
5728 pp.decode_path[:len(decode_path_only)] != decode_path_only
5731 if pp.asn1_type_name == Choice.asn1_type_name:
5733 pp_kwargs = pp._asdict()
5734 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5735 pp = _pp(**pp_kwargs)
5736 yield pp_console_row(
5741 with_colours=with_colours,
5742 with_decode_path=with_decode_path,
5743 decode_path_len_decrease=len(decode_path_only),
5745 for row in pp_console_blob(
5747 decode_path_len_decrease=len(decode_path_only),
5751 for row in _pprint_pps(pp):
5753 return "\n".join(_pprint_pps(obj.pps()))
5754 return SEQUENCEOF(), pprint_any
5757 def main(): # pragma: no cover
5759 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5760 parser.add_argument(
5764 help="Skip that number of bytes from the beginning",
5766 parser.add_argument(
5768 help="Python paths to dictionary with OIDs, comma separated",
5770 parser.add_argument(
5772 help="Python path to schema definition to use",
5774 parser.add_argument(
5775 "--defines-by-path",
5776 help="Python path to decoder's defines_by_path",
5778 parser.add_argument(
5780 action="store_true",
5781 help="Disallow BER encoding",
5783 parser.add_argument(
5784 "--print-decode-path",
5785 action="store_true",
5786 help="Print decode paths",
5788 parser.add_argument(
5789 "--decode-path-only",
5790 help="Print only specified decode path",
5792 parser.add_argument(
5794 action="store_true",
5795 help="Allow explicit tag out-of-bound",
5797 parser.add_argument(
5799 type=argparse.FileType("rb"),
5800 help="Path to DER file you want to decode",
5802 args = parser.parse_args()
5803 args.DERFile.seek(args.skip)
5804 der = memoryview(args.DERFile.read())
5805 args.DERFile.close()
5807 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
5808 if args.oids else ()
5811 schema = obj_by_path(args.schema)
5812 from functools import partial
5813 pprinter = partial(pprint, big_blobs=True)
5815 schema, pprinter = generic_decoder()
5817 "bered": not args.nobered,
5818 "allow_expl_oob": args.allow_expl_oob,
5820 if args.defines_by_path is not None:
5821 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5822 obj, tail = schema().decode(der, ctx=ctx)
5826 with_colours=environ.get("NO_COLOR") is None,
5827 with_decode_path=args.print_decode_path,
5829 () if args.decode_path_only is None else
5830 tuple(args.decode_path_only.split(":"))
5834 print("\nTrailing data: %s" % hexenc(tail))
5837 if __name__ == "__main__":