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
576 .. autoclass:: pyderasn.UTCTime
577 :members: __init__, todatetime
581 .. autoclass:: pyderasn.GeneralizedTime
588 .. autoclass:: pyderasn.Choice
593 .. autoclass:: PrimitiveTypes
597 .. autoclass:: pyderasn.Any
605 .. autoclass:: pyderasn.Sequence
610 .. autoclass:: pyderasn.Set
615 .. autoclass:: pyderasn.SequenceOf
620 .. autoclass:: pyderasn.SetOf
626 .. autofunction:: pyderasn.abs_decode_path
627 .. autofunction:: pyderasn.colonize_hex
628 .. autofunction:: pyderasn.hexenc
629 .. autofunction:: pyderasn.hexdec
630 .. autofunction:: pyderasn.tag_encode
631 .. autofunction:: pyderasn.tag_decode
632 .. autofunction:: pyderasn.tag_ctxp
633 .. autofunction:: pyderasn.tag_ctxc
634 .. autoclass:: pyderasn.DecodeError
636 .. autoclass:: pyderasn.NotEnoughData
637 .. autoclass:: pyderasn.ExceedingData
638 .. autoclass:: pyderasn.LenIndefForm
639 .. autoclass:: pyderasn.TagMismatch
640 .. autoclass:: pyderasn.InvalidLength
641 .. autoclass:: pyderasn.InvalidOID
642 .. autoclass:: pyderasn.ObjUnknown
643 .. autoclass:: pyderasn.ObjNotReady
644 .. autoclass:: pyderasn.InvalidValueType
645 .. autoclass:: pyderasn.BoundsError
648 from codecs import getdecoder
649 from codecs import getencoder
650 from collections import namedtuple
651 from collections import OrderedDict
652 from copy import copy
653 from datetime import datetime
654 from math import ceil
655 from os import environ
656 from string import ascii_letters
657 from string import digits
658 from unicodedata import category as unicat
660 from six import add_metaclass
661 from six import binary_type
662 from six import byte2int
663 from six import indexbytes
664 from six import int2byte
665 from six import integer_types
666 from six import iterbytes
667 from six import iteritems
668 from six import itervalues
670 from six import string_types
671 from six import text_type
672 from six import unichr as six_unichr
673 from six.moves import xrange as six_xrange
677 from termcolor import colored
678 except ImportError: # pragma: no cover
679 def colored(what, *args, **kwargs):
725 "TagClassApplication",
729 "TagFormConstructed",
740 TagClassUniversal = 0
741 TagClassApplication = 1 << 6
742 TagClassContext = 1 << 7
743 TagClassPrivate = 1 << 6 | 1 << 7
745 TagFormConstructed = 1 << 5
748 TagClassApplication: "APPLICATION ",
749 TagClassPrivate: "PRIVATE ",
750 TagClassUniversal: "UNIV ",
754 LENINDEF = b"\x80" # length indefinite mark
755 LENINDEF_PP_CHAR = "I" if PY2 else "∞"
758 ########################################################################
760 ########################################################################
762 class ASN1Error(ValueError):
766 class DecodeError(ASN1Error):
767 def __init__(self, msg="", klass=None, decode_path=(), offset=0):
769 :param str msg: reason of decode failing
770 :param klass: optional exact DecodeError inherited class (like
771 :py:exc:`NotEnoughData`, :py:exc:`TagMismatch`,
772 :py:exc:`InvalidLength`)
773 :param decode_path: tuple of strings. It contains human
774 readable names of the fields through which
775 decoding process has passed
776 :param int offset: binary offset where failure happened
778 super(DecodeError, self).__init__()
781 self.decode_path = decode_path
787 "" if self.klass is None else self.klass.__name__,
789 ("(%s)" % ":".join(str(dp) for dp in self.decode_path))
790 if len(self.decode_path) > 0 else ""
792 ("(at %d)" % self.offset) if self.offset > 0 else "",
798 return "%s(%s)" % (self.__class__.__name__, self)
801 class NotEnoughData(DecodeError):
805 class ExceedingData(ASN1Error):
806 def __init__(self, nbytes):
807 super(ExceedingData, self).__init__()
811 return "%d trailing bytes" % self.nbytes
814 return "%s(%s)" % (self.__class__.__name__, self)
817 class LenIndefForm(DecodeError):
821 class TagMismatch(DecodeError):
825 class InvalidLength(DecodeError):
829 class InvalidOID(DecodeError):
833 class ObjUnknown(ASN1Error):
834 def __init__(self, name):
835 super(ObjUnknown, self).__init__()
839 return "object is unknown: %s" % self.name
842 return "%s(%s)" % (self.__class__.__name__, self)
845 class ObjNotReady(ASN1Error):
846 def __init__(self, name):
847 super(ObjNotReady, self).__init__()
851 return "object is not ready: %s" % self.name
854 return "%s(%s)" % (self.__class__.__name__, self)
857 class InvalidValueType(ASN1Error):
858 def __init__(self, expected_types):
859 super(InvalidValueType, self).__init__()
860 self.expected_types = expected_types
863 return "invalid value type, expected: %s" % ", ".join(
864 [repr(t) for t in self.expected_types]
868 return "%s(%s)" % (self.__class__.__name__, self)
871 class BoundsError(ASN1Error):
872 def __init__(self, bound_min, value, bound_max):
873 super(BoundsError, self).__init__()
874 self.bound_min = bound_min
876 self.bound_max = bound_max
879 return "unsatisfied bounds: %s <= %s <= %s" % (
886 return "%s(%s)" % (self.__class__.__name__, self)
889 ########################################################################
891 ########################################################################
893 _hexdecoder = getdecoder("hex")
894 _hexencoder = getencoder("hex")
898 """Binary data to hexadecimal string convert
900 return _hexdecoder(data)[0]
904 """Hexadecimal string to binary data convert
906 return _hexencoder(data)[0].decode("ascii")
909 def int_bytes_len(num, byte_len=8):
912 return int(ceil(float(num.bit_length()) / byte_len))
915 def zero_ended_encode(num):
916 octets = bytearray(int_bytes_len(num, 7))
918 octets[i] = num & 0x7F
922 octets[i] = 0x80 | (num & 0x7F)
928 def tag_encode(num, klass=TagClassUniversal, form=TagFormPrimitive):
929 """Encode tag to binary form
931 :param int num: tag's number
932 :param int klass: tag's class (:py:data:`pyderasn.TagClassUniversal`,
933 :py:data:`pyderasn.TagClassContext`,
934 :py:data:`pyderasn.TagClassApplication`,
935 :py:data:`pyderasn.TagClassPrivate`)
936 :param int form: tag's form (:py:data:`pyderasn.TagFormPrimitive`,
937 :py:data:`pyderasn.TagFormConstructed`)
941 return int2byte(klass | form | num)
942 # [XX|X|11111][1.......][1.......] ... [0.......]
943 return int2byte(klass | form | 31) + zero_ended_encode(num)
947 """Decode tag from binary form
951 No validation is performed, assuming that it has already passed.
953 It returns tuple with three integers, as
954 :py:func:`pyderasn.tag_encode` accepts.
956 first_octet = byte2int(tag)
957 klass = first_octet & 0xC0
958 form = first_octet & 0x20
959 if first_octet & 0x1F < 0x1F:
960 return (klass, form, first_octet & 0x1F)
962 for octet in iterbytes(tag[1:]):
965 return (klass, form, num)
969 """Create CONTEXT PRIMITIVE tag
971 return tag_encode(num=num, klass=TagClassContext, form=TagFormPrimitive)
975 """Create CONTEXT CONSTRUCTED tag
977 return tag_encode(num=num, klass=TagClassContext, form=TagFormConstructed)
981 """Take off tag from the data
983 :returns: (encoded tag, tag length, remaining data)
986 raise NotEnoughData("no data at all")
987 if byte2int(data) & 0x1F < 31:
988 return data[:1], 1, data[1:]
993 raise DecodeError("unfinished tag")
994 if indexbytes(data, i) & 0x80 == 0:
997 return data[:i], i, data[i:]
1003 octets = bytearray(int_bytes_len(l) + 1)
1004 octets[0] = 0x80 | (len(octets) - 1)
1005 for i in six_xrange(len(octets) - 1, 0, -1):
1006 octets[i] = l & 0xFF
1008 return bytes(octets)
1011 def len_decode(data):
1014 :returns: (decoded length, length's length, remaining data)
1015 :raises LenIndefForm: if indefinite form encoding is met
1018 raise NotEnoughData("no data at all")
1019 first_octet = byte2int(data)
1020 if first_octet & 0x80 == 0:
1021 return first_octet, 1, data[1:]
1022 octets_num = first_octet & 0x7F
1023 if octets_num + 1 > len(data):
1024 raise NotEnoughData("encoded length is longer than data")
1026 raise LenIndefForm()
1027 if byte2int(data[1:]) == 0:
1028 raise DecodeError("leading zeros")
1030 for v in iterbytes(data[1:1 + octets_num]):
1033 raise DecodeError("long form instead of short one")
1034 return l, 1 + octets_num, data[1 + octets_num:]
1037 ########################################################################
1039 ########################################################################
1041 class AutoAddSlots(type):
1042 def __new__(cls, name, bases, _dict):
1043 _dict["__slots__"] = _dict.get("__slots__", ())
1044 return type.__new__(cls, name, bases, _dict)
1047 @add_metaclass(AutoAddSlots)
1049 """Common ASN.1 object class
1051 All ASN.1 types are inherited from it. It has metaclass that
1052 automatically adds ``__slots__`` to all inherited classes.
1076 self.tag = getattr(self, "impl", self.tag_default) if impl is None else impl
1077 self._expl = getattr(self, "expl", None) if expl is None else expl
1078 if self.tag != self.tag_default and self._expl is not None:
1079 raise ValueError("implicit and explicit tags can not be set simultaneously")
1080 if default is not None:
1082 self.optional = optional
1083 self.offset, self.llen, self.vlen = _decoded
1085 self.expl_lenindef = False
1086 self.lenindef = False
1087 self.ber_encoded = False
1090 def ready(self): # pragma: no cover
1091 """Is object ready to be encoded?
1093 raise NotImplementedError()
1095 def _assert_ready(self):
1097 raise ObjNotReady(self.__class__.__name__)
1101 """Is either object or any elements inside is BER encoded?
1103 return self.expl_lenindef or self.lenindef or self.ber_encoded
1107 """Is object decoded?
1109 return (self.llen + self.vlen) > 0
1111 def copy(self): # pragma: no cover
1112 """Make a copy of object, safe to be mutated
1114 raise NotImplementedError()
1118 """See :ref:`decoding`
1120 return len(self.tag)
1124 """See :ref:`decoding`
1126 return self.tlen + self.llen + self.vlen
1128 def __str__(self): # pragma: no cover
1129 return self.__bytes__() if PY2 else self.__unicode__()
1131 def __ne__(self, their):
1132 return not(self == their)
1134 def __gt__(self, their): # pragma: no cover
1135 return not(self < their)
1137 def __le__(self, their): # pragma: no cover
1138 return (self == their) or (self < their)
1140 def __ge__(self, their): # pragma: no cover
1141 return (self == their) or (self > their)
1143 def _encode(self): # pragma: no cover
1144 raise NotImplementedError()
1146 def _decode(self, tlv, offset, decode_path, ctx, tag_only): # pragma: no cover
1147 raise NotImplementedError()
1150 """Encode the structure
1152 :returns: DER representation
1154 raw = self._encode()
1155 if self._expl is None:
1157 return b"".join((self._expl, len_encode(len(raw)), raw))
1167 _ctx_immutable=True,
1171 :param data: either binary or memoryview
1172 :param int offset: initial data's offset
1173 :param bool leavemm: do we need to leave memoryview of remaining
1174 data as is, or convert it to bytes otherwise
1175 :param ctx: optional :ref:`context <ctx>` governing decoding process
1176 :param tag_only: decode only the tag, without length and contents
1177 (used only in Choice and Set structures, trying to
1178 determine if tag satisfies the scheme)
1179 :param _ctx_immutable: do we need to copy ``ctx`` before using it
1180 :returns: (Obj, remaining data)
1182 .. seealso:: :ref:`decoding`
1186 elif _ctx_immutable:
1188 tlv = memoryview(data)
1189 if self._expl is None:
1190 result = self._decode(
1193 decode_path=decode_path,
1202 t, tlen, lv = tag_strip(tlv)
1203 except DecodeError as err:
1204 raise err.__class__(
1206 klass=self.__class__,
1207 decode_path=decode_path,
1212 klass=self.__class__,
1213 decode_path=decode_path,
1217 l, llen, v = len_decode(lv)
1218 except LenIndefForm as err:
1219 if not ctx.get("bered", False):
1220 raise err.__class__(
1222 klass=self.__class__,
1223 decode_path=decode_path,
1227 offset += tlen + llen
1228 result = self._decode(
1231 decode_path=decode_path,
1235 if tag_only: # pragma: no cover
1238 eoc_expected, tail = tail[:EOC_LEN], tail[EOC_LEN:]
1239 if eoc_expected.tobytes() != EOC:
1242 klass=self.__class__,
1243 decode_path=decode_path,
1247 obj.expl_lenindef = True
1248 except DecodeError as err:
1249 raise err.__class__(
1251 klass=self.__class__,
1252 decode_path=decode_path,
1257 raise NotEnoughData(
1258 "encoded length is longer than data",
1259 klass=self.__class__,
1260 decode_path=decode_path,
1263 result = self._decode(
1265 offset=offset + tlen + llen,
1266 decode_path=decode_path,
1270 if tag_only: # pragma: no cover
1273 if obj.tlvlen < l and not ctx.get("allow_expl_oob", False):
1275 "explicit tag out-of-bound, longer than data",
1276 klass=self.__class__,
1277 decode_path=decode_path,
1280 return obj, (tail if leavemm else tail.tobytes())
1282 def decod(self, data, offset=0, decode_path=(), ctx=None):
1283 """Decode the data, check that tail is empty
1285 :raises ExceedingData: if tail is not empty
1287 This is just a wrapper over :py:meth:`pyderasn.Obj.decode`
1288 (decode without tail) that also checks that there is no
1291 obj, tail = self.decode(
1294 decode_path=decode_path,
1299 raise ExceedingData(len(tail))
1304 """See :ref:`decoding`
1306 return self._expl is not None
1310 """See :ref:`decoding`
1315 def expl_tlen(self):
1316 """See :ref:`decoding`
1318 return len(self._expl)
1321 def expl_llen(self):
1322 """See :ref:`decoding`
1324 if self.expl_lenindef:
1326 return len(len_encode(self.tlvlen))
1329 def expl_offset(self):
1330 """See :ref:`decoding`
1332 return self.offset - self.expl_tlen - self.expl_llen
1335 def expl_vlen(self):
1336 """See :ref:`decoding`
1341 def expl_tlvlen(self):
1342 """See :ref:`decoding`
1344 return self.expl_tlen + self.expl_llen + self.expl_vlen
1347 def fulloffset(self):
1348 """See :ref:`decoding`
1350 return self.expl_offset if self.expled else self.offset
1354 """See :ref:`decoding`
1356 return self.expl_tlvlen if self.expled else self.tlvlen
1358 def pps_lenindef(self, decode_path):
1359 if self.lenindef and not (
1360 getattr(self, "defined", None) is not None and
1361 self.defined[1].lenindef
1364 asn1_type_name="EOC",
1366 decode_path=decode_path,
1368 self.offset + self.tlvlen -
1369 (EOC_LEN * 2 if self.expl_lenindef else EOC_LEN)
1377 if self.expl_lenindef:
1379 asn1_type_name="EOC",
1380 obj_name="EXPLICIT",
1381 decode_path=decode_path,
1382 offset=self.expl_offset + self.expl_tlvlen - EOC_LEN,
1391 class DecodePathDefBy(object):
1392 """DEFINED BY representation inside decode path
1394 __slots__ = ("defined_by",)
1396 def __init__(self, defined_by):
1397 self.defined_by = defined_by
1399 def __ne__(self, their):
1400 return not(self == their)
1402 def __eq__(self, their):
1403 if not isinstance(their, self.__class__):
1405 return self.defined_by == their.defined_by
1408 return "DEFINED BY " + str(self.defined_by)
1411 return "<%s: %s>" % (self.__class__.__name__, self.defined_by)
1414 ########################################################################
1416 ########################################################################
1418 PP = namedtuple("PP", (
1446 asn1_type_name="unknown",
1463 expl_lenindef=False,
1494 def _colourize(what, colour, with_colours, attrs=("bold",)):
1495 return colored(what, colour, attrs=attrs) if with_colours else what
1498 def colonize_hex(hexed):
1499 """Separate hexadecimal string with colons
1501 return ":".join(hexed[i:i + 2] for i in six_xrange(0, len(hexed), 2))
1510 with_decode_path=False,
1511 decode_path_len_decrease=0,
1518 " " if pp.expl_offset is None else
1519 ("-%d" % (pp.offset - pp.expl_offset))
1521 LENINDEF_PP_CHAR if pp.expl_lenindef else " ",
1523 col = _colourize(col, "red", with_colours, ())
1524 col += _colourize("B", "red", with_colours) if pp.bered else " "
1526 col = "[%d,%d,%4d]%s" % (
1530 LENINDEF_PP_CHAR if pp.lenindef else " "
1532 col = _colourize(col, "green", with_colours, ())
1534 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1535 if decode_path_len > 0:
1536 cols.append(" ." * decode_path_len)
1537 ent = pp.decode_path[-1]
1538 if isinstance(ent, DecodePathDefBy):
1539 cols.append(_colourize("DEFINED BY", "red", with_colours, ("reverse",)))
1540 value = str(ent.defined_by)
1543 len(oid_maps) > 0 and
1544 ent.defined_by.asn1_type_name ==
1545 ObjectIdentifier.asn1_type_name
1547 for oid_map in oid_maps:
1548 oid_name = oid_map.get(value)
1549 if oid_name is not None:
1550 cols.append(_colourize("%s:" % oid_name, "green", with_colours))
1552 if oid_name is None:
1553 cols.append(_colourize("%s:" % value, "white", with_colours, ("reverse",)))
1555 cols.append(_colourize("%s:" % ent, "yellow", with_colours, ("reverse",)))
1556 if pp.expl is not None:
1557 klass, _, num = pp.expl
1558 col = "[%s%d] EXPLICIT" % (TagClassReprs[klass], num)
1559 cols.append(_colourize(col, "blue", with_colours))
1560 if pp.impl is not None:
1561 klass, _, num = pp.impl
1562 col = "[%s%d]" % (TagClassReprs[klass], num)
1563 cols.append(_colourize(col, "blue", with_colours))
1564 if pp.asn1_type_name.replace(" ", "") != pp.obj_name.upper():
1565 cols.append(_colourize(pp.obj_name, "magenta", with_colours))
1567 cols.append(_colourize("BER", "red", with_colours))
1568 cols.append(_colourize(pp.asn1_type_name, "cyan", with_colours))
1569 if pp.value is not None:
1571 cols.append(_colourize(value, "white", with_colours, ("reverse",)))
1573 len(oid_maps) > 0 and
1574 pp.asn1_type_name == ObjectIdentifier.asn1_type_name
1576 for oid_map in oid_maps:
1577 oid_name = oid_map.get(value)
1578 if oid_name is not None:
1579 cols.append(_colourize("(%s)" % oid_name, "green", with_colours))
1581 if pp.asn1_type_name == Integer.asn1_type_name:
1582 hex_repr = hex(int(pp.obj._value))[2:].upper()
1583 if len(hex_repr) % 2 != 0:
1584 hex_repr = "0" + hex_repr
1585 cols.append(_colourize(
1586 "(%s)" % colonize_hex(hex_repr),
1591 if isinstance(pp.blob, binary_type):
1592 cols.append(hexenc(pp.blob))
1593 elif isinstance(pp.blob, tuple):
1594 cols.append(", ".join(pp.blob))
1596 cols.append(_colourize("OPTIONAL", "red", with_colours))
1598 cols.append(_colourize("DEFAULT", "red", with_colours))
1599 if with_decode_path:
1600 cols.append(_colourize(
1601 "[%s]" % ":".join(str(p) for p in pp.decode_path),
1605 return " ".join(cols)
1608 def pp_console_blob(pp, decode_path_len_decrease=0):
1609 cols = [" " * len("XXXXXYYZZ [X,X,XXXX]Z")]
1610 decode_path_len = len(pp.decode_path) - decode_path_len_decrease
1611 if decode_path_len > 0:
1612 cols.append(" ." * (decode_path_len + 1))
1613 if isinstance(pp.blob, binary_type):
1614 blob = hexenc(pp.blob).upper()
1615 for i in six_xrange(0, len(blob), 32):
1616 chunk = blob[i:i + 32]
1617 yield " ".join(cols + [colonize_hex(chunk)])
1618 elif isinstance(pp.blob, tuple):
1619 yield " ".join(cols + [", ".join(pp.blob)])
1627 with_decode_path=False,
1628 decode_path_only=(),
1630 """Pretty print object
1632 :param Obj obj: object you want to pretty print
1633 :param oid_maps: list of ``OID <-> humand readable string`` dictionary.
1634 When OID from it is met, then its humand readable form
1636 :param big_blobs: if large binary objects are met (like OctetString
1637 values), do we need to print them too, on separate
1639 :param with_colours: colourize output, if ``termcolor`` library
1641 :param with_decode_path: print decode path
1642 :param decode_path_only: print only that specified decode path
1644 def _pprint_pps(pps):
1646 if hasattr(pp, "_fields"):
1648 decode_path_only != () and
1650 str(p) for p in pp.decode_path[:len(decode_path_only)]
1651 ) != decode_path_only
1655 yield pp_console_row(
1660 with_colours=with_colours,
1661 with_decode_path=with_decode_path,
1662 decode_path_len_decrease=len(decode_path_only),
1664 for row in pp_console_blob(
1666 decode_path_len_decrease=len(decode_path_only),
1670 yield pp_console_row(
1675 with_colours=with_colours,
1676 with_decode_path=with_decode_path,
1677 decode_path_len_decrease=len(decode_path_only),
1680 for row in _pprint_pps(pp):
1682 return "\n".join(_pprint_pps(obj.pps()))
1685 ########################################################################
1686 # ASN.1 primitive types
1687 ########################################################################
1690 """``BOOLEAN`` boolean type
1692 >>> b = Boolean(True)
1694 >>> b == Boolean(True)
1700 tag_default = tag_encode(1)
1701 asn1_type_name = "BOOLEAN"
1713 :param value: set the value. Either boolean type, or
1714 :py:class:`pyderasn.Boolean` object
1715 :param bytes impl: override default tag with ``IMPLICIT`` one
1716 :param bytes expl: override default tag with ``EXPLICIT`` one
1717 :param default: set default value. Type same as in ``value``
1718 :param bool optional: is object ``OPTIONAL`` in sequence
1720 super(Boolean, self).__init__(impl, expl, default, optional, _decoded)
1721 self._value = None if value is None else self._value_sanitize(value)
1722 if default is not None:
1723 default = self._value_sanitize(default)
1724 self.default = self.__class__(
1730 self._value = default
1732 def _value_sanitize(self, value):
1733 if isinstance(value, bool):
1735 if issubclass(value.__class__, Boolean):
1737 raise InvalidValueType((self.__class__, bool))
1741 return self._value is not None
1744 obj = self.__class__()
1745 obj._value = self._value
1747 obj._expl = self._expl
1748 obj.default = self.default
1749 obj.optional = self.optional
1750 obj.offset = self.offset
1751 obj.llen = self.llen
1752 obj.vlen = self.vlen
1753 obj.expl_lenindef = self.expl_lenindef
1754 obj.lenindef = self.lenindef
1755 obj.ber_encoded = self.ber_encoded
1758 def __nonzero__(self):
1759 self._assert_ready()
1763 self._assert_ready()
1766 def __eq__(self, their):
1767 if isinstance(their, bool):
1768 return self._value == their
1769 if not issubclass(their.__class__, Boolean):
1772 self._value == their._value and
1773 self.tag == their.tag and
1774 self._expl == their._expl
1785 return self.__class__(
1787 impl=self.tag if impl is None else impl,
1788 expl=self._expl if expl is None else expl,
1789 default=self.default if default is None else default,
1790 optional=self.optional if optional is None else optional,
1794 self._assert_ready()
1798 (b"\xFF" if self._value else b"\x00"),
1801 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
1803 t, _, lv = tag_strip(tlv)
1804 except DecodeError as err:
1805 raise err.__class__(
1807 klass=self.__class__,
1808 decode_path=decode_path,
1813 klass=self.__class__,
1814 decode_path=decode_path,
1820 l, _, v = len_decode(lv)
1821 except DecodeError as err:
1822 raise err.__class__(
1824 klass=self.__class__,
1825 decode_path=decode_path,
1829 raise InvalidLength(
1830 "Boolean's length must be equal to 1",
1831 klass=self.__class__,
1832 decode_path=decode_path,
1836 raise NotEnoughData(
1837 "encoded length is longer than data",
1838 klass=self.__class__,
1839 decode_path=decode_path,
1842 first_octet = byte2int(v)
1844 if first_octet == 0:
1846 elif first_octet == 0xFF:
1848 elif ctx.get("bered", False):
1853 "unacceptable Boolean value",
1854 klass=self.__class__,
1855 decode_path=decode_path,
1858 obj = self.__class__(
1862 default=self.default,
1863 optional=self.optional,
1864 _decoded=(offset, 1, 1),
1866 obj.ber_encoded = ber_encoded
1870 return pp_console_row(next(self.pps()))
1872 def pps(self, decode_path=()):
1875 asn1_type_name=self.asn1_type_name,
1876 obj_name=self.__class__.__name__,
1877 decode_path=decode_path,
1878 value=str(self._value) if self.ready else None,
1879 optional=self.optional,
1880 default=self == self.default,
1881 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
1882 expl=None if self._expl is None else tag_decode(self._expl),
1887 expl_offset=self.expl_offset if self.expled else None,
1888 expl_tlen=self.expl_tlen if self.expled else None,
1889 expl_llen=self.expl_llen if self.expled else None,
1890 expl_vlen=self.expl_vlen if self.expled else None,
1891 expl_lenindef=self.expl_lenindef,
1892 ber_encoded=self.ber_encoded,
1895 for pp in self.pps_lenindef(decode_path):
1900 """``INTEGER`` integer type
1902 >>> b = Integer(-123)
1904 >>> b == Integer(-123)
1909 >>> Integer(2, bounds=(1, 3))
1911 >>> Integer(5, bounds=(1, 3))
1912 Traceback (most recent call last):
1913 pyderasn.BoundsError: unsatisfied bounds: 1 <= 5 <= 3
1917 class Version(Integer):
1924 >>> v = Version("v1")
1931 {'v3': 2, 'v1': 0, 'v2': 1}
1933 __slots__ = ("specs", "_bound_min", "_bound_max")
1934 tag_default = tag_encode(2)
1935 asn1_type_name = "INTEGER"
1949 :param value: set the value. Either integer type, named value
1950 (if ``schema`` is specified in the class), or
1951 :py:class:`pyderasn.Integer` object
1952 :param bounds: set ``(MIN, MAX)`` value constraint.
1953 (-inf, +inf) by default
1954 :param bytes impl: override default tag with ``IMPLICIT`` one
1955 :param bytes expl: override default tag with ``EXPLICIT`` one
1956 :param default: set default value. Type same as in ``value``
1957 :param bool optional: is object ``OPTIONAL`` in sequence
1959 super(Integer, self).__init__(impl, expl, default, optional, _decoded)
1961 specs = getattr(self, "schema", {}) if _specs is None else _specs
1962 self.specs = specs if isinstance(specs, dict) else dict(specs)
1963 self._bound_min, self._bound_max = getattr(
1966 (float("-inf"), float("+inf")),
1967 ) if bounds is None else bounds
1968 if value is not None:
1969 self._value = self._value_sanitize(value)
1970 if default is not None:
1971 default = self._value_sanitize(default)
1972 self.default = self.__class__(
1978 if self._value is None:
1979 self._value = default
1981 def _value_sanitize(self, value):
1982 if isinstance(value, integer_types):
1984 elif issubclass(value.__class__, Integer):
1985 value = value._value
1986 elif isinstance(value, str):
1987 value = self.specs.get(value)
1989 raise ObjUnknown("integer value: %s" % value)
1991 raise InvalidValueType((self.__class__, int, str))
1992 if not self._bound_min <= value <= self._bound_max:
1993 raise BoundsError(self._bound_min, value, self._bound_max)
1998 return self._value is not None
2001 obj = self.__class__(_specs=self.specs)
2002 obj._value = self._value
2003 obj._bound_min = self._bound_min
2004 obj._bound_max = self._bound_max
2006 obj._expl = self._expl
2007 obj.default = self.default
2008 obj.optional = self.optional
2009 obj.offset = self.offset
2010 obj.llen = self.llen
2011 obj.vlen = self.vlen
2012 obj.expl_lenindef = self.expl_lenindef
2013 obj.lenindef = self.lenindef
2014 obj.ber_encoded = self.ber_encoded
2018 self._assert_ready()
2019 return int(self._value)
2022 self._assert_ready()
2025 bytes(self._expl or b"") +
2026 str(self._value).encode("ascii"),
2029 def __eq__(self, their):
2030 if isinstance(their, integer_types):
2031 return self._value == their
2032 if not issubclass(their.__class__, Integer):
2035 self._value == their._value and
2036 self.tag == their.tag and
2037 self._expl == their._expl
2040 def __lt__(self, their):
2041 return self._value < their._value
2045 for name, value in iteritems(self.specs):
2046 if value == self._value:
2059 return self.__class__(
2062 (self._bound_min, self._bound_max)
2063 if bounds is None else bounds
2065 impl=self.tag if impl is None else impl,
2066 expl=self._expl if expl is None else expl,
2067 default=self.default if default is None else default,
2068 optional=self.optional if optional is None else optional,
2073 self._assert_ready()
2077 octets = bytearray([0])
2081 octets = bytearray()
2083 octets.append((value & 0xFF) ^ 0xFF)
2085 if len(octets) == 0 or octets[-1] & 0x80 == 0:
2088 octets = bytearray()
2090 octets.append(value & 0xFF)
2092 if octets[-1] & 0x80 > 0:
2095 octets = bytes(octets)
2097 bytes_len = ceil(value.bit_length() / 8) or 1
2100 octets = value.to_bytes(
2105 except OverflowError:
2109 return b"".join((self.tag, len_encode(len(octets)), octets))
2111 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2113 t, _, lv = tag_strip(tlv)
2114 except DecodeError as err:
2115 raise err.__class__(
2117 klass=self.__class__,
2118 decode_path=decode_path,
2123 klass=self.__class__,
2124 decode_path=decode_path,
2130 l, llen, v = len_decode(lv)
2131 except DecodeError as err:
2132 raise err.__class__(
2134 klass=self.__class__,
2135 decode_path=decode_path,
2139 raise NotEnoughData(
2140 "encoded length is longer than data",
2141 klass=self.__class__,
2142 decode_path=decode_path,
2146 raise NotEnoughData(
2148 klass=self.__class__,
2149 decode_path=decode_path,
2152 v, tail = v[:l], v[l:]
2153 first_octet = byte2int(v)
2155 second_octet = byte2int(v[1:])
2157 ((first_octet == 0x00) and (second_octet & 0x80 == 0)) or
2158 ((first_octet == 0xFF) and (second_octet & 0x80 != 0))
2161 "non normalized integer",
2162 klass=self.__class__,
2163 decode_path=decode_path,
2168 if first_octet & 0x80 > 0:
2169 octets = bytearray()
2170 for octet in bytearray(v):
2171 octets.append(octet ^ 0xFF)
2172 for octet in octets:
2173 value = (value << 8) | octet
2177 for octet in bytearray(v):
2178 value = (value << 8) | octet
2180 value = int.from_bytes(v, byteorder="big", signed=True)
2182 obj = self.__class__(
2184 bounds=(self._bound_min, self._bound_max),
2187 default=self.default,
2188 optional=self.optional,
2190 _decoded=(offset, llen, l),
2192 except BoundsError as err:
2195 klass=self.__class__,
2196 decode_path=decode_path,
2202 return pp_console_row(next(self.pps()))
2204 def pps(self, decode_path=()):
2207 asn1_type_name=self.asn1_type_name,
2208 obj_name=self.__class__.__name__,
2209 decode_path=decode_path,
2210 value=(self.named or str(self._value)) if self.ready else None,
2211 optional=self.optional,
2212 default=self == self.default,
2213 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2214 expl=None if self._expl is None else tag_decode(self._expl),
2219 expl_offset=self.expl_offset if self.expled else None,
2220 expl_tlen=self.expl_tlen if self.expled else None,
2221 expl_llen=self.expl_llen if self.expled else None,
2222 expl_vlen=self.expl_vlen if self.expled else None,
2223 expl_lenindef=self.expl_lenindef,
2226 for pp in self.pps_lenindef(decode_path):
2230 SET01 = frozenset(("0", "1"))
2233 class BitString(Obj):
2234 """``BIT STRING`` bit string type
2236 >>> BitString(b"hello world")
2237 BIT STRING 88 bits 68656c6c6f20776f726c64
2240 >>> b == b"hello world"
2245 >>> BitString("'0A3B5F291CD'H")
2246 BIT STRING 44 bits 0a3b5f291cd0
2247 >>> b = BitString("'010110000000'B")
2248 BIT STRING 12 bits 5800
2251 >>> b[0], b[1], b[2], b[3]
2252 (False, True, False, True)
2256 [False, True, False, True, True, False, False, False, False, False, False, False]
2260 class KeyUsage(BitString):
2262 ("digitalSignature", 0),
2263 ("nonRepudiation", 1),
2264 ("keyEncipherment", 2),
2267 >>> b = KeyUsage(("keyEncipherment", "nonRepudiation"))
2268 KeyUsage BIT STRING 3 bits nonRepudiation, keyEncipherment
2270 ['nonRepudiation', 'keyEncipherment']
2272 {'nonRepudiation': 1, 'digitalSignature': 0, 'keyEncipherment': 2}
2276 Pay attention that BIT STRING can be encoded both in primitive
2277 and constructed forms. Decoder always checks constructed form tag
2278 additionally to specified primitive one. If BER decoding is
2279 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2280 of DER restrictions.
2282 __slots__ = ("tag_constructed", "specs", "defined")
2283 tag_default = tag_encode(3)
2284 asn1_type_name = "BIT STRING"
2297 :param value: set the value. Either binary type, tuple of named
2298 values (if ``schema`` is specified in the class),
2299 string in ``'XXX...'B`` form, or
2300 :py:class:`pyderasn.BitString` object
2301 :param bytes impl: override default tag with ``IMPLICIT`` one
2302 :param bytes expl: override default tag with ``EXPLICIT`` one
2303 :param default: set default value. Type same as in ``value``
2304 :param bool optional: is object ``OPTIONAL`` in sequence
2306 super(BitString, self).__init__(impl, expl, default, optional, _decoded)
2307 specs = getattr(self, "schema", {}) if _specs is None else _specs
2308 self.specs = specs if isinstance(specs, dict) else dict(specs)
2309 self._value = None if value is None else self._value_sanitize(value)
2310 if default is not None:
2311 default = self._value_sanitize(default)
2312 self.default = self.__class__(
2318 self._value = default
2320 tag_klass, _, tag_num = tag_decode(self.tag)
2321 self.tag_constructed = tag_encode(
2323 form=TagFormConstructed,
2327 def _bits2octets(self, bits):
2328 if len(self.specs) > 0:
2329 bits = bits.rstrip("0")
2331 bits += "0" * ((8 - (bit_len % 8)) % 8)
2332 octets = bytearray(len(bits) // 8)
2333 for i in six_xrange(len(octets)):
2334 octets[i] = int(bits[i * 8:(i * 8) + 8], 2)
2335 return bit_len, bytes(octets)
2337 def _value_sanitize(self, value):
2338 if isinstance(value, (string_types, binary_type)):
2340 isinstance(value, string_types) and
2341 value.startswith("'")
2343 if value.endswith("'B"):
2345 if not frozenset(value) <= SET01:
2346 raise ValueError("B's coding contains unacceptable chars")
2347 return self._bits2octets(value)
2348 if value.endswith("'H"):
2352 hexdec(value + ("" if len(value) % 2 == 0 else "0")),
2354 if isinstance(value, binary_type):
2355 return (len(value) * 8, value)
2356 raise InvalidValueType((self.__class__, string_types, binary_type))
2357 if isinstance(value, tuple):
2360 isinstance(value[0], integer_types) and
2361 isinstance(value[1], binary_type)
2366 bit = self.specs.get(name)
2368 raise ObjUnknown("BitString value: %s" % name)
2371 return self._bits2octets("")
2372 bits = frozenset(bits)
2373 return self._bits2octets("".join(
2374 ("1" if bit in bits else "0")
2375 for bit in six_xrange(max(bits) + 1)
2377 if issubclass(value.__class__, BitString):
2379 raise InvalidValueType((self.__class__, binary_type, string_types))
2383 return self._value is not None
2386 obj = self.__class__(_specs=self.specs)
2388 if value is not None:
2389 value = (value[0], value[1])
2392 obj._expl = self._expl
2393 obj.default = self.default
2394 obj.optional = self.optional
2395 obj.offset = self.offset
2396 obj.llen = self.llen
2397 obj.vlen = self.vlen
2398 obj.expl_lenindef = self.expl_lenindef
2399 obj.lenindef = self.lenindef
2400 obj.ber_encoded = self.ber_encoded
2404 self._assert_ready()
2405 for i in six_xrange(self._value[0]):
2410 self._assert_ready()
2411 return self._value[0]
2413 def __bytes__(self):
2414 self._assert_ready()
2415 return self._value[1]
2417 def __eq__(self, their):
2418 if isinstance(their, bytes):
2419 return self._value[1] == their
2420 if not issubclass(their.__class__, BitString):
2423 self._value == their._value and
2424 self.tag == their.tag and
2425 self._expl == their._expl
2430 return [name for name, bit in iteritems(self.specs) if self[bit]]
2440 return self.__class__(
2442 impl=self.tag if impl is None else impl,
2443 expl=self._expl if expl is None else expl,
2444 default=self.default if default is None else default,
2445 optional=self.optional if optional is None else optional,
2449 def __getitem__(self, key):
2450 if isinstance(key, int):
2451 bit_len, octets = self._value
2455 byte2int(memoryview(octets)[key // 8:]) >>
2458 if isinstance(key, string_types):
2459 value = self.specs.get(key)
2461 raise ObjUnknown("BitString value: %s" % key)
2463 raise InvalidValueType((int, str))
2466 self._assert_ready()
2467 bit_len, octets = self._value
2470 len_encode(len(octets) + 1),
2471 int2byte((8 - bit_len % 8) % 8),
2475 def _decode_chunk(self, lv, offset, decode_path):
2477 l, llen, v = len_decode(lv)
2478 except DecodeError as err:
2479 raise err.__class__(
2481 klass=self.__class__,
2482 decode_path=decode_path,
2486 raise NotEnoughData(
2487 "encoded length is longer than data",
2488 klass=self.__class__,
2489 decode_path=decode_path,
2493 raise NotEnoughData(
2495 klass=self.__class__,
2496 decode_path=decode_path,
2499 pad_size = byte2int(v)
2500 if l == 1 and pad_size != 0:
2502 "invalid empty value",
2503 klass=self.__class__,
2504 decode_path=decode_path,
2510 klass=self.__class__,
2511 decode_path=decode_path,
2514 if byte2int(v[l - 1:l]) & ((1 << pad_size) - 1) != 0:
2517 klass=self.__class__,
2518 decode_path=decode_path,
2521 v, tail = v[:l], v[l:]
2522 obj = self.__class__(
2523 value=((len(v) - 1) * 8 - pad_size, v[1:].tobytes()),
2526 default=self.default,
2527 optional=self.optional,
2529 _decoded=(offset, llen, l),
2533 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2535 t, tlen, lv = tag_strip(tlv)
2536 except DecodeError as err:
2537 raise err.__class__(
2539 klass=self.__class__,
2540 decode_path=decode_path,
2544 if tag_only: # pragma: no cover
2546 return self._decode_chunk(lv, offset, decode_path)
2547 if t == self.tag_constructed:
2548 if not ctx.get("bered", False):
2550 "unallowed BER constructed encoding",
2551 klass=self.__class__,
2552 decode_path=decode_path,
2555 if tag_only: # pragma: no cover
2559 l, llen, v = len_decode(lv)
2560 except LenIndefForm:
2561 llen, l, v = 1, 0, lv[1:]
2563 except DecodeError as err:
2564 raise err.__class__(
2566 klass=self.__class__,
2567 decode_path=decode_path,
2571 raise NotEnoughData(
2572 "encoded length is longer than data",
2573 klass=self.__class__,
2574 decode_path=decode_path,
2577 if not lenindef and l == 0:
2578 raise NotEnoughData(
2580 klass=self.__class__,
2581 decode_path=decode_path,
2585 sub_offset = offset + tlen + llen
2589 if v[:EOC_LEN].tobytes() == EOC:
2596 "chunk out of bounds",
2597 klass=self.__class__,
2598 decode_path=decode_path + (str(len(chunks) - 1),),
2599 offset=chunks[-1].offset,
2601 sub_decode_path = decode_path + (str(len(chunks)),)
2603 chunk, v_tail = BitString().decode(
2606 decode_path=sub_decode_path,
2609 _ctx_immutable=False,
2613 "expected BitString encoded chunk",
2614 klass=self.__class__,
2615 decode_path=sub_decode_path,
2618 chunks.append(chunk)
2619 sub_offset += chunk.tlvlen
2620 vlen += chunk.tlvlen
2622 if len(chunks) == 0:
2625 klass=self.__class__,
2626 decode_path=decode_path,
2631 for chunk_i, chunk in enumerate(chunks[:-1]):
2632 if chunk.bit_len % 8 != 0:
2634 "BitString chunk is not multiple of 8 bits",
2635 klass=self.__class__,
2636 decode_path=decode_path + (str(chunk_i),),
2637 offset=chunk.offset,
2639 values.append(bytes(chunk))
2640 bit_len += chunk.bit_len
2641 chunk_last = chunks[-1]
2642 values.append(bytes(chunk_last))
2643 bit_len += chunk_last.bit_len
2644 obj = self.__class__(
2645 value=(bit_len, b"".join(values)),
2648 default=self.default,
2649 optional=self.optional,
2651 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
2653 obj.lenindef = lenindef
2654 obj.ber_encoded = True
2655 return obj, (v[EOC_LEN:] if lenindef else v)
2657 klass=self.__class__,
2658 decode_path=decode_path,
2663 return pp_console_row(next(self.pps()))
2665 def pps(self, decode_path=()):
2669 bit_len, blob = self._value
2670 value = "%d bits" % bit_len
2671 if len(self.specs) > 0:
2672 blob = tuple(self.named)
2675 asn1_type_name=self.asn1_type_name,
2676 obj_name=self.__class__.__name__,
2677 decode_path=decode_path,
2680 optional=self.optional,
2681 default=self == self.default,
2682 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
2683 expl=None if self._expl is None else tag_decode(self._expl),
2688 expl_offset=self.expl_offset if self.expled else None,
2689 expl_tlen=self.expl_tlen if self.expled else None,
2690 expl_llen=self.expl_llen if self.expled else None,
2691 expl_vlen=self.expl_vlen if self.expled else None,
2692 expl_lenindef=self.expl_lenindef,
2693 lenindef=self.lenindef,
2694 ber_encoded=self.ber_encoded,
2697 defined_by, defined = self.defined or (None, None)
2698 if defined_by is not None:
2700 decode_path=decode_path + (DecodePathDefBy(defined_by),)
2702 for pp in self.pps_lenindef(decode_path):
2706 class OctetString(Obj):
2707 """``OCTET STRING`` binary string type
2709 >>> s = OctetString(b"hello world")
2710 OCTET STRING 11 bytes 68656c6c6f20776f726c64
2711 >>> s == OctetString(b"hello world")
2716 >>> OctetString(b"hello", bounds=(4, 4))
2717 Traceback (most recent call last):
2718 pyderasn.BoundsError: unsatisfied bounds: 4 <= 5 <= 4
2719 >>> OctetString(b"hell", bounds=(4, 4))
2720 OCTET STRING 4 bytes 68656c6c
2724 Pay attention that OCTET STRING can be encoded both in primitive
2725 and constructed forms. Decoder always checks constructed form tag
2726 additionally to specified primitive one. If BER decoding is
2727 :ref:`not enabled <bered_ctx>`, then decoder will fail, because
2728 of DER restrictions.
2730 __slots__ = ("tag_constructed", "_bound_min", "_bound_max", "defined")
2731 tag_default = tag_encode(4)
2732 asn1_type_name = "OCTET STRING"
2745 :param value: set the value. Either binary type, or
2746 :py:class:`pyderasn.OctetString` object
2747 :param bounds: set ``(MIN, MAX)`` value size constraint.
2748 (-inf, +inf) by default
2749 :param bytes impl: override default tag with ``IMPLICIT`` one
2750 :param bytes expl: override default tag with ``EXPLICIT`` one
2751 :param default: set default value. Type same as in ``value``
2752 :param bool optional: is object ``OPTIONAL`` in sequence
2754 super(OctetString, self).__init__(
2762 self._bound_min, self._bound_max = getattr(
2766 ) if bounds is None else bounds
2767 if value is not None:
2768 self._value = self._value_sanitize(value)
2769 if default is not None:
2770 default = self._value_sanitize(default)
2771 self.default = self.__class__(
2776 if self._value is None:
2777 self._value = default
2779 tag_klass, _, tag_num = tag_decode(self.tag)
2780 self.tag_constructed = tag_encode(
2782 form=TagFormConstructed,
2786 def _value_sanitize(self, value):
2787 if isinstance(value, binary_type):
2789 elif issubclass(value.__class__, OctetString):
2790 value = value._value
2792 raise InvalidValueType((self.__class__, bytes))
2793 if not self._bound_min <= len(value) <= self._bound_max:
2794 raise BoundsError(self._bound_min, len(value), self._bound_max)
2799 return self._value is not None
2802 obj = self.__class__()
2803 obj._value = self._value
2804 obj._bound_min = self._bound_min
2805 obj._bound_max = self._bound_max
2807 obj._expl = self._expl
2808 obj.default = self.default
2809 obj.optional = self.optional
2810 obj.offset = self.offset
2811 obj.llen = self.llen
2812 obj.vlen = self.vlen
2813 obj.expl_lenindef = self.expl_lenindef
2814 obj.lenindef = self.lenindef
2815 obj.ber_encoded = self.ber_encoded
2818 def __bytes__(self):
2819 self._assert_ready()
2822 def __eq__(self, their):
2823 if isinstance(their, binary_type):
2824 return self._value == their
2825 if not issubclass(their.__class__, OctetString):
2828 self._value == their._value and
2829 self.tag == their.tag and
2830 self._expl == their._expl
2833 def __lt__(self, their):
2834 return self._value < their._value
2845 return self.__class__(
2848 (self._bound_min, self._bound_max)
2849 if bounds is None else bounds
2851 impl=self.tag if impl is None else impl,
2852 expl=self._expl if expl is None else expl,
2853 default=self.default if default is None else default,
2854 optional=self.optional if optional is None else optional,
2858 self._assert_ready()
2861 len_encode(len(self._value)),
2865 def _decode_chunk(self, lv, offset, decode_path):
2867 l, llen, v = len_decode(lv)
2868 except DecodeError as err:
2869 raise err.__class__(
2871 klass=self.__class__,
2872 decode_path=decode_path,
2876 raise NotEnoughData(
2877 "encoded length is longer than data",
2878 klass=self.__class__,
2879 decode_path=decode_path,
2882 v, tail = v[:l], v[l:]
2884 obj = self.__class__(
2886 bounds=(self._bound_min, self._bound_max),
2889 default=self.default,
2890 optional=self.optional,
2891 _decoded=(offset, llen, l),
2893 except DecodeError as err:
2896 klass=self.__class__,
2897 decode_path=decode_path,
2900 except BoundsError as err:
2903 klass=self.__class__,
2904 decode_path=decode_path,
2909 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
2911 t, tlen, lv = tag_strip(tlv)
2912 except DecodeError as err:
2913 raise err.__class__(
2915 klass=self.__class__,
2916 decode_path=decode_path,
2922 return self._decode_chunk(lv, offset, decode_path)
2923 if t == self.tag_constructed:
2924 if not ctx.get("bered", False):
2926 "unallowed BER constructed encoding",
2927 klass=self.__class__,
2928 decode_path=decode_path,
2935 l, llen, v = len_decode(lv)
2936 except LenIndefForm:
2937 llen, l, v = 1, 0, lv[1:]
2939 except DecodeError as err:
2940 raise err.__class__(
2942 klass=self.__class__,
2943 decode_path=decode_path,
2947 raise NotEnoughData(
2948 "encoded length is longer than data",
2949 klass=self.__class__,
2950 decode_path=decode_path,
2954 sub_offset = offset + tlen + llen
2958 if v[:EOC_LEN].tobytes() == EOC:
2965 "chunk out of bounds",
2966 klass=self.__class__,
2967 decode_path=decode_path + (str(len(chunks) - 1),),
2968 offset=chunks[-1].offset,
2970 sub_decode_path = decode_path + (str(len(chunks)),)
2972 chunk, v_tail = OctetString().decode(
2975 decode_path=sub_decode_path,
2978 _ctx_immutable=False,
2982 "expected OctetString encoded chunk",
2983 klass=self.__class__,
2984 decode_path=sub_decode_path,
2987 chunks.append(chunk)
2988 sub_offset += chunk.tlvlen
2989 vlen += chunk.tlvlen
2992 obj = self.__class__(
2993 value=b"".join(bytes(chunk) for chunk in chunks),
2994 bounds=(self._bound_min, self._bound_max),
2997 default=self.default,
2998 optional=self.optional,
2999 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
3001 except DecodeError as err:
3004 klass=self.__class__,
3005 decode_path=decode_path,
3008 except BoundsError as err:
3011 klass=self.__class__,
3012 decode_path=decode_path,
3015 obj.lenindef = lenindef
3016 obj.ber_encoded = True
3017 return obj, (v[EOC_LEN:] if lenindef else v)
3019 klass=self.__class__,
3020 decode_path=decode_path,
3025 return pp_console_row(next(self.pps()))
3027 def pps(self, decode_path=()):
3030 asn1_type_name=self.asn1_type_name,
3031 obj_name=self.__class__.__name__,
3032 decode_path=decode_path,
3033 value=("%d bytes" % len(self._value)) if self.ready else None,
3034 blob=self._value if self.ready else None,
3035 optional=self.optional,
3036 default=self == self.default,
3037 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3038 expl=None if self._expl is None else tag_decode(self._expl),
3043 expl_offset=self.expl_offset if self.expled else None,
3044 expl_tlen=self.expl_tlen if self.expled else None,
3045 expl_llen=self.expl_llen if self.expled else None,
3046 expl_vlen=self.expl_vlen if self.expled else None,
3047 expl_lenindef=self.expl_lenindef,
3048 lenindef=self.lenindef,
3049 ber_encoded=self.ber_encoded,
3052 defined_by, defined = self.defined or (None, None)
3053 if defined_by is not None:
3055 decode_path=decode_path + (DecodePathDefBy(defined_by),)
3057 for pp in self.pps_lenindef(decode_path):
3062 """``NULL`` null object
3070 tag_default = tag_encode(5)
3071 asn1_type_name = "NULL"
3075 value=None, # unused, but Sequence passes it
3082 :param bytes impl: override default tag with ``IMPLICIT`` one
3083 :param bytes expl: override default tag with ``EXPLICIT`` one
3084 :param bool optional: is object ``OPTIONAL`` in sequence
3086 super(Null, self).__init__(impl, expl, None, optional, _decoded)
3094 obj = self.__class__()
3096 obj._expl = self._expl
3097 obj.default = self.default
3098 obj.optional = self.optional
3099 obj.offset = self.offset
3100 obj.llen = self.llen
3101 obj.vlen = self.vlen
3102 obj.expl_lenindef = self.expl_lenindef
3103 obj.lenindef = self.lenindef
3104 obj.ber_encoded = self.ber_encoded
3107 def __eq__(self, their):
3108 if not issubclass(their.__class__, Null):
3111 self.tag == their.tag and
3112 self._expl == their._expl
3122 return self.__class__(
3123 impl=self.tag if impl is None else impl,
3124 expl=self._expl if expl is None else expl,
3125 optional=self.optional if optional is None else optional,
3129 return self.tag + len_encode(0)
3131 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3133 t, _, lv = tag_strip(tlv)
3134 except DecodeError as err:
3135 raise err.__class__(
3137 klass=self.__class__,
3138 decode_path=decode_path,
3143 klass=self.__class__,
3144 decode_path=decode_path,
3147 if tag_only: # pragma: no cover
3150 l, _, v = len_decode(lv)
3151 except DecodeError as err:
3152 raise err.__class__(
3154 klass=self.__class__,
3155 decode_path=decode_path,
3159 raise InvalidLength(
3160 "Null must have zero length",
3161 klass=self.__class__,
3162 decode_path=decode_path,
3165 obj = self.__class__(
3168 optional=self.optional,
3169 _decoded=(offset, 1, 0),
3174 return pp_console_row(next(self.pps()))
3176 def pps(self, decode_path=()):
3179 asn1_type_name=self.asn1_type_name,
3180 obj_name=self.__class__.__name__,
3181 decode_path=decode_path,
3182 optional=self.optional,
3183 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3184 expl=None if self._expl is None else tag_decode(self._expl),
3189 expl_offset=self.expl_offset if self.expled else None,
3190 expl_tlen=self.expl_tlen if self.expled else None,
3191 expl_llen=self.expl_llen if self.expled else None,
3192 expl_vlen=self.expl_vlen if self.expled else None,
3193 expl_lenindef=self.expl_lenindef,
3196 for pp in self.pps_lenindef(decode_path):
3200 class ObjectIdentifier(Obj):
3201 """``OBJECT IDENTIFIER`` OID type
3203 >>> oid = ObjectIdentifier((1, 2, 3))
3204 OBJECT IDENTIFIER 1.2.3
3205 >>> oid == ObjectIdentifier("1.2.3")
3211 >>> oid + (4, 5) + ObjectIdentifier("1.7")
3212 OBJECT IDENTIFIER 1.2.3.4.5.1.7
3214 >>> str(ObjectIdentifier((3, 1)))
3215 Traceback (most recent call last):
3216 pyderasn.InvalidOID: unacceptable first arc value
3218 __slots__ = ("defines",)
3219 tag_default = tag_encode(6)
3220 asn1_type_name = "OBJECT IDENTIFIER"
3233 :param value: set the value. Either tuples of integers,
3234 string of "."-concatenated integers, or
3235 :py:class:`pyderasn.ObjectIdentifier` object
3236 :param defines: sequence of tuples. Each tuple has two elements.
3237 First one is relative to current one decode
3238 path, aiming to the field defined by that OID.
3239 Read about relative path in
3240 :py:func:`pyderasn.abs_decode_path`. Second
3241 tuple element is ``{OID: pyderasn.Obj()}``
3242 dictionary, mapping between current OID value
3243 and structure applied to defined field.
3244 :ref:`Read about DEFINED BY <definedby>`
3245 :param bytes impl: override default tag with ``IMPLICIT`` one
3246 :param bytes expl: override default tag with ``EXPLICIT`` one
3247 :param default: set default value. Type same as in ``value``
3248 :param bool optional: is object ``OPTIONAL`` in sequence
3250 super(ObjectIdentifier, self).__init__(
3258 if value is not None:
3259 self._value = self._value_sanitize(value)
3260 if default is not None:
3261 default = self._value_sanitize(default)
3262 self.default = self.__class__(
3267 if self._value is None:
3268 self._value = default
3269 self.defines = defines
3271 def __add__(self, their):
3272 if isinstance(their, self.__class__):
3273 return self.__class__(self._value + their._value)
3274 if isinstance(their, tuple):
3275 return self.__class__(self._value + their)
3276 raise InvalidValueType((self.__class__, tuple))
3278 def _value_sanitize(self, value):
3279 if issubclass(value.__class__, ObjectIdentifier):
3281 if isinstance(value, string_types):
3283 value = tuple(int(arc) for arc in value.split("."))
3285 raise InvalidOID("unacceptable arcs values")
3286 if isinstance(value, tuple):
3288 raise InvalidOID("less than 2 arcs")
3289 first_arc = value[0]
3290 if first_arc in (0, 1):
3291 if not (0 <= value[1] <= 39):
3292 raise InvalidOID("second arc is too wide")
3293 elif first_arc == 2:
3296 raise InvalidOID("unacceptable first arc value")
3298 raise InvalidValueType((self.__class__, str, tuple))
3302 return self._value is not None
3305 obj = self.__class__()
3306 obj._value = self._value
3307 obj.defines = self.defines
3309 obj._expl = self._expl
3310 obj.default = self.default
3311 obj.optional = self.optional
3312 obj.offset = self.offset
3313 obj.llen = self.llen
3314 obj.vlen = self.vlen
3315 obj.expl_lenindef = self.expl_lenindef
3316 obj.lenindef = self.lenindef
3317 obj.ber_encoded = self.ber_encoded
3321 self._assert_ready()
3322 return iter(self._value)
3325 return ".".join(str(arc) for arc in self._value or ())
3328 self._assert_ready()
3331 bytes(self._expl or b"") +
3332 str(self._value).encode("ascii"),
3335 def __eq__(self, their):
3336 if isinstance(their, tuple):
3337 return self._value == their
3338 if not issubclass(their.__class__, ObjectIdentifier):
3341 self.tag == their.tag and
3342 self._expl == their._expl and
3343 self._value == their._value
3346 def __lt__(self, their):
3347 return self._value < their._value
3358 return self.__class__(
3360 defines=self.defines if defines is None else defines,
3361 impl=self.tag if impl is None else impl,
3362 expl=self._expl if expl is None else expl,
3363 default=self.default if default is None else default,
3364 optional=self.optional if optional is None else optional,
3368 self._assert_ready()
3370 first_value = value[1]
3371 first_arc = value[0]
3374 elif first_arc == 1:
3376 elif first_arc == 2:
3378 else: # pragma: no cover
3379 raise RuntimeError("invalid arc is stored")
3380 octets = [zero_ended_encode(first_value)]
3381 for arc in value[2:]:
3382 octets.append(zero_ended_encode(arc))
3383 v = b"".join(octets)
3384 return b"".join((self.tag, len_encode(len(v)), v))
3386 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
3388 t, _, lv = tag_strip(tlv)
3389 except DecodeError as err:
3390 raise err.__class__(
3392 klass=self.__class__,
3393 decode_path=decode_path,
3398 klass=self.__class__,
3399 decode_path=decode_path,
3402 if tag_only: # pragma: no cover
3405 l, llen, v = len_decode(lv)
3406 except DecodeError as err:
3407 raise err.__class__(
3409 klass=self.__class__,
3410 decode_path=decode_path,
3414 raise NotEnoughData(
3415 "encoded length is longer than data",
3416 klass=self.__class__,
3417 decode_path=decode_path,
3421 raise NotEnoughData(
3423 klass=self.__class__,
3424 decode_path=decode_path,
3427 v, tail = v[:l], v[l:]
3434 octet = indexbytes(v, i)
3435 if i == 0 and octet == 0x80:
3436 if ctx.get("bered", False):
3439 raise DecodeError("non normalized arc encoding")
3440 arc = (arc << 7) | (octet & 0x7F)
3441 if octet & 0x80 == 0:
3449 klass=self.__class__,
3450 decode_path=decode_path,
3454 second_arc = arcs[0]
3455 if 0 <= second_arc <= 39:
3457 elif 40 <= second_arc <= 79:
3463 obj = self.__class__(
3464 value=tuple([first_arc, second_arc] + arcs[1:]),
3467 default=self.default,
3468 optional=self.optional,
3469 _decoded=(offset, llen, l),
3472 obj.ber_encoded = True
3476 return pp_console_row(next(self.pps()))
3478 def pps(self, decode_path=()):
3481 asn1_type_name=self.asn1_type_name,
3482 obj_name=self.__class__.__name__,
3483 decode_path=decode_path,
3484 value=str(self) if self.ready else None,
3485 optional=self.optional,
3486 default=self == self.default,
3487 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3488 expl=None if self._expl is None else tag_decode(self._expl),
3493 expl_offset=self.expl_offset if self.expled else None,
3494 expl_tlen=self.expl_tlen if self.expled else None,
3495 expl_llen=self.expl_llen if self.expled else None,
3496 expl_vlen=self.expl_vlen if self.expled else None,
3497 expl_lenindef=self.expl_lenindef,
3498 ber_encoded=self.ber_encoded,
3501 for pp in self.pps_lenindef(decode_path):
3505 class Enumerated(Integer):
3506 """``ENUMERATED`` integer type
3508 This type is identical to :py:class:`pyderasn.Integer`, but requires
3509 schema to be specified and does not accept values missing from it.
3512 tag_default = tag_encode(10)
3513 asn1_type_name = "ENUMERATED"
3524 bounds=None, # dummy argument, workability for Integer.decode
3526 super(Enumerated, self).__init__(
3535 if len(self.specs) == 0:
3536 raise ValueError("schema must be specified")
3538 def _value_sanitize(self, value):
3539 if isinstance(value, self.__class__):
3540 value = value._value
3541 elif isinstance(value, integer_types):
3542 for _value in itervalues(self.specs):
3547 "unknown integer value: %s" % value,
3548 klass=self.__class__,
3550 elif isinstance(value, string_types):
3551 value = self.specs.get(value)
3553 raise ObjUnknown("integer value: %s" % value)
3555 raise InvalidValueType((self.__class__, int, str))
3559 obj = self.__class__(_specs=self.specs)
3560 obj._value = self._value
3561 obj._bound_min = self._bound_min
3562 obj._bound_max = self._bound_max
3564 obj._expl = self._expl
3565 obj.default = self.default
3566 obj.optional = self.optional
3567 obj.offset = self.offset
3568 obj.llen = self.llen
3569 obj.vlen = self.vlen
3570 obj.expl_lenindef = self.expl_lenindef
3571 obj.lenindef = self.lenindef
3572 obj.ber_encoded = self.ber_encoded
3584 return self.__class__(
3586 impl=self.tag if impl is None else impl,
3587 expl=self._expl if expl is None else expl,
3588 default=self.default if default is None else default,
3589 optional=self.optional if optional is None else optional,
3594 def escape_control_unicode(c):
3595 if unicat(c).startswith("C"):
3596 c = repr(c).lstrip("u").strip("'")
3600 class CommonString(OctetString):
3601 """Common class for all strings
3603 Everything resembles :py:class:`pyderasn.OctetString`, except
3604 ability to deal with unicode text strings.
3606 >>> hexenc("привет мир".encode("utf-8"))
3607 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3608 >>> UTF8String("привет мир") == UTF8String(hexdec("d0...80"))
3610 >>> s = UTF8String("привет мир")
3611 UTF8String UTF8String привет мир
3613 'привет мир'
3614 >>> hexenc(bytes(s))
3615 'd0bfd180d0b8d0b2d0b5d18220d0bcd0b8d180'
3617 >>> PrintableString("привет мир")
3618 Traceback (most recent call last):
3619 pyderasn.DecodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)
3621 >>> BMPString("ада", bounds=(2, 2))
3622 Traceback (most recent call last):
3623 pyderasn.BoundsError: unsatisfied bounds: 2 <= 3 <= 2
3624 >>> s = BMPString("ад", bounds=(2, 2))
3627 >>> hexenc(bytes(s))
3635 * - :py:class:`pyderasn.UTF8String`
3637 * - :py:class:`pyderasn.NumericString`
3639 * - :py:class:`pyderasn.PrintableString`
3641 * - :py:class:`pyderasn.TeletexString`
3643 * - :py:class:`pyderasn.T61String`
3645 * - :py:class:`pyderasn.VideotexString`
3647 * - :py:class:`pyderasn.IA5String`
3649 * - :py:class:`pyderasn.GraphicString`
3651 * - :py:class:`pyderasn.VisibleString`
3653 * - :py:class:`pyderasn.ISO646String`
3655 * - :py:class:`pyderasn.GeneralString`
3657 * - :py:class:`pyderasn.UniversalString`
3659 * - :py:class:`pyderasn.BMPString`
3662 __slots__ = ("encoding",)
3664 def _value_sanitize(self, value):
3666 value_decoded = None
3667 if isinstance(value, self.__class__):
3668 value_raw = value._value
3669 elif isinstance(value, text_type):
3670 value_decoded = value
3671 elif isinstance(value, binary_type):
3674 raise InvalidValueType((self.__class__, text_type, binary_type))
3677 value_decoded.encode(self.encoding)
3678 if value_raw is None else value_raw
3681 value_raw.decode(self.encoding)
3682 if value_decoded is None else value_decoded
3684 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3685 raise DecodeError(str(err))
3686 if not self._bound_min <= len(value_decoded) <= self._bound_max:
3694 def __eq__(self, their):
3695 if isinstance(their, binary_type):
3696 return self._value == their
3697 if isinstance(their, text_type):
3698 return self._value == their.encode(self.encoding)
3699 if not isinstance(their, self.__class__):
3702 self._value == their._value and
3703 self.tag == their.tag and
3704 self._expl == their._expl
3707 def __unicode__(self):
3709 return self._value.decode(self.encoding)
3710 return text_type(self._value)
3713 return pp_console_row(next(self.pps(no_unicode=PY2)))
3715 def pps(self, decode_path=(), no_unicode=False):
3719 hexenc(bytes(self)) if no_unicode else
3720 "".join(escape_control_unicode(c) for c in self.__unicode__())
3724 asn1_type_name=self.asn1_type_name,
3725 obj_name=self.__class__.__name__,
3726 decode_path=decode_path,
3728 optional=self.optional,
3729 default=self == self.default,
3730 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3731 expl=None if self._expl is None else tag_decode(self._expl),
3736 expl_offset=self.expl_offset if self.expled else None,
3737 expl_tlen=self.expl_tlen if self.expled else None,
3738 expl_llen=self.expl_llen if self.expled else None,
3739 expl_vlen=self.expl_vlen if self.expled else None,
3740 expl_lenindef=self.expl_lenindef,
3741 ber_encoded=self.ber_encoded,
3744 for pp in self.pps_lenindef(decode_path):
3748 class UTF8String(CommonString):
3750 tag_default = tag_encode(12)
3752 asn1_type_name = "UTF8String"
3755 class AllowableCharsMixin(object):
3757 def allowable_chars(self):
3759 return self._allowable_chars
3760 return frozenset(six_unichr(c) for c in self._allowable_chars)
3763 class NumericString(AllowableCharsMixin, CommonString):
3766 Its value is properly sanitized: only ASCII digits with spaces can
3769 >>> NumericString().allowable_chars
3770 frozenset(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '])
3773 tag_default = tag_encode(18)
3775 asn1_type_name = "NumericString"
3776 _allowable_chars = frozenset(digits.encode("ascii") + b" ")
3778 def _value_sanitize(self, value):
3779 value = super(NumericString, self)._value_sanitize(value)
3780 if not frozenset(value) <= self._allowable_chars:
3781 raise DecodeError("non-numeric value")
3785 class PrintableString(AllowableCharsMixin, CommonString):
3788 Its value is properly sanitized: see X.680 41.4 table 10.
3790 >>> PrintableString().allowable_chars
3791 frozenset([' ', "'", ..., 'z'])
3794 tag_default = tag_encode(19)
3796 asn1_type_name = "PrintableString"
3797 _allowable_chars = frozenset(
3798 (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
3801 def _value_sanitize(self, value):
3802 value = super(PrintableString, self)._value_sanitize(value)
3803 if not frozenset(value) <= self._allowable_chars:
3804 raise DecodeError("non-printable value")
3808 class TeletexString(CommonString):
3810 tag_default = tag_encode(20)
3812 asn1_type_name = "TeletexString"
3815 class T61String(TeletexString):
3817 asn1_type_name = "T61String"
3820 class VideotexString(CommonString):
3822 tag_default = tag_encode(21)
3823 encoding = "iso-8859-1"
3824 asn1_type_name = "VideotexString"
3827 class IA5String(CommonString):
3829 tag_default = tag_encode(22)
3831 asn1_type_name = "IA5"
3834 LEN_YYMMDDHHMMSSZ = len("YYMMDDHHMMSSZ")
3835 LEN_YYYYMMDDHHMMSSDMZ = len("YYYYMMDDHHMMSSDMZ")
3836 LEN_YYYYMMDDHHMMSSZ = len("YYYYMMDDHHMMSSZ")
3839 class UTCTime(CommonString):
3840 """``UTCTime`` datetime type
3842 >>> t = UTCTime(datetime(2017, 9, 30, 22, 7, 50, 123))
3843 UTCTime UTCTime 2017-09-30T22:07:50
3849 datetime.datetime(2017, 9, 30, 22, 7, 50)
3850 >>> UTCTime(datetime(2057, 9, 30, 22, 7, 50)).todatetime()
3851 datetime.datetime(1957, 9, 30, 22, 7, 50)
3855 BER encoding is unsupported.
3858 tag_default = tag_encode(23)
3860 asn1_type_name = "UTCTime"
3870 bounds=None, # dummy argument, workability for OctetString.decode
3873 :param value: set the value. Either datetime type, or
3874 :py:class:`pyderasn.UTCTime` object
3875 :param bytes impl: override default tag with ``IMPLICIT`` one
3876 :param bytes expl: override default tag with ``EXPLICIT`` one
3877 :param default: set default value. Type same as in ``value``
3878 :param bool optional: is object ``OPTIONAL`` in sequence
3880 super(UTCTime, self).__init__(
3888 if value is not None:
3889 self._value = self._value_sanitize(value)
3890 if default is not None:
3891 default = self._value_sanitize(default)
3892 self.default = self.__class__(
3897 if self._value is None:
3898 self._value = default
3900 def _strptime(self, value):
3901 # datetime.strptime's format: %y%m%d%H%M%SZ
3902 if len(value) != LEN_YYMMDDHHMMSSZ:
3903 raise ValueError("invalid UTCTime length")
3904 if value[-1] != "Z":
3905 raise ValueError("non UTC timezone")
3907 2000 + int(value[:2]), # %y
3908 int(value[2:4]), # %m
3909 int(value[4:6]), # %d
3910 int(value[6:8]), # %H
3911 int(value[8:10]), # %M
3912 int(value[10:12]), # %S
3915 def _value_sanitize(self, value):
3916 if isinstance(value, binary_type):
3918 value_decoded = value.decode("ascii")
3919 except (UnicodeEncodeError, UnicodeDecodeError) as err:
3920 raise DecodeError("invalid UTCTime encoding: %r" % err)
3922 self._strptime(value_decoded)
3923 except (TypeError, ValueError) as err:
3924 raise DecodeError("invalid UTCTime format: %r" % err)
3926 if isinstance(value, self.__class__):
3928 if isinstance(value, datetime):
3929 return value.strftime("%y%m%d%H%M%SZ").encode("ascii")
3930 raise InvalidValueType((self.__class__, datetime))
3932 def __eq__(self, their):
3933 if isinstance(their, binary_type):
3934 return self._value == their
3935 if isinstance(their, datetime):
3936 return self.todatetime() == their
3937 if not isinstance(their, self.__class__):
3940 self._value == their._value and
3941 self.tag == their.tag and
3942 self._expl == their._expl
3945 def todatetime(self):
3946 """Convert to datetime
3950 Pay attention that UTCTime can not hold full year, so all years
3951 having < 50 years are treated as 20xx, 19xx otherwise, according
3952 to X.509 recomendation.
3954 value = self._strptime(self._value.decode("ascii"))
3955 year = value.year % 100
3957 year=(2000 + year) if year < 50 else (1900 + year),
3961 minute=value.minute,
3962 second=value.second,
3966 return pp_console_row(next(self.pps()))
3968 def pps(self, decode_path=()):
3971 asn1_type_name=self.asn1_type_name,
3972 obj_name=self.__class__.__name__,
3973 decode_path=decode_path,
3974 value=self.todatetime().isoformat() if self.ready else None,
3975 optional=self.optional,
3976 default=self == self.default,
3977 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
3978 expl=None if self._expl is None else tag_decode(self._expl),
3983 expl_offset=self.expl_offset if self.expled else None,
3984 expl_tlen=self.expl_tlen if self.expled else None,
3985 expl_llen=self.expl_llen if self.expled else None,
3986 expl_vlen=self.expl_vlen if self.expled else None,
3987 expl_lenindef=self.expl_lenindef,
3988 ber_encoded=self.ber_encoded,
3991 for pp in self.pps_lenindef(decode_path):
3995 class GeneralizedTime(UTCTime):
3996 """``GeneralizedTime`` datetime type
3998 This type is similar to :py:class:`pyderasn.UTCTime`.
4000 >>> t = GeneralizedTime(datetime(2017, 9, 30, 22, 7, 50, 123))
4001 GeneralizedTime GeneralizedTime 2017-09-30T22:07:50.000123
4003 '20170930220750.000123Z'
4004 >>> t = GeneralizedTime(datetime(2057, 9, 30, 22, 7, 50))
4005 GeneralizedTime GeneralizedTime 2057-09-30T22:07:50
4009 BER encoding is unsupported.
4013 Only microsecond fractions are supported.
4014 :py:exc:`pyderasn.DecodeError` will be raised during decoding of
4015 higher precision values.
4018 tag_default = tag_encode(24)
4019 asn1_type_name = "GeneralizedTime"
4021 def _strptime(self, value):
4023 if l == LEN_YYYYMMDDHHMMSSZ:
4024 # datetime.strptime's format: %y%m%d%H%M%SZ
4025 if value[-1] != "Z":
4026 raise ValueError("non UTC timezone")
4028 int(value[:4]), # %Y
4029 int(value[4:6]), # %m
4030 int(value[6:8]), # %d
4031 int(value[8:10]), # %H
4032 int(value[10:12]), # %M
4033 int(value[12:14]), # %S
4035 if l >= LEN_YYYYMMDDHHMMSSDMZ:
4036 # datetime.strptime's format: %Y%m%d%H%M%S.%fZ
4037 if value[-1] != "Z":
4038 raise ValueError("non UTC timezone")
4039 if value[14] != ".":
4040 raise ValueError("no fractions separator")
4043 raise ValueError("trailing zero")
4046 raise ValueError("only microsecond fractions are supported")
4047 us = int(us + ("0" * (6 - us_len)))
4049 int(value[:4]), # %Y
4050 int(value[4:6]), # %m
4051 int(value[6:8]), # %d
4052 int(value[8:10]), # %H
4053 int(value[10:12]), # %M
4054 int(value[12:14]), # %S
4058 raise ValueError("invalid GeneralizedTime length")
4060 def _value_sanitize(self, value):
4061 if isinstance(value, binary_type):
4063 value_decoded = value.decode("ascii")
4064 except (UnicodeEncodeError, UnicodeDecodeError) as err:
4065 raise DecodeError("invalid GeneralizedTime encoding: %r" % err)
4067 self._strptime(value_decoded)
4068 except (TypeError, ValueError) as err:
4070 "invalid GeneralizedTime format: %r" % err,
4071 klass=self.__class__,
4074 if isinstance(value, self.__class__):
4076 if isinstance(value, datetime):
4077 encoded = value.strftime("%Y%m%d%H%M%S")
4078 if value.microsecond > 0:
4079 encoded = encoded + (".%06d" % value.microsecond).rstrip("0")
4080 return (encoded + "Z").encode("ascii")
4081 raise InvalidValueType((self.__class__, datetime))
4083 def todatetime(self):
4084 return self._strptime(self._value.decode("ascii"))
4087 class GraphicString(CommonString):
4089 tag_default = tag_encode(25)
4090 encoding = "iso-8859-1"
4091 asn1_type_name = "GraphicString"
4094 class VisibleString(CommonString):
4096 tag_default = tag_encode(26)
4098 asn1_type_name = "VisibleString"
4101 class ISO646String(VisibleString):
4103 asn1_type_name = "ISO646String"
4106 class GeneralString(CommonString):
4108 tag_default = tag_encode(27)
4109 encoding = "iso-8859-1"
4110 asn1_type_name = "GeneralString"
4113 class UniversalString(CommonString):
4115 tag_default = tag_encode(28)
4116 encoding = "utf-32-be"
4117 asn1_type_name = "UniversalString"
4120 class BMPString(CommonString):
4122 tag_default = tag_encode(30)
4123 encoding = "utf-16-be"
4124 asn1_type_name = "BMPString"
4128 """``CHOICE`` special type
4132 class GeneralName(Choice):
4134 ("rfc822Name", IA5String(impl=tag_ctxp(1))),
4135 ("dNSName", IA5String(impl=tag_ctxp(2))),
4138 >>> gn = GeneralName()
4140 >>> gn["rfc822Name"] = IA5String("foo@bar.baz")
4141 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4142 >>> gn["dNSName"] = IA5String("bar.baz")
4143 GeneralName CHOICE dNSName[[2] IA5String IA5 bar.baz]
4144 >>> gn["rfc822Name"]
4147 [2] IA5String IA5 bar.baz
4150 >>> gn.value == gn["dNSName"]
4153 OrderedDict([('rfc822Name', [1] IA5String IA5), ('dNSName', [2] IA5String IA5)])
4155 >>> GeneralName(("rfc822Name", IA5String("foo@bar.baz")))
4156 GeneralName CHOICE rfc822Name[[1] IA5String IA5 foo@bar.baz]
4158 __slots__ = ("specs",)
4160 asn1_type_name = "CHOICE"
4173 :param value: set the value. Either ``(choice, value)`` tuple, or
4174 :py:class:`pyderasn.Choice` object
4175 :param bytes impl: can not be set, do **not** use it
4176 :param bytes expl: override default tag with ``EXPLICIT`` one
4177 :param default: set default value. Type same as in ``value``
4178 :param bool optional: is object ``OPTIONAL`` in sequence
4180 if impl is not None:
4181 raise ValueError("no implicit tag allowed for CHOICE")
4182 super(Choice, self).__init__(None, expl, default, optional, _decoded)
4184 schema = getattr(self, "schema", ())
4185 if len(schema) == 0:
4186 raise ValueError("schema must be specified")
4188 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4191 if value is not None:
4192 self._value = self._value_sanitize(value)
4193 if default is not None:
4194 default_value = self._value_sanitize(default)
4195 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4196 default_obj.specs = self.specs
4197 default_obj._value = default_value
4198 self.default = default_obj
4200 self._value = default_obj.copy()._value
4202 def _value_sanitize(self, value):
4203 if isinstance(value, tuple) and len(value) == 2:
4205 spec = self.specs.get(choice)
4207 raise ObjUnknown(choice)
4208 if not isinstance(obj, spec.__class__):
4209 raise InvalidValueType((spec,))
4210 return (choice, spec(obj))
4211 if isinstance(value, self.__class__):
4213 raise InvalidValueType((self.__class__, tuple))
4217 return self._value is not None and self._value[1].ready
4221 return self.expl_lenindef or (
4222 (self._value is not None) and
4223 self._value[1].bered
4227 obj = self.__class__(schema=self.specs)
4228 obj._expl = self._expl
4229 obj.default = self.default
4230 obj.optional = self.optional
4231 obj.offset = self.offset
4232 obj.llen = self.llen
4233 obj.vlen = self.vlen
4234 obj.expl_lenindef = self.expl_lenindef
4235 obj.lenindef = self.lenindef
4236 obj.ber_encoded = self.ber_encoded
4238 if value is not None:
4239 obj._value = (value[0], value[1].copy())
4242 def __eq__(self, their):
4243 if isinstance(their, tuple) and len(their) == 2:
4244 return self._value == their
4245 if not isinstance(their, self.__class__):
4248 self.specs == their.specs and
4249 self._value == their._value
4259 return self.__class__(
4262 expl=self._expl if expl is None else expl,
4263 default=self.default if default is None else default,
4264 optional=self.optional if optional is None else optional,
4269 self._assert_ready()
4270 return self._value[0]
4274 self._assert_ready()
4275 return self._value[1]
4277 def __getitem__(self, key):
4278 if key not in self.specs:
4279 raise ObjUnknown(key)
4280 if self._value is None:
4282 choice, value = self._value
4287 def __setitem__(self, key, value):
4288 spec = self.specs.get(key)
4290 raise ObjUnknown(key)
4291 if not isinstance(value, spec.__class__):
4292 raise InvalidValueType((spec.__class__,))
4293 self._value = (key, spec(value))
4301 return self._value[1].decoded if self.ready else False
4304 self._assert_ready()
4305 return self._value[1].encode()
4307 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4308 for choice, spec in iteritems(self.specs):
4309 sub_decode_path = decode_path + (choice,)
4315 decode_path=sub_decode_path,
4318 _ctx_immutable=False,
4325 klass=self.__class__,
4326 decode_path=decode_path,
4329 if tag_only: # pragma: no cover
4331 value, tail = spec.decode(
4335 decode_path=sub_decode_path,
4337 _ctx_immutable=False,
4339 obj = self.__class__(
4342 default=self.default,
4343 optional=self.optional,
4344 _decoded=(offset, 0, value.fulllen),
4346 obj._value = (choice, value)
4350 value = pp_console_row(next(self.pps()))
4352 value = "%s[%r]" % (value, self.value)
4355 def pps(self, decode_path=()):
4358 asn1_type_name=self.asn1_type_name,
4359 obj_name=self.__class__.__name__,
4360 decode_path=decode_path,
4361 value=self.choice if self.ready else None,
4362 optional=self.optional,
4363 default=self == self.default,
4364 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4365 expl=None if self._expl is None else tag_decode(self._expl),
4370 expl_lenindef=self.expl_lenindef,
4374 yield self.value.pps(decode_path=decode_path + (self.choice,))
4375 for pp in self.pps_lenindef(decode_path):
4379 class PrimitiveTypes(Choice):
4380 """Predefined ``CHOICE`` for all generic primitive types
4382 It could be useful for general decoding of some unspecified values:
4384 >>> PrimitiveTypes().decode(hexdec("0403666f6f"))[0].value
4385 OCTET STRING 3 bytes 666f6f
4386 >>> PrimitiveTypes().decode(hexdec("0203123456"))[0].value
4390 schema = tuple((klass.__name__, klass()) for klass in (
4415 """``ANY`` special type
4417 >>> Any(Integer(-123))
4419 >>> a = Any(OctetString(b"hello world").encode())
4420 ANY 040b68656c6c6f20776f726c64
4421 >>> hexenc(bytes(a))
4422 b'0x040x0bhello world'
4424 __slots__ = ("defined",)
4425 tag_default = tag_encode(0)
4426 asn1_type_name = "ANY"
4436 :param value: set the value. Either any kind of pyderasn's
4437 **ready** object, or bytes. Pay attention that
4438 **no** validation is performed is raw binary value
4440 :param bytes expl: override default tag with ``EXPLICIT`` one
4441 :param bool optional: is object ``OPTIONAL`` in sequence
4443 super(Any, self).__init__(None, expl, None, optional, _decoded)
4444 self._value = None if value is None else self._value_sanitize(value)
4447 def _value_sanitize(self, value):
4448 if isinstance(value, binary_type):
4450 if isinstance(value, self.__class__):
4452 if isinstance(value, Obj):
4453 return value.encode()
4454 raise InvalidValueType((self.__class__, Obj, binary_type))
4458 return self._value is not None
4462 if self.expl_lenindef or self.lenindef:
4464 if self.defined is None:
4466 return self.defined[1].bered
4469 obj = self.__class__()
4470 obj._value = self._value
4472 obj._expl = self._expl
4473 obj.optional = self.optional
4474 obj.offset = self.offset
4475 obj.llen = self.llen
4476 obj.vlen = self.vlen
4477 obj.expl_lenindef = self.expl_lenindef
4478 obj.lenindef = self.lenindef
4479 obj.ber_encoded = self.ber_encoded
4482 def __eq__(self, their):
4483 if isinstance(their, binary_type):
4484 return self._value == their
4485 if issubclass(their.__class__, Any):
4486 return self._value == their._value
4495 return self.__class__(
4497 expl=self._expl if expl is None else expl,
4498 optional=self.optional if optional is None else optional,
4501 def __bytes__(self):
4502 self._assert_ready()
4510 self._assert_ready()
4513 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4515 t, tlen, lv = tag_strip(tlv)
4516 except DecodeError as err:
4517 raise err.__class__(
4519 klass=self.__class__,
4520 decode_path=decode_path,
4524 l, llen, v = len_decode(lv)
4525 except LenIndefForm as err:
4526 if not ctx.get("bered", False):
4527 raise err.__class__(
4529 klass=self.__class__,
4530 decode_path=decode_path,
4533 llen, vlen, v = 1, 0, lv[1:]
4534 sub_offset = offset + tlen + llen
4536 while v[:EOC_LEN].tobytes() != EOC:
4537 chunk, v = Any().decode(
4540 decode_path=decode_path + (str(chunk_i),),
4543 _ctx_immutable=False,
4545 vlen += chunk.tlvlen
4546 sub_offset += chunk.tlvlen
4548 tlvlen = tlen + llen + vlen + EOC_LEN
4549 obj = self.__class__(
4550 value=tlv[:tlvlen].tobytes(),
4552 optional=self.optional,
4553 _decoded=(offset, 0, tlvlen),
4557 return obj, v[EOC_LEN:]
4558 except DecodeError as err:
4559 raise err.__class__(
4561 klass=self.__class__,
4562 decode_path=decode_path,
4566 raise NotEnoughData(
4567 "encoded length is longer than data",
4568 klass=self.__class__,
4569 decode_path=decode_path,
4572 tlvlen = tlen + llen + l
4573 v, tail = tlv[:tlvlen], v[l:]
4574 obj = self.__class__(
4577 optional=self.optional,
4578 _decoded=(offset, 0, tlvlen),
4584 return pp_console_row(next(self.pps()))
4586 def pps(self, decode_path=()):
4589 asn1_type_name=self.asn1_type_name,
4590 obj_name=self.__class__.__name__,
4591 decode_path=decode_path,
4592 blob=self._value if self.ready else None,
4593 optional=self.optional,
4594 default=self == self.default,
4595 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
4596 expl=None if self._expl is None else tag_decode(self._expl),
4601 expl_offset=self.expl_offset if self.expled else None,
4602 expl_tlen=self.expl_tlen if self.expled else None,
4603 expl_llen=self.expl_llen if self.expled else None,
4604 expl_vlen=self.expl_vlen if self.expled else None,
4605 expl_lenindef=self.expl_lenindef,
4606 lenindef=self.lenindef,
4609 defined_by, defined = self.defined or (None, None)
4610 if defined_by is not None:
4612 decode_path=decode_path + (DecodePathDefBy(defined_by),)
4614 for pp in self.pps_lenindef(decode_path):
4618 ########################################################################
4619 # ASN.1 constructed types
4620 ########################################################################
4622 def get_def_by_path(defines_by_path, sub_decode_path):
4623 """Get define by decode path
4625 for path, define in defines_by_path:
4626 if len(path) != len(sub_decode_path):
4628 for p1, p2 in zip(path, sub_decode_path):
4629 if (p1 != any) and (p1 != p2):
4635 def abs_decode_path(decode_path, rel_path):
4636 """Create an absolute decode path from current and relative ones
4638 :param decode_path: current decode path, starting point. Tuple of strings
4639 :param rel_path: relative path to ``decode_path``. Tuple of strings.
4640 If first tuple's element is "/", then treat it as
4641 an absolute path, ignoring ``decode_path`` as
4642 starting point. Also this tuple can contain ".."
4643 elements, stripping the leading element from
4646 >>> abs_decode_path(("foo", "bar"), ("baz", "whatever"))
4647 ("foo", "bar", "baz", "whatever")
4648 >>> abs_decode_path(("foo", "bar", "baz"), ("..", "..", "whatever"))
4650 >>> abs_decode_path(("foo", "bar"), ("/", "baz", "whatever"))
4653 if rel_path[0] == "/":
4655 if rel_path[0] == "..":
4656 return abs_decode_path(decode_path[:-1], rel_path[1:])
4657 return decode_path + rel_path
4660 class Sequence(Obj):
4661 """``SEQUENCE`` structure type
4663 You have to make specification of sequence::
4665 class Extension(Sequence):
4667 ("extnID", ObjectIdentifier()),
4668 ("critical", Boolean(default=False)),
4669 ("extnValue", OctetString()),
4672 Then, you can work with it as with dictionary.
4674 >>> ext = Extension()
4675 >>> Extension().specs
4677 ('extnID', OBJECT IDENTIFIER),
4678 ('critical', BOOLEAN False OPTIONAL DEFAULT),
4679 ('extnValue', OCTET STRING),
4681 >>> ext["extnID"] = "1.2.3"
4682 Traceback (most recent call last):
4683 pyderasn.InvalidValueType: invalid value type, expected: <class 'pyderasn.ObjectIdentifier'>
4684 >>> ext["extnID"] = ObjectIdentifier("1.2.3")
4686 You can determine if sequence is ready to be encoded:
4691 Traceback (most recent call last):
4692 pyderasn.ObjNotReady: object is not ready: extnValue
4693 >>> ext["extnValue"] = OctetString(b"foobar")
4697 Value you want to assign, must have the same **type** as in
4698 corresponding specification, but it can have different tags,
4699 optional/default attributes -- they will be taken from specification
4702 class TBSCertificate(Sequence):
4704 ("version", Version(expl=tag_ctxc(0), default="v1")),
4707 >>> tbs = TBSCertificate()
4708 >>> tbs["version"] = Version("v2") # no need to explicitly add ``expl``
4710 Assign ``None`` to remove value from sequence.
4712 You can set values in Sequence during its initialization:
4714 >>> AlgorithmIdentifier((
4715 ("algorithm", ObjectIdentifier("1.2.3")),
4716 ("parameters", Any(Null()))
4718 AlgorithmIdentifier SEQUENCE[algorithm: OBJECT IDENTIFIER 1.2.3; parameters: ANY 0500 OPTIONAL]
4720 You can determine if value exists/set in the sequence and take its value:
4722 >>> "extnID" in ext, "extnValue" in ext, "critical" in ext
4725 OBJECT IDENTIFIER 1.2.3
4727 But pay attention that if value has default, then it won't be (not
4728 in) in the sequence (because ``DEFAULT`` must not be encoded in
4729 DER), but you can read its value:
4731 >>> "critical" in ext, ext["critical"]
4732 (False, BOOLEAN False)
4733 >>> ext["critical"] = Boolean(True)
4734 >>> "critical" in ext, ext["critical"]
4735 (True, BOOLEAN True)
4737 All defaulted values are always optional.
4739 .. _allow_default_values_ctx:
4741 DER prohibits default value encoding and will raise an error if
4742 default value is unexpectedly met during decode.
4743 If :ref:`bered <bered_ctx>` context option is set, then no error
4744 will be raised, but ``bered`` attribute set. You can disable strict
4745 defaulted values existence validation by setting
4746 ``"allow_default_values": True`` :ref:`context <ctx>` option.
4748 Two sequences are equal if they have equal specification (schema),
4749 implicit/explicit tagging and the same values.
4751 __slots__ = ("specs",)
4752 tag_default = tag_encode(form=TagFormConstructed, num=16)
4753 asn1_type_name = "SEQUENCE"
4765 super(Sequence, self).__init__(impl, expl, default, optional, _decoded)
4767 schema = getattr(self, "schema", ())
4769 schema if isinstance(schema, OrderedDict) else OrderedDict(schema)
4772 if value is not None:
4773 if issubclass(value.__class__, Sequence):
4774 self._value = value._value
4775 elif hasattr(value, "__iter__"):
4776 for seq_key, seq_value in value:
4777 self[seq_key] = seq_value
4779 raise InvalidValueType((Sequence,))
4780 if default is not None:
4781 if not issubclass(default.__class__, Sequence):
4782 raise InvalidValueType((Sequence,))
4783 default_value = default._value
4784 default_obj = self.__class__(impl=self.tag, expl=self._expl)
4785 default_obj.specs = self.specs
4786 default_obj._value = default_value
4787 self.default = default_obj
4789 self._value = default_obj.copy()._value
4793 for name, spec in iteritems(self.specs):
4794 value = self._value.get(name)
4805 if self.expl_lenindef or self.lenindef or self.ber_encoded:
4807 return any(value.bered for value in itervalues(self._value))
4810 obj = self.__class__(schema=self.specs)
4812 obj._expl = self._expl
4813 obj.default = self.default
4814 obj.optional = self.optional
4815 obj.offset = self.offset
4816 obj.llen = self.llen
4817 obj.vlen = self.vlen
4818 obj.expl_lenindef = self.expl_lenindef
4819 obj.lenindef = self.lenindef
4820 obj.ber_encoded = self.ber_encoded
4821 obj._value = {k: v.copy() for k, v in iteritems(self._value)}
4824 def __eq__(self, their):
4825 if not isinstance(their, self.__class__):
4828 self.specs == their.specs and
4829 self.tag == their.tag and
4830 self._expl == their._expl and
4831 self._value == their._value
4842 return self.__class__(
4845 impl=self.tag if impl is None else impl,
4846 expl=self._expl if expl is None else expl,
4847 default=self.default if default is None else default,
4848 optional=self.optional if optional is None else optional,
4851 def __contains__(self, key):
4852 return key in self._value
4854 def __setitem__(self, key, value):
4855 spec = self.specs.get(key)
4857 raise ObjUnknown(key)
4859 self._value.pop(key, None)
4861 if not isinstance(value, spec.__class__):
4862 raise InvalidValueType((spec.__class__,))
4863 value = spec(value=value)
4864 if spec.default is not None and value == spec.default:
4865 self._value.pop(key, None)
4867 self._value[key] = value
4869 def __getitem__(self, key):
4870 value = self._value.get(key)
4871 if value is not None:
4873 spec = self.specs.get(key)
4875 raise ObjUnknown(key)
4876 if spec.default is not None:
4880 def _encoded_values(self):
4882 for name, spec in iteritems(self.specs):
4883 value = self._value.get(name)
4887 raise ObjNotReady(name)
4888 raws.append(value.encode())
4892 v = b"".join(self._encoded_values())
4893 return b"".join((self.tag, len_encode(len(v)), v))
4895 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
4897 t, tlen, lv = tag_strip(tlv)
4898 except DecodeError as err:
4899 raise err.__class__(
4901 klass=self.__class__,
4902 decode_path=decode_path,
4907 klass=self.__class__,
4908 decode_path=decode_path,
4911 if tag_only: # pragma: no cover
4914 ctx_bered = ctx.get("bered", False)
4916 l, llen, v = len_decode(lv)
4917 except LenIndefForm as err:
4919 raise err.__class__(
4921 klass=self.__class__,
4922 decode_path=decode_path,
4925 l, llen, v = 0, 1, lv[1:]
4927 except DecodeError as err:
4928 raise err.__class__(
4930 klass=self.__class__,
4931 decode_path=decode_path,
4935 raise NotEnoughData(
4936 "encoded length is longer than data",
4937 klass=self.__class__,
4938 decode_path=decode_path,
4942 v, tail = v[:l], v[l:]
4944 sub_offset = offset + tlen + llen
4947 ctx_allow_default_values = ctx.get("allow_default_values", False)
4948 for name, spec in iteritems(self.specs):
4949 if spec.optional and (
4950 (lenindef and v[:EOC_LEN].tobytes() == EOC) or
4954 sub_decode_path = decode_path + (name,)
4956 value, v_tail = spec.decode(
4960 decode_path=sub_decode_path,
4962 _ctx_immutable=False,
4964 except TagMismatch as err:
4965 if (len(err.decode_path) == len(decode_path) + 1) and spec.optional:
4969 defined = get_def_by_path(ctx.get("_defines", ()), sub_decode_path)
4970 if defined is not None:
4971 defined_by, defined_spec = defined
4972 if issubclass(value.__class__, SequenceOf):
4973 for i, _value in enumerate(value):
4974 sub_sub_decode_path = sub_decode_path + (
4976 DecodePathDefBy(defined_by),
4978 defined_value, defined_tail = defined_spec.decode(
4979 memoryview(bytes(_value)),
4981 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
4982 if value.expled else (value.tlen + value.llen)
4985 decode_path=sub_sub_decode_path,
4987 _ctx_immutable=False,
4989 if len(defined_tail) > 0:
4992 klass=self.__class__,
4993 decode_path=sub_sub_decode_path,
4996 _value.defined = (defined_by, defined_value)
4998 defined_value, defined_tail = defined_spec.decode(
4999 memoryview(bytes(value)),
5001 (value.tlen + value.llen + value.expl_tlen + value.expl_llen)
5002 if value.expled else (value.tlen + value.llen)
5005 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5007 _ctx_immutable=False,
5009 if len(defined_tail) > 0:
5012 klass=self.__class__,
5013 decode_path=sub_decode_path + (DecodePathDefBy(defined_by),),
5016 value.defined = (defined_by, defined_value)
5018 value_len = value.fulllen
5020 sub_offset += value_len
5022 if spec.default is not None and value == spec.default:
5023 if ctx_bered or ctx_allow_default_values:
5027 "DEFAULT value met",
5028 klass=self.__class__,
5029 decode_path=sub_decode_path,
5032 values[name] = value
5034 spec_defines = getattr(spec, "defines", ())
5035 if len(spec_defines) == 0:
5036 defines_by_path = ctx.get("defines_by_path", ())
5037 if len(defines_by_path) > 0:
5038 spec_defines = get_def_by_path(defines_by_path, sub_decode_path)
5039 if spec_defines is not None and len(spec_defines) > 0:
5040 for rel_path, schema in spec_defines:
5041 defined = schema.get(value, None)
5042 if defined is not None:
5043 ctx.setdefault("_defines", []).append((
5044 abs_decode_path(sub_decode_path[:-1], rel_path),
5048 if v[:EOC_LEN].tobytes() != EOC:
5051 klass=self.__class__,
5052 decode_path=decode_path,
5060 klass=self.__class__,
5061 decode_path=decode_path,
5064 obj = self.__class__(
5068 default=self.default,
5069 optional=self.optional,
5070 _decoded=(offset, llen, vlen),
5073 obj.lenindef = lenindef
5074 obj.ber_encoded = ber_encoded
5078 value = pp_console_row(next(self.pps()))
5080 for name in self.specs:
5081 _value = self._value.get(name)
5084 cols.append("%s: %s" % (name, repr(_value)))
5085 return "%s[%s]" % (value, "; ".join(cols))
5087 def pps(self, decode_path=()):
5090 asn1_type_name=self.asn1_type_name,
5091 obj_name=self.__class__.__name__,
5092 decode_path=decode_path,
5093 optional=self.optional,
5094 default=self == self.default,
5095 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5096 expl=None if self._expl is None else tag_decode(self._expl),
5101 expl_offset=self.expl_offset if self.expled else None,
5102 expl_tlen=self.expl_tlen if self.expled else None,
5103 expl_llen=self.expl_llen if self.expled else None,
5104 expl_vlen=self.expl_vlen if self.expled else None,
5105 expl_lenindef=self.expl_lenindef,
5106 lenindef=self.lenindef,
5107 ber_encoded=self.ber_encoded,
5110 for name in self.specs:
5111 value = self._value.get(name)
5114 yield value.pps(decode_path=decode_path + (name,))
5115 for pp in self.pps_lenindef(decode_path):
5119 class Set(Sequence):
5120 """``SET`` structure type
5122 Its usage is identical to :py:class:`pyderasn.Sequence`.
5124 .. _allow_unordered_set_ctx:
5126 DER prohibits unordered values encoding and will raise an error
5127 during decode. If If :ref:`bered <bered_ctx>` context option is set,
5128 then no error will occure. Also you can disable strict values
5129 ordering check by setting ``"allow_unordered_set": True``
5130 :ref:`context <ctx>` option.
5133 tag_default = tag_encode(form=TagFormConstructed, num=17)
5134 asn1_type_name = "SET"
5137 raws = self._encoded_values()
5140 return b"".join((self.tag, len_encode(len(v)), v))
5142 def _specs_items(self):
5143 return iteritems(self.specs)
5145 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5147 t, tlen, lv = tag_strip(tlv)
5148 except DecodeError as err:
5149 raise err.__class__(
5151 klass=self.__class__,
5152 decode_path=decode_path,
5157 klass=self.__class__,
5158 decode_path=decode_path,
5164 ctx_bered = ctx.get("bered", False)
5166 l, llen, v = len_decode(lv)
5167 except LenIndefForm as err:
5169 raise err.__class__(
5171 klass=self.__class__,
5172 decode_path=decode_path,
5175 l, llen, v = 0, 1, lv[1:]
5177 except DecodeError as err:
5178 raise err.__class__(
5180 klass=self.__class__,
5181 decode_path=decode_path,
5185 raise NotEnoughData(
5186 "encoded length is longer than data",
5187 klass=self.__class__,
5191 v, tail = v[:l], v[l:]
5193 sub_offset = offset + tlen + llen
5196 ctx_allow_default_values = ctx.get("allow_default_values", False)
5197 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5198 value_prev = memoryview(v[:0])
5201 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5203 for name, spec in self._specs_items():
5204 sub_decode_path = decode_path + (name,)
5210 decode_path=sub_decode_path,
5213 _ctx_immutable=False,
5220 klass=self.__class__,
5221 decode_path=decode_path,
5224 value, v_tail = spec.decode(
5228 decode_path=sub_decode_path,
5230 _ctx_immutable=False,
5232 value_len = value.fulllen
5233 if value_prev.tobytes() > v[:value_len].tobytes():
5234 if ctx_bered or ctx_allow_unordered_set:
5238 "unordered " + self.asn1_type_name,
5239 klass=self.__class__,
5240 decode_path=sub_decode_path,
5243 if spec.default is None or value != spec.default:
5245 elif ctx_bered or ctx_allow_default_values:
5249 "DEFAULT value met",
5250 klass=self.__class__,
5251 decode_path=sub_decode_path,
5254 values[name] = value
5255 value_prev = v[:value_len]
5256 sub_offset += value_len
5259 obj = self.__class__(
5263 default=self.default,
5264 optional=self.optional,
5265 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5268 if v[:EOC_LEN].tobytes() != EOC:
5271 klass=self.__class__,
5272 decode_path=decode_path,
5280 "not all values are ready",
5281 klass=self.__class__,
5282 decode_path=decode_path,
5285 obj.ber_encoded = ber_encoded
5289 class SequenceOf(Obj):
5290 """``SEQUENCE OF`` sequence type
5292 For that kind of type you must specify the object it will carry on
5293 (bounds are for example here, not required)::
5295 class Ints(SequenceOf):
5300 >>> ints.append(Integer(123))
5301 >>> ints.append(Integer(234))
5303 Ints SEQUENCE OF[INTEGER 123, INTEGER 234]
5304 >>> [int(i) for i in ints]
5306 >>> ints.append(Integer(345))
5307 Traceback (most recent call last):
5308 pyderasn.BoundsError: unsatisfied bounds: 0 <= 3 <= 2
5311 >>> ints[1] = Integer(345)
5313 Ints SEQUENCE OF[INTEGER 123, INTEGER 345]
5315 Also you can initialize sequence with preinitialized values:
5317 >>> ints = Ints([Integer(123), Integer(234)])
5319 __slots__ = ("spec", "_bound_min", "_bound_max")
5320 tag_default = tag_encode(form=TagFormConstructed, num=16)
5321 asn1_type_name = "SEQUENCE OF"
5334 super(SequenceOf, self).__init__(
5342 schema = getattr(self, "schema", None)
5344 raise ValueError("schema must be specified")
5346 self._bound_min, self._bound_max = getattr(
5350 ) if bounds is None else bounds
5352 if value is not None:
5353 self._value = self._value_sanitize(value)
5354 if default is not None:
5355 default_value = self._value_sanitize(default)
5356 default_obj = self.__class__(
5361 default_obj._value = default_value
5362 self.default = default_obj
5364 self._value = default_obj.copy()._value
5366 def _value_sanitize(self, value):
5367 if issubclass(value.__class__, SequenceOf):
5368 value = value._value
5369 elif hasattr(value, "__iter__"):
5372 raise InvalidValueType((self.__class__, iter))
5373 if not self._bound_min <= len(value) <= self._bound_max:
5374 raise BoundsError(self._bound_min, len(value), self._bound_max)
5376 if not isinstance(v, self.spec.__class__):
5377 raise InvalidValueType((self.spec.__class__,))
5382 return all(v.ready for v in self._value)
5386 if self.expl_lenindef or self.lenindef or self.ber_encoded:
5388 return any(v.bered for v in self._value)
5391 obj = self.__class__(schema=self.spec)
5392 obj._bound_min = self._bound_min
5393 obj._bound_max = self._bound_max
5395 obj._expl = self._expl
5396 obj.default = self.default
5397 obj.optional = self.optional
5398 obj.offset = self.offset
5399 obj.llen = self.llen
5400 obj.vlen = self.vlen
5401 obj.expl_lenindef = self.expl_lenindef
5402 obj.lenindef = self.lenindef
5403 obj.ber_encoded = self.ber_encoded
5404 obj._value = [v.copy() for v in self._value]
5407 def __eq__(self, their):
5408 if isinstance(their, self.__class__):
5410 self.spec == their.spec and
5411 self.tag == their.tag and
5412 self._expl == their._expl and
5413 self._value == their._value
5415 if hasattr(their, "__iter__"):
5416 return self._value == list(their)
5428 return self.__class__(
5432 (self._bound_min, self._bound_max)
5433 if bounds is None else bounds
5435 impl=self.tag if impl is None else impl,
5436 expl=self._expl if expl is None else expl,
5437 default=self.default if default is None else default,
5438 optional=self.optional if optional is None else optional,
5441 def __contains__(self, key):
5442 return key in self._value
5444 def append(self, value):
5445 if not isinstance(value, self.spec.__class__):
5446 raise InvalidValueType((self.spec.__class__,))
5447 if len(self._value) + 1 > self._bound_max:
5450 len(self._value) + 1,
5453 self._value.append(value)
5456 self._assert_ready()
5457 return iter(self._value)
5460 self._assert_ready()
5461 return len(self._value)
5463 def __setitem__(self, key, value):
5464 if not isinstance(value, self.spec.__class__):
5465 raise InvalidValueType((self.spec.__class__,))
5466 self._value[key] = self.spec(value=value)
5468 def __getitem__(self, key):
5469 return self._value[key]
5471 def _encoded_values(self):
5472 return [v.encode() for v in self._value]
5475 v = b"".join(self._encoded_values())
5476 return b"".join((self.tag, len_encode(len(v)), v))
5478 def _decode(self, tlv, offset, decode_path, ctx, tag_only, ordering_check=False):
5480 t, tlen, lv = tag_strip(tlv)
5481 except DecodeError as err:
5482 raise err.__class__(
5484 klass=self.__class__,
5485 decode_path=decode_path,
5490 klass=self.__class__,
5491 decode_path=decode_path,
5497 ctx_bered = ctx.get("bered", False)
5499 l, llen, v = len_decode(lv)
5500 except LenIndefForm as err:
5502 raise err.__class__(
5504 klass=self.__class__,
5505 decode_path=decode_path,
5508 l, llen, v = 0, 1, lv[1:]
5510 except DecodeError as err:
5511 raise err.__class__(
5513 klass=self.__class__,
5514 decode_path=decode_path,
5518 raise NotEnoughData(
5519 "encoded length is longer than data",
5520 klass=self.__class__,
5521 decode_path=decode_path,
5525 v, tail = v[:l], v[l:]
5527 sub_offset = offset + tlen + llen
5529 ctx_allow_unordered_set = ctx.get("allow_unordered_set", False)
5530 value_prev = memoryview(v[:0])
5534 if lenindef and v[:EOC_LEN].tobytes() == EOC:
5536 sub_decode_path = decode_path + (str(len(_value)),)
5537 value, v_tail = spec.decode(
5541 decode_path=sub_decode_path,
5543 _ctx_immutable=False,
5545 value_len = value.fulllen
5547 if value_prev.tobytes() > v[:value_len].tobytes():
5548 if ctx_bered or ctx_allow_unordered_set:
5552 "unordered " + self.asn1_type_name,
5553 klass=self.__class__,
5554 decode_path=sub_decode_path,
5557 value_prev = v[:value_len]
5558 _value.append(value)
5559 sub_offset += value_len
5563 obj = self.__class__(
5566 bounds=(self._bound_min, self._bound_max),
5569 default=self.default,
5570 optional=self.optional,
5571 _decoded=(offset, llen, vlen + (EOC_LEN if lenindef else 0)),
5573 except BoundsError as err:
5576 klass=self.__class__,
5577 decode_path=decode_path,
5581 if v[:EOC_LEN].tobytes() != EOC:
5584 klass=self.__class__,
5585 decode_path=decode_path,
5590 obj.ber_encoded = ber_encoded
5595 pp_console_row(next(self.pps())),
5596 ", ".join(repr(v) for v in self._value),
5599 def pps(self, decode_path=()):
5602 asn1_type_name=self.asn1_type_name,
5603 obj_name=self.__class__.__name__,
5604 decode_path=decode_path,
5605 optional=self.optional,
5606 default=self == self.default,
5607 impl=None if self.tag == self.tag_default else tag_decode(self.tag),
5608 expl=None if self._expl is None else tag_decode(self._expl),
5613 expl_offset=self.expl_offset if self.expled else None,
5614 expl_tlen=self.expl_tlen if self.expled else None,
5615 expl_llen=self.expl_llen if self.expled else None,
5616 expl_vlen=self.expl_vlen if self.expled else None,
5617 expl_lenindef=self.expl_lenindef,
5618 lenindef=self.lenindef,
5619 ber_encoded=self.ber_encoded,
5622 for i, value in enumerate(self._value):
5623 yield value.pps(decode_path=decode_path + (str(i),))
5624 for pp in self.pps_lenindef(decode_path):
5628 class SetOf(SequenceOf):
5629 """``SET OF`` sequence type
5631 Its usage is identical to :py:class:`pyderasn.SequenceOf`.
5634 tag_default = tag_encode(form=TagFormConstructed, num=17)
5635 asn1_type_name = "SET OF"
5638 raws = self._encoded_values()
5641 return b"".join((self.tag, len_encode(len(v)), v))
5643 def _decode(self, tlv, offset, decode_path, ctx, tag_only):
5644 return super(SetOf, self)._decode(
5650 ordering_check=True,
5654 def obj_by_path(pypath): # pragma: no cover
5655 """Import object specified as string Python path
5657 Modules must be separated from classes/functions with ``:``.
5659 >>> obj_by_path("foo.bar:Baz")
5660 <class 'foo.bar.Baz'>
5661 >>> obj_by_path("foo.bar:Baz.boo")
5662 <classmethod 'foo.bar.Baz.boo'>
5664 mod, objs = pypath.rsplit(":", 1)
5665 from importlib import import_module
5666 obj = import_module(mod)
5667 for obj_name in objs.split("."):
5668 obj = getattr(obj, obj_name)
5672 def generic_decoder(): # pragma: no cover
5673 # All of this below is a big hack with self references
5674 choice = PrimitiveTypes()
5675 choice.specs["SequenceOf"] = SequenceOf(schema=choice)
5676 choice.specs["SetOf"] = SetOf(schema=choice)
5677 for i in six_xrange(31):
5678 choice.specs["SequenceOf%d" % i] = SequenceOf(
5682 choice.specs["Any"] = Any()
5684 # Class name equals to type name, to omit it from output
5685 class SEQUENCEOF(SequenceOf):
5693 with_decode_path=False,
5694 decode_path_only=(),
5696 def _pprint_pps(pps):
5698 if hasattr(pp, "_fields"):
5700 decode_path_only != () and
5701 pp.decode_path[:len(decode_path_only)] != decode_path_only
5704 if pp.asn1_type_name == Choice.asn1_type_name:
5706 pp_kwargs = pp._asdict()
5707 pp_kwargs["decode_path"] = pp.decode_path[:-1] + (">",)
5708 pp = _pp(**pp_kwargs)
5709 yield pp_console_row(
5714 with_colours=with_colours,
5715 with_decode_path=with_decode_path,
5716 decode_path_len_decrease=len(decode_path_only),
5718 for row in pp_console_blob(
5720 decode_path_len_decrease=len(decode_path_only),
5724 for row in _pprint_pps(pp):
5726 return "\n".join(_pprint_pps(obj.pps()))
5727 return SEQUENCEOF(), pprint_any
5730 def main(): # pragma: no cover
5732 parser = argparse.ArgumentParser(description="PyDERASN ASN.1 BER/DER decoder")
5733 parser.add_argument(
5737 help="Skip that number of bytes from the beginning",
5739 parser.add_argument(
5741 help="Python paths to dictionary with OIDs, comma separated",
5743 parser.add_argument(
5745 help="Python path to schema definition to use",
5747 parser.add_argument(
5748 "--defines-by-path",
5749 help="Python path to decoder's defines_by_path",
5751 parser.add_argument(
5753 action="store_true",
5754 help="Disallow BER encoding",
5756 parser.add_argument(
5757 "--print-decode-path",
5758 action="store_true",
5759 help="Print decode paths",
5761 parser.add_argument(
5762 "--decode-path-only",
5763 help="Print only specified decode path",
5765 parser.add_argument(
5767 action="store_true",
5768 help="Allow explicit tag out-of-bound",
5770 parser.add_argument(
5772 type=argparse.FileType("rb"),
5773 help="Path to DER file you want to decode",
5775 args = parser.parse_args()
5776 args.DERFile.seek(args.skip)
5777 der = memoryview(args.DERFile.read())
5778 args.DERFile.close()
5780 [obj_by_path(_path) for _path in (args.oids or "").split(",")]
5781 if args.oids else ()
5784 schema = obj_by_path(args.schema)
5785 from functools import partial
5786 pprinter = partial(pprint, big_blobs=True)
5788 schema, pprinter = generic_decoder()
5790 "bered": not args.nobered,
5791 "allow_expl_oob": args.allow_expl_oob,
5793 if args.defines_by_path is not None:
5794 ctx["defines_by_path"] = obj_by_path(args.defines_by_path)
5795 obj, tail = schema().decode(der, ctx=ctx)
5799 with_colours=environ.get("NO_COLOR") is None,
5800 with_decode_path=args.print_decode_path,
5802 () if args.decode_path_only is None else
5803 tuple(args.decode_path_only.split(":"))
5807 print("\nTrailing data: %s" % hexenc(tail))
5810 if __name__ == "__main__":